All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fabric3.monitor.runtime.LogbackDispatcher Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * Fabric3
 * Copyright (c) 2009-2011 Metaform Systems
 *
 * Fabric3 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version, with the
 * following exception:
 *
 * Linking this software statically or dynamically with other
 * modules is making a combined work based on this software.
 * Thus, the terms and conditions of the GNU General Public
 * License cover the whole combination.
 *
 * As a special exception, the copyright holders of this software
 * give you permission to link this software with independent
 * modules to produce an executable, regardless of the license
 * terms of these independent modules, and to copy and distribute
 * the resulting executable under terms of your choice, provided
 * that you also meet, for each linked independent module, the
 * terms and conditions of the license of that module. An
 * independent module is a module which is not derived from or
 * based on this software. If you modify this software, you may
 * extend this exception to your version of the software, but
 * you are not obligated to do so. If you do not wish to do so,
 * delete this exception statement from your version.
 *
 * Fabric3 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the
 * GNU General Public License along with Fabric3.
 * If not, see .
*/
package org.fabric3.monitor.runtime;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.joran.spi.JoranException;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import org.fabric3.host.monitor.MonitorConfigurationException;
import org.fabric3.host.monitor.MonitorEvent;
import org.fabric3.host.monitor.MonitorEventDispatcher;
import org.fabric3.host.runtime.HostInfo;

/**
 * Dispatches to one or more Logback appenders. If a configuration is not set, a default one will be created that logs to the console.
 *
 * @version $Rev: 9763 $ $Date: 2011-01-03 00:48:06 +0000 (Mon, 03 Jan 2011) $
 */
public class LogbackDispatcher implements MonitorEventDispatcher {
    private static final String DEFAULT_PATTERN = "[%level %thread %d{YY:MM:DD HH:mm:ss.SSS}] %msg%n%ex";
    private HostInfo hostInfo;
    private boolean configured;
    private LoggerContext context;
    private Logger logger;

    static {
        ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger(Logger.ROOT_LOGGER_NAME).detachAndStopAllAppenders();
    }

    /**
     * Constructor which delegates to a log context that uses a private appender configuration and does not send messages to parent appenders.
     *
     * @param name     the log context name
     * @param hostInfo the host info
     */
    public LogbackDispatcher(String name, HostInfo hostInfo) {
        // by default do not send log messages to parent appenders
        this(name, false, hostInfo);
    }

    /**
     * Constructor.
     *
     * @param name     the log context name
     * @param additive true if the log context should use parent appenders; otherwise the log context uses a private appender configuration and does
     *                 not send messages to parent appenders.
     * @param hostInfo the host info
     */
    public LogbackDispatcher(String name, boolean additive, HostInfo hostInfo) {
        this.hostInfo = hostInfo;
        context = (LoggerContext) LoggerFactory.getILoggerFactory();
        logger = context.getLogger(name);
        logger.setAdditive(additive);
    }

    public void configure(Element element) throws MonitorConfigurationException {
        try {
            expandLogFileNames(element);
            // wrap the configuration in a document that LogBack accepts
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            document.adoptNode(element);
            document.appendChild(element);
            InputSource source = transform(document);

            logger.detachAndStopAllAppenders();
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(context);
            configurator.doConfigure(source);
            configured = true;
        } catch (ParserConfigurationException e) {
            throw new MonitorConfigurationException("Error parsing monitor configuration", e);
        } catch (TransformerException e) {
            throw new MonitorConfigurationException("Error parsing monitor configuration", e);
        } catch (JoranException e) {
            throw new MonitorConfigurationException("Error parsing monitor configuration", e);
        }
    }

    public void start() {
        if (!configured) {
            configureDefaultAppender(context);
        }
    }

    public void stop() {
        // stop appenders
        logger.detachAndStopAllAppenders();
    }

    public void onEvent(MonitorEvent event) {
        if (!(event instanceof ILoggingEvent)) {
            throw new AssertionError("Event must implement " + ILoggingEvent.class.getName());
        }
        logger.callAppenders((ILoggingEvent) event);
    }

    /**
     * Replace relative file names in appender configurations with absolute paths under the runtime data/logs directory.
     *
     * @param element the log configuration
     */
    private void expandLogFileNames(Element element) {
        NodeList files = element.getElementsByTagName("file");
        File dir = new File(hostInfo.getDataDir(), "log");
        for (int i = 0; i < files.getLength(); i++) {
            if (!dir.exists()) {
                dir.mkdirs();
            }
            Element fileElement = (Element) files.item(i);
            fileElement.setTextContent(new File(dir, fileElement.getTextContent()).getAbsolutePath());
        }
    }

    /**
     * Creates a default console appender if a configuration is not set.
     *
     * @param context the context to configure
     */
    private void configureDefaultAppender(LoggerContext context) {
        logger.detachAndStopAllAppenders();
        ConsoleAppender appender = new ConsoleAppender();
        appender.setContext(context);
        appender.setName("fabric3-console");
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(context);
        encoder.setPattern(DEFAULT_PATTERN);
        encoder.start();
        appender.setEncoder(encoder);
        appender.start();
        logger.addAppender(appender);
    }

    /**
     * Transforms a document to an InputSource.
     *
     * @param document the document
     * @return the InputSource
     * @throws TransformerException if the document cannot be transformed
     */
    private InputSource transform(Document document) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        DOMSource source = new DOMSource(document);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        StreamResult result = new StreamResult(stream);
        transformer.transform(source, result);
        return new InputSource(new ByteArrayInputStream(stream.toByteArray()));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy