Subversion Repositories mkgmap

Rev

Rev 4850 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2006 Steve Ratcliffe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program 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.
 *
 *
 * Author: Steve Ratcliffe
 * Create date: 30-Dec-2006
 */

package uk.me.parabola.log;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;

/**
 * Simple logging class.  By default it is disabled.  You have to set it up
 * using (currently) a system property.  On the other hand it uses varargs
 * to make easier logging without having to do string concatenation in the
 * regular code.
 *
 * @author Steve Ratcliffe
 */

public class Logger {
        private final java.util.logging.Logger log;
        private final boolean addPrefix;
        public static final Logger defaultLogger = new Logger(java.util.logging.Logger.GLOBAL_LOGGER_NAME, false);

        private static final ThreadLocal<String> threadTags = new ThreadLocal<>();

        static {
                initLogging();
        }

        private Logger(String name, boolean addPrefix) {
                this.log = java.util.logging.Logger.getLogger(name);
                this.addPrefix = addPrefix;
        }

        /**
         * Get a logger by its name.
         *
         * @param name The name of the logger.  Uses the same conventions as in
         * java.util.logging.Logger as this is just a thin wrapper around that
         * class.
         * @return The logger.
         */

        public static Logger getLogger(String name) {
                return new Logger(name, true);
        }

        /**
         * Convenience class to get a logger using a class name as the name.
         * @param aClass The class - its name will be used to retrieve the
         * logger.
         * @return The logger.
         */

        public static Logger getLogger(Class<?> aClass) {
                String name = aClass.getName();
                return getLogger(name);
        }

        public static void resetLogging(String filename) {
                initLoggingFromFile(filename);
        }

        private static void initLogging() {
                Properties props = System.getProperties();

                String logconf = props.getProperty("log.config");
                if (logconf != null) {
                        initLoggingFromFile(logconf);
                }
                else {
                        staticSetup();
                }
                if (!defaultLogger.isLoggable(Level.WARNING))
                        defaultLogger.log.setLevel(Level.WARNING);
        }

        private static void initLoggingFromFile(String logconf) {
                try {
                        InputStream in = new FileInputStream(logconf);
                        LogManager lm = LogManager.getLogManager();
                        lm.reset();
                        lm.readConfiguration(in);
                } catch (FileNotFoundException e) {
                        System.err.println("Failed to open logging config file " + logconf);
                        staticSetup();
                } catch (IOException e) {
                        staticSetup();
                }
        }

        /**
         * The default setup, which is basically not to do any logging apart from
         * showing errors.
         */

        private static void staticSetup() {
                // Static setup.
                LogManager.getLogManager().reset();
                java.util.logging.Logger l = java.util.logging.Logger.getLogger("");

                ConsoleHandler handler = new ConsoleHandler();
                UsefulFormatter f = new UsefulFormatter();

                f.setShowTime(false);

                handler.setFormatter(f);
                handler.setLevel(Level.FINE);

                l.addHandler(handler);
                l.setLevel(Level.SEVERE);
        }

        public boolean isLoggable(Level level) {
                return log.isLoggable(level);
        }

        public boolean isDebugEnabled() {
                return log.isLoggable(Level.FINE);
        }

        public boolean isInfoEnabled() {
                return log.isLoggable(Level.INFO);
        }

        /**
         * Debug message.  We are using the j.u.l FINE level for this.  As it is
         * possible that the toString method on the logged object is expensive
         * we check that the message should be logged first.  Though this is
         * perhaps overkill.
         *
         * This comment applies to all the corresponding methods below.
         *
         * @param o The object to be logged.
         */

        public void debug(Object o) {
                if (log.isLoggable(Level.FINE))
                        log.fine(tagMessage(o == null? "null" : o.toString()));
        }

        /**
         * Log a message that consists of a variable number of arguments.  The
         * arguments are simply concatenated with a space between them.
         *
         * The arrayFormat call is very expensive and checking the log level first
         * is important.  The same applies to all similar routines below.
         *
         * @param olist The list of objects to log as one message.
         */

        public void debug(Object ... olist) {
                if (log.isLoggable(Level.FINE))
                        arrayFormat(Level.FINE, olist);
        }

        public void info(Object o) {
                if (log.isLoggable(Level.INFO))
                        log.info(tagMessage(o == null? "null" : o.toString()));
        }

        public void info(Object ... olist) {
                if (log.isLoggable(Level.INFO))
                        arrayFormat(Level.INFO, olist);
        }

        public void infof(String fmt, Object... args) {
                if (log.isLoggable(Level.INFO))
                        printf(Level.INFO, fmt, args);
        }

        public void warn(Object o) {
                if (log.isLoggable(Level.WARNING))
                        log.warning(tagMessage(o == null? "null" : o.toString()));
        }

        public void warn(Object ... olist) {
                if (log.isLoggable(Level.WARNING))
                        arrayFormat(Level.WARNING, olist);
        }

        public void warnf(String fmt, Object... args) {
                if (log.isLoggable(Level.WARNING))
                        printf(Level.WARNING, fmt, args);
        }

        public void error(Object o) {
                log.severe(tagMessage(o == null? "null" : o.toString()));
        }

        public void error(Object ... olist) {
                arrayFormat(Level.SEVERE, olist);
        }

        public void errorf(String fmt, Object... args) {
                printf(Level.SEVERE, fmt, args);
        }
       
        public void error(Object o, Throwable e) {
                log.log(Level.SEVERE, tagMessage(o == null? "null" : o.toString()), e);
        }
       
        // output a requested diagnostic message
        public void diagnostic(String msg) {
                log.log(LogLevel.DIAGNOSTIC, tagMessage(msg));
        }

        // output an echo or echotags message
        public void echo(String msg) {
                log.log(LogLevel.ECHO, tagMessage(msg));
        }

        // an information message that is always output
        public void write(String msg) {
                log.log(LogLevel.OVERRIDE, tagMessage(msg));
        }

        public void log(Level level, Object o) {
                if (log.isLoggable(level))
                        log.log(level, tagMessage(o == null? "null" : o.toString()));
        }

        public void log(Level level, Object ... olist) {
                if (log.isLoggable(level))
                        arrayFormat(level, olist);
        }
       
        /**
         * Format the list of arguments by appending them to one string, keeping a
         * space between them.
         *
         * Only call this if you've checked that the message needs to be printed,
         * otherwise it will all go to waste.
         *
         * @param type The Level type FINE, INFO etc.
         * @param olist The argument list as objects.
         */

        private void arrayFormat(Level type, Object... olist) {
                if (log.isLoggable(type)) {
                        StringBuilder sb = new StringBuilder();
                        for (Object o : olist) {
                                sb.append(o);
                                sb.append(' ');
                        }
                        sb.setLength(sb.length()-1);
                        log.log(type, tagMessage(sb.toString()));
                }
        }

        private void printf(Level type, String fmt, Object... args) {
                if (log.isLoggable(type)) {
                        String msg = String.format(fmt, args);
                        log.log(type, tagMessage(msg));
                }
        }

        private String tagMessage(String message) {
                if (!addPrefix)
                        return message;
               
                String threadTag = threadTags.get();
                return (threadTag != null) ? threadTag + ": " + message : message;
        }

        public void threadTag(String tag) {
                threadTags.set(tag);
        }

        public String threadTag() {
                return threadTags.get();
        }
}