/* Copyright (c) 2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.cli; import java.io.File; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import javax.annotation.Nullable; import org.locationtech.geogig.api.DefaultPlatform; import org.locationtech.geogig.api.Platform; import org.locationtech.geogig.api.plumbing.ResolveGeogigDir; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import com.google.common.base.Optional; import com.google.common.base.Throwables; import com.google.common.io.ByteSource; import com.google.common.io.Files; import com.google.common.io.Resources; /** * Utility class for the CLI applications to configure logging using the default logback logger * context. * <p> * {@link #tryConfigureLogging()} is meant to be called by the {@code static main(String [])} * methods or such places where it wouldn't interfere with any alternate logging mechanism a client * application may be using (e.g. geoserver using log4j instead). */ class Logging { private static final Logger LOGGER = LoggerFactory.getLogger(Logging.class); private static File geogigDirLoggingConfiguration; static void tryConfigureLogging() { tryConfigureLogging(new DefaultPlatform()); } static void tryConfigureLogging(Platform platform) { // instantiate and call ResolveGeogigDir directly to avoid calling getGeogig() and hence get // some logging events before having configured logging final Optional<URL> geogigDirUrl = new ResolveGeogigDir(platform).call(); if (!geogigDirUrl.isPresent() || !"file".equalsIgnoreCase(geogigDirUrl.get().getProtocol())) { // redirect java.util.logging to SLF4J anyways SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); return; } final File geogigDir; try { geogigDir = new File(geogigDirUrl.get().toURI()); } catch (URISyntaxException e) { throw Throwables.propagate(e); } if (geogigDir.equals(geogigDirLoggingConfiguration)) { return; } if (!geogigDir.exists() || !geogigDir.isDirectory()) { return; } final URL loggingFile = getOrCreateLoggingConfigFile(geogigDir); if (loggingFile == null) { return; } try { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); loggerContext.reset(); /* * Set the geogigdir variable for the config file can resolve the default location * ${geogigdir}/log/geogig.log */ loggerContext.putProperty("geogigdir", geogigDir.getAbsolutePath()); JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(loggerContext); configurator.doConfigure(loggingFile); // redirect java.util.logging to SLF4J SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); geogigDirLoggingConfiguration = geogigDir; } catch (JoranException e) { LOGGER.error("Error configuring logging from file {}. '{}'", loggingFile, e.getMessage(), e); } } @Nullable private static URL getOrCreateLoggingConfigFile(final File geogigdir) { final File logsDir = new File(geogigdir, "log"); if (!logsDir.exists() && !logsDir.mkdir()) { return null; } final File configFile = new File(logsDir, "logback.xml"); if (configFile.exists()) { try { return configFile.toURI().toURL(); } catch (MalformedURLException e) { throw Throwables.propagate(e); } } ByteSource from; final URL resource = GeogigCLI.class.getResource("logback_default.xml"); try { from = Resources.asByteSource(resource); } catch (NullPointerException npe) { LOGGER.warn("Couldn't obtain default logging configuration file"); return null; } try { from.copyTo(Files.asByteSink(configFile)); return configFile.toURI().toURL(); } catch (Exception e) { LOGGER.warn("Error copying logback_default.xml to {}. Using default configuration.", configFile, e); return resource; } } }