/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.gmx.util; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * <p>Title: LoggingConfig</p> * <p>Description: Sketchy logging control because we can't pick a log framework.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.gmx.util.LoggingConfig</code></p> */ public class LoggingConfig { /** The singleton instance */ protected static volatile LoggingConfig instance = null; /** The singleton instance ctor lock */ protected static final Object lock = new Object(); /** Logging line separa */ public static final String EOL = System.getProperty("line.separator"); /** A map of logging enabled states keyed by package or class name */ protected final Map<String, Boolean> loggingLevels = new ConcurrentHashMap<String, Boolean>(); /** A map of gloggers */ protected final Map<String, GLogger> loggers = new ConcurrentHashMap<String, GLogger>(); /** The global logger used when the passed logger key cannot be resolved */ protected final GLogger globalLogger; /** * Acquires the singleton logging instance * @return the singleton logging instance */ public static LoggingConfig getInstance() { if(instance==null) { synchronized(lock) { if(instance==null) { instance = new LoggingConfig(); } } } return instance; } /** * Sets a logging level for the passed class. * Once the level is set, triggers an update on all registered loggers. * @param clazz The name of logging namespace to set * @param enabled true to enable, false to disable */ public static void set(Class<?> clazz, boolean enabled) { if(clazz==null) return; set(clazz.getName(), enabled); } /** * Sets a logging level for the passed name. * Once the level is set, triggers an update on all registered loggers. * @param name The name of logging namespace to set * @param enabled true to enable, false to disable */ public synchronized static void set(String name, boolean enabled) { if(name==null) return; Boolean b = getInstance().loggingLevels.get(name); if(b==null && !enabled) return; getInstance().loggingLevels.put(name, enabled); for(GLogger gl: getInstance().loggers.values()) { gl._testEnabled(); } } /** * Creates a new LoggingConfig */ private LoggingConfig() { globalLogger = new GLogger("*"); } /** * Returns a logger for the passed name * @param name The logger name * @return a logger */ public GLogger getLogger(CharSequence name) { if(name==null) return globalLogger; String key = name.toString().trim(); if("*".equals(key)) return globalLogger; GLogger logger = loggers.get(key); if(logger==null) { synchronized(loggers) { logger = loggers.get(key); if(logger==null) { logger = new GLogger(key); } } } return logger; } /** * Returns a logger for the passed class * @param clazz The class * @return a logger */ public GLogger getLogger(Class<?> clazz) { if(clazz==null) return globalLogger; return getLogger(clazz.getName()); } /** * Formats a stack trace * @param t The throwable * @return A formatted stack trace */ public static String stackTrace(Throwable t) { StringBuilder b = new StringBuilder(); for(StackTraceElement ste: t.getStackTrace()) { b.append(ste.toString()).append(EOL); } return b.toString(); } /** * <p>Title: GLogger</p> * <p>Description: A logger handed out that processes acording to the enabled state of the package or class.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.gmx.util.LoggingConfig.GLogger</code></p> */ public class GLogger { /** The GLogger Key */ protected final String key; /** The GLogger parent Key */ protected final String pkey; /** The enabled state */ protected boolean enabled = false; /** The date format */ protected final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:m:s/S"); /** * Creates a new GLogger * @param key The identity key */ public GLogger(String key) { super(); this.key = key; if(key.contains(".")) { StringBuilder b = new StringBuilder(this.key).reverse(); pkey = b.delete(0, b.indexOf(".")).reverse().toString(); } else { pkey = null; } _testEnabled(); } /** * Determines if this logger is enabled * @return true if the logger is enabled, false otherwise */ public boolean isEnabled() { return enabled; } /** * Sets the enabled state of this logger * @param enabled true to enable, false to disable */ public void setEnabled(boolean enabled) { this.enabled = enabled; LoggingConfig.set(key, enabled); } /** * Determines if this logger is enabled * @return true if the logger is enabled, false otherwise */ private boolean _testEnabled() { Boolean b = loggingLevels.get(key); if(b==null) { if(pkey!=null) { b = loggingLevels.get(pkey); } } enabled = b==null ? false : b; return enabled; } /** * Conditionally logs a formatted message * @param override If true, overrides the enabled state of the logger * @param stream The print stream to send to * @param objs The objects to format the message from */ private void _log(boolean override, PrintStream stream, Object...objs) { if(stream==null || objs==null || objs.length<1) return; StringBuilder b = new StringBuilder(sdf.format(new Date())); b.append("[").append(Thread.currentThread().getName()).append("]"); int argl = objs.length-1; for(int i = 0; i < objs.length; i++) { if(objs[i]==null) continue; if(i==argl && (objs[i] instanceof Throwable)) { b.append(stackTrace((Throwable)objs[i])); } else { b.append(objs[i].toString()); } } stream.println(b.toString()); } /** * Logs a formatted value made form the passed objects to the passed print stream * @param stream The print stream to send to * @param objs The objects to format the message from */ public void log(PrintStream stream, Object...objs) { if(!enabled) return; _log(false, stream, objs); } /** * Logs a formatted value made form the passed objects to System out * @param objs The objects to format the message from */ public void log(Object...objs) { log(System.out, objs); } /** * Unconditionally logs a formatted value made form the passed objects to System out * @param objs The objects to format the message from */ public void olog(Object...objs) { _log(true, System.out, objs); } /** * Logs a formatted value made form the passed objects to System err * @param objs The objects to format the message from */ public void elog(Object...objs) { _log(true, System.err, objs); } } }