| /******************************************************************************* |
| * Copyright (c) 2010 Sonatype, Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Sonatype, Inc. - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.m2e.logback.configuration; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.Timer; |
| import java.util.TimerTask; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.slf4j.ILoggerFactory; |
| import org.slf4j.LoggerFactory; |
| import org.slf4j.helpers.SubstituteLoggerFactory; |
| |
| import ch.qos.logback.classic.LoggerContext; |
| import ch.qos.logback.classic.joran.JoranConfigurator; |
| import ch.qos.logback.classic.util.ContextInitializer; |
| import ch.qos.logback.core.joran.spi.JoranException; |
| import ch.qos.logback.core.util.StatusPrinter; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.core.runtime.Status; |
| |
| |
| public class LogPlugin extends Plugin { |
| private static final String PLUGIN_ID = "org.eclipse.m2e.logback.configuration"; //$NON-NLS-1$ |
| |
| private static final String RESOURCES_PLUGIN_ID = "org.eclipse.core.resources"; //$NON-NLS-1$ |
| |
| // This has to match the log directory in defaultLogbackConfiguration/logback.xml |
| public static final String PROPERTY_LOG_DIRECTORY = "org.eclipse.m2e.log.dir"; //$NON-NLS-1$ |
| |
| private BundleContext bundleContext; |
| |
| private boolean isConfigured; |
| |
| private Timer timer = new Timer("logback configurator timer"); |
| |
| private TimerTask timerTask = new TimerTask() { |
| @SuppressWarnings("synthetic-access") |
| public void run() { |
| if(!isStateLocationInitialized()) { |
| return; |
| } |
| |
| // The state location was initialized |
| timer.cancel(); |
| configureLogback(); |
| } |
| }; |
| |
| private boolean isStateLocationInitialized() { |
| if(!Platform.isRunning()) { |
| return false; |
| } |
| |
| Bundle resourcesBundle = Platform.getBundle(RESOURCES_PLUGIN_ID); |
| if(resourcesBundle == null) { |
| return false; |
| } |
| |
| return resourcesBundle.getState() == Bundle.ACTIVE; |
| } |
| |
| @Override |
| public void start(BundleContext context) throws Exception { |
| super.start(context); |
| bundleContext = context; |
| |
| if(System.getProperty(ContextInitializer.CONFIG_FILE_PROPERTY) != null) { |
| // The standard logback config file property is set - don't force our configuration |
| systemOut(ContextInitializer.CONFIG_FILE_PROPERTY + "=" //$NON-NLS-1$ |
| + System.getProperty(ContextInitializer.CONFIG_FILE_PROPERTY)); |
| return; |
| } |
| |
| if(!isStateLocationInitialized()) { |
| systemOut("The " + PLUGIN_ID + " bundle was activated before the state location was initialized. Will retry after the state location is initialized."); //$NON-NLS-1$ //$NON-NLS-2$ |
| timer.schedule(timerTask, 0 /*delay*/, 50 /*period*/); |
| } else { |
| configureLogback(); |
| } |
| } |
| |
| private static void systemOut(String message) { |
| System.out.println(PLUGIN_ID + ": " + message); //$NON-NLS-1$ |
| } |
| |
| private static void systemErr(String message) { |
| System.err.println(PLUGIN_ID + ": " + message); //$NON-NLS-1$ |
| } |
| |
| private synchronized void configureLogback() { |
| if(isConfigured) { |
| systemOut("Logback was configured already"); //$NON-NLS-1$ |
| return; |
| } |
| |
| try { |
| File stateDir = getStateLocation().toFile(); |
| |
| File configFile = new File(stateDir, "logback." + bundleContext.getBundle().getVersion().toString() + ".xml"); //$NON-NLS-1$ //$NON-NLS-2$ |
| systemOut("Logback config file: " + configFile.getAbsolutePath()); //$NON-NLS-1$ |
| |
| if(!configFile.isFile()) { |
| // Copy the default config file to the actual config file |
| InputStream is = bundleContext.getBundle().getEntry("defaultLogbackConfiguration/logback.xml").openStream(); //$NON-NLS-1$ |
| try { |
| configFile.getParentFile().mkdirs(); |
| FileOutputStream fos = new FileOutputStream(configFile); |
| try { |
| for(byte[] buffer = new byte[1024 * 4];;) { |
| int n = is.read(buffer); |
| if(n < 0) { |
| break; |
| } |
| fos.write(buffer, 0, n); |
| } |
| } finally { |
| fos.close(); |
| } |
| } finally { |
| is.close(); |
| } |
| } |
| |
| if(System.getProperty(PROPERTY_LOG_DIRECTORY, "").length() <= 0) { //$NON-NLS-1$ |
| System.setProperty(PROPERTY_LOG_DIRECTORY, stateDir.getAbsolutePath()); |
| } |
| loadConfiguration(configFile.toURL()); |
| |
| isConfigured = true; |
| } catch(Exception e) { |
| e.printStackTrace(); |
| getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, "Exception while setting up logging:" + e.getMessage(), e)); //$NON-NLS-1$ |
| return; |
| } |
| } |
| |
| public static void loadConfiguration(URL configFile) throws JoranException { |
| ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); |
| int i = 0; |
| while(loggerFactory instanceof SubstituteLoggerFactory && i < 100) { |
| // slf4j is initialization phase |
| systemOut("SLF4J logger factory class: " + loggerFactory.getClass().getName()); //$NON-NLS-1$ |
| try { |
| Thread.sleep(50); |
| } catch(InterruptedException e) { |
| e.printStackTrace(); |
| } |
| i++ ; |
| loggerFactory = LoggerFactory.getILoggerFactory(); |
| } |
| if(!(loggerFactory instanceof LoggerContext)) { |
| if(loggerFactory == null) { |
| // Is it possible? |
| systemErr("SLF4J logger factory is null"); //$NON-NLS-1$ |
| return; |
| } |
| systemErr("SLF4J logger factory is not an instance of LoggerContext: " //$NON-NLS-1$ |
| + loggerFactory.getClass().getName()); |
| return; |
| } |
| |
| systemOut("Initializing logback"); //$NON-NLS-1$ |
| LoggerContext lc = (LoggerContext) loggerFactory; |
| lc.reset(); |
| |
| JoranConfigurator configurator = new JoranConfigurator(); |
| configurator.setContext(lc); |
| configurator.doConfigure(configFile); |
| |
| StatusPrinter.printInCaseOfErrorsOrWarnings(lc); |
| |
| LogHelper.logJavaProperties(LoggerFactory.getLogger(LogPlugin.class)); |
| } |
| } |