/* -*- mode: Java; c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/ /* * Copyright (c) 2002 Extreme! Lab, Indiana University. All rights reserved. * * This software is open source. See the bottom of this file for the licence. * * $Id: Logger.java,v 1.17 2003/03/17 21:41:49 aslom Exp $ */ package soaprmi.util.logging; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.IllegalArgumentException; import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; /** * miniLogger really small logger that is self-contained and very easy to use * and configure from command line using system properties * (or from inside of your application if you desire so). * * @version $Revision: 1.17 $ $Date: 2003/03/17 21:41:49 $ (GMT) * @author Aleksander Slominski [http://www.extreme.indiana.edu/~aslom] */ public class Logger { public static final Logger global = new Logger("global", null); public static final String PROPERTY_PREFIX = ""; //"foo.bar." public static final String PROPERTY_LOG = PROPERTY_PREFIX+"log"; public static final String PROPERTY_SHOWTIME = PROPERTY_PREFIX+"showtime"; public static final String PROPERTY_DEBUG = PROPERTY_PREFIX+"debug"; private static final boolean QUIET = false; // no configuration messages private static final boolean DEBUG = false; private static final boolean WARN = false; // global state private static PrintStream sink = System.err; private static boolean guessFailed; private static List anchoredLoggers = new LinkedList(); private static boolean showTime = true; //private static List cmdLoggers; // per instance states private Level myLevel; private String myName; // do magic reading -Dlog property, ex: // -Dlog=wombat:INFO,tests:ALL,xpp:OFF // -Dlog=:OFF // -Ddebug=true static { if(Log.ON) { //cmdLoggers = new ArrayList(); try { //String names = System.getProperty("log"); String names = null; try { names = (String) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return System.getProperty(PROPERTY_LOG); } }); } catch(AccessControlException ace) { if(DEBUG) System.err.println("no access to log sytem property for log"); if(DEBUG) ace.printStackTrace(); } if(DEBUG) System.err.println("Logger log="+names); // last resort String debug = System.getProperty(PROPERTY_DEBUG); if(names == null && debug != null) { String s = debug.toLowerCase(); if(DEBUG) System.err.println("Logger debug="+s); if(!"false".equals(s) && !"off".equals(s)) names = ":ALL"; } if(!QUIET && names != null ) { System.err.println( "Logger $Revision: 1.17 $ $Date: 2003/03/17 21:41:49 $ (GMT)"+ " configured as '"+names+"'"); } setCmdNames(names); //set list of loggers and levels String requestedShowTime = System.getProperty(PROPERTY_SHOWTIME); if(requestedShowTime != null) { showTime = Boolean.getBoolean(requestedShowTime); } } catch(IllegalArgumentException ex) { // this is user error and that is why printing of it is not suppressed System.err.println("can't set logging "+ex); ex.printStackTrace(); } catch(java.security.AccessControlException ex) { if(WARN ||DEBUG) { System.err.println("can't set logging "+ex); ex.printStackTrace(); } } } } protected Logger(String name, String resourceBundleName) { this.myName = name; } public static Logger getAnonymousLogger() { return new Logger(null, null); } public static Logger getLogger(java.lang.String name) { return LogManager.getLogManager().getLogger(name); } public static Logger getLogger() { // determine log klass dynamically String name = ""; Location loc = new Location(); if(guessLocation(loc, 2)) { name = loc.klass; } if(DEBUG) System.err.println("Logger.getLogger loc.klass="+loc.klass); return LogManager.getLogManager().getLogger(name); } public String getName() { return myName; } public boolean isLoggable(Level level) { return level.intValue() >= myLevel.intValue(); } public final boolean isSevereEnabled() { return isLoggable(Level.SEVERE); } public final boolean isWariningEnabled() { return isLoggable(Level.WARNING); } public final boolean isInfoEnabled() { return isLoggable(Level.INFO); } public final boolean isConfigEnabled() { return isLoggable(Level.CONFIG); } public final boolean isFineEnabled() { return isLoggable(Level.FINE); } public final boolean isFinerEnabled() { return isLoggable(Level.FINER); } public final boolean isFinestEnabled() { return isLoggable(Level.FINEST); } public void setLevel(Level newLevel) { myLevel = newLevel; if(DEBUG) { boolean enabled = myLevel != Level.OFF; System.err.println("Logger.setLevel name='"+myName+"' level="+myLevel+" enabled="+enabled); //if(DEBUG) System.err.println("Logger name="+name+" is not enabled"); } } public Level getLevel() { return myLevel; } protected static String parametersToList(Object[] params) { if(params == null) return " array with parameters is null"; StringBuffer sb = new StringBuffer(); for (int i = 0; i < params.length; i++) { sb.append(params[i]); if(i < params.length - 1) sb.append(","); } return sb.toString(); } /** Log a method entry with Level.FINER and message "ENTRY" */ public void entering() { logg(Level.FINER, "ENTRY"); } public void entering(String sourceClass, String sourceMethod) { logg(Level.FINER, sourceClass+":"+sourceMethod+" ENTRY"); } /** Log a method entry with Level.FINER and message "ENTRY" and parametr content appended */ public void entering(Object param1) { logg(Level.FINER, "ENTRY "+param1); } public void entering(String sourceClass, String sourceMethod, Object param1) { logg(Level.FINER, sourceClass+":"+sourceMethod+" ENTRY "+param1); } /** Log a method entry with Level.FINER and message "ENTRY" and parametrs content appended */ public void entering(Object[] params) { logg(Level.FINER, "ENTRY "+parametersToList(params)); } public void entering(String sourceClass, String sourceMethod, Object[] params) { logg(Level.FINER, sourceClass+":"+sourceMethod+" ENTRY "+parametersToList(params)); } /** Log a method return with Level.FINER and message "RETURN" */ public void exiting() { logg(Level.FINER, "RETURN"); } public void exiting(String sourceClass, String sourceMethod) { logg(Level.FINER, sourceClass+":"+sourceMethod+" RETURN"); } /** Log a method return with Level.FINER and message "RETURN" and return value appended */ public void exiting(Object result) { logg(Level.FINER, "RETURN "+result); } public void exiting(String sourceClass, String sourceMethod, Object result) { logg(Level.FINER, sourceClass+":"+sourceMethod+" RETURN "+result); } /** Log an exception thrown with Level.FINER and message "THROW" and exception appended*/ public Throwable throwing(Throwable thrown) { logg(Level.FINER, "THROW", thrown); return thrown; } public Throwable throwing(String sourceClass, String sourceMethod, Throwable thrown) { logg(Level.FINER, sourceClass+":"+sourceMethod+" THROW", thrown); return thrown; } /** report that exception was caught with log message at FINER level and "CAUGHT" message */ public Throwable caught(Throwable thrown) { logg(Level.FINER, "CAUGHT", thrown); return thrown; } public Throwable caught(String sourceClass, String sourceMethod, Throwable thrown) { logg(Level.FINER, sourceClass+":"+sourceMethod+" CAUGHT", thrown); return thrown; } public void severe(String msg) { logg(Level.SEVERE, msg); } public void warning(String msg) { logg(Level.WARNING, msg); } public void info(String msg) { logg(Level.INFO, msg); } public void config(String msg) { logg(Level.CONFIG, msg); } public void fine(String msg) { logg(Level.FINE, msg); } public void finer(String msg) { logg(Level.FINER, msg); } public void finest(String msg) { logg(Level.FINEST, msg); } public void log(Level level, String msg) { logg(level, msg); } public void log(Level level, String msg, Throwable thrown) { logg(level, msg, thrown); } public void log(Level level, String msg, Object param1) { logg(level, msg+" "+param1); } public void log(Level level, String msg, Object[] params) { logg(level, msg+" "+parametersToList(params)); } public void severe(String msg, Throwable thrown) { logg(Level.SEVERE, msg, thrown); } public void warning(String msg, Throwable thrown) { logg(Level.WARNING, msg, thrown); } public void info(String msg, Throwable thrown) { logg(Level.INFO, msg, thrown); } public void config(String msg, Throwable thrown) { logg(Level.CONFIG, msg, thrown); } public void fine(String msg, Throwable thrown) { logg(Level.FINE, msg, thrown); } public void finer(String msg, Throwable thrown) { logg(Level.FINER, msg, thrown); } public void finest(String msg, Throwable thrown) { logg(Level.FINEST, msg, thrown); } public static synchronized PrintStream getSink() { return sink; } public static synchronized void setSink(PrintStream ps) { if(!QUIET) System.err.println("Logger sink="+ps); if(sink != System.err) { String s = global.queryPrefix() + "Logger.setSink() can only be called once"; ps.println(s); throw new IllegalArgumentException("sink can be only set once"); } sink = ps; } // --- internal state protected void logg(Level level, String msg) { if(!isLoggable(level)) { return; } String s = queryPrefix() + msg; //"\n\tat zoo.Zoo.sayMoo(Zoo.java:15) " synchronized(getClass()) { sink.println(s); } if(!Log.ON) { throw new RuntimeException( "For efficiency reasons use code: if(Log.ON) log(..)"); } } protected void logg(Level level, String msg, Throwable thrown) { if(!isLoggable(level)) return; String s = queryPrefix() + msg; synchronized(getClass()) { sink.print(s+" expection: "); if(thrown != null) { thrown.printStackTrace(sink); } } if(!Log.ON) { throw new RuntimeException( "For efficiency reasons use code: if(Log.ON) log(..)"); } } private String queryPrefix() { //TODO: is it faster than shared myLoc and synchronizing(myLoc) (considering printing...)? Location myLoc = new Location(); StringBuffer buf = new StringBuffer(80); buf.append("[ "); if(guessLocation(myLoc)) { if(showTime) { long now = System.currentTimeMillis(); formatTime(now, buf); buf.append(' '); } String tname = Thread.currentThread().getName(); //toString(); //long ltid = Thread.currentThread().hashCode(); //String tid = Long.toString(ltid, 16); buf.append(tname).append(": "); //e.printStackTrace(System.out); boolean addSpaceAfterLoggerName = true; String loggerNameToPrint = myName; if(myLoc.fileName != null) { int i = myLoc.fileName.lastIndexOf(".java"); if(i > 0) { String s = myLoc.fileName.substring(0, i); if(myName.endsWith(s)) { int j = myName.length() - s.length(); loggerNameToPrint = myName.substring(0, j); //+"%"+ myName.substring(j); addSpaceAfterLoggerName = false; } } } buf.append(loggerNameToPrint); if(addSpaceAfterLoggerName) { buf.append(" "); } if(myLoc.line != -1) { buf.append(myLoc.fileName).append(':') .append(myLoc.line).append(' ').append(myLoc.method); } else { buf.append(myLoc.fileName).append(' ') .append(myLoc.klass).append(' ').append(myLoc.method); } } else { buf.append(myName); } buf.append(" ] "); //} return buf.toString(); } private static boolean guessLocation(Location loc) { return guessLocation(loc, 5); } private static boolean guessLocation(Location loc, int levels) { if(guessFailed) return false; Throwable throwable = new Throwable(); StringWriter sw = new StringWriter(); throwable.printStackTrace(new PrintWriter(sw)); String s = sw.toString()+"\n"; String line = null; try { // skip two lines int i = s.indexOf('\n'); for(int lines = 0; lines < levels; ++lines) i = s.indexOf('\n', i+1); int j = s.indexOf('\n', i+1); // extract info from line ex.: // " at soaprmi.soapenc.SoapEnc.readObject(SoapEnc.java:116)"); ///System.err.println("s="+s+" i="+i+" j="+j); line = s.substring(i+1, j); if(DEBUG) System.err.println("line="+line); i = line.indexOf('('); if(i < 0) { if(DEBUG) System.err.println("problem trace="+s+" line="+line); line = "at .(.java:-1)"; i = line.indexOf('('); } loc.method = line.substring(0, i); j = loc.method.lastIndexOf('.'); if(j < 0) { loc.klass = ""; int k = loc.method.lastIndexOf("at "); loc.method = loc.method.substring(k+3); } else { int k = loc.method.lastIndexOf("at "); loc.klass = loc.method.substring(k+3, j); //! loc.method = loc.method.substring(j+1); } j = line.lastIndexOf(')'); String pos = line.substring(i+1, j); //! loc.line = -1; loc.fileName = pos; i = pos.indexOf(':'); if(i >= 0) { loc.fileName=pos.substring(0, i); String lineNo = ""; try { lineNo = pos.substring(i + 1); if(DEBUG) System.err.println("lineNo="+lineNo); // hacking for IRIX: '6, Compiled Code' // from line output such like that 'at A.(A.java:6, Compiled Code)' int posComma = lineNo.indexOf(','); if(posComma != -1) { lineNo = lineNo.substring(0, posComma); } loc.line=Integer.parseInt(lineNo); } catch(NumberFormatException ex) { System.err.println(Logger.class.getName() +" disabling advanced logging " +" - can't parse" +" string: '"+line+"'" +" for line number '"+lineNo+"'" +" stack trace:---\n"+s+"\n---"); ex.printStackTrace(); guessFailed = true; } } } catch(IndexOutOfBoundsException ex) { System.err.println(Logger.class.getName()+ " disabling advanced logging - "+ " location guess failed for stack trace"+ "on line: '"+line+"'\n of stack trace:---\n"+s+"---"); ex.printStackTrace(); guessFailed = true; } return ! guessFailed; } /** * Enables list of loggers passed as string parameter. * Format: [logger_name:LEVEL][,...] * logger_name is package[.class] or any name that was given * when creating logger with Logger.getLogger("name"); * LEVEL -s execatly name of Level such as ALL, FINE, etc. * (see Level class) */ public static void setCmdNames(String names) { if(DEBUG) System.err.println("Logger.setNames names="+names); if(names != null) { if(names.indexOf(',') == -1) { setCmdLogger(names); } else { StringTokenizer tok = new StringTokenizer(names, ","); while (tok.hasMoreTokens()) { setCmdLogger(tok.nextToken()); } } } } private static void setCmdLogger(String name) { Level level = Level.ALL; //default level int pos; if((pos = name.indexOf(':')) != -1) { String levelName = name.substring(pos + 1); level = Level.parse(levelName); name = name.substring(0, pos); } // DONE: investigate to change it to LogManager.getLogManager().getLogger() Logger l = LogManager.getLogManager().getLogger(name, level); //Logger l = new Logger(name, null); //Logger.getLogger(name); //if(level != null) { // l.setLevel(level); //} //LogManager.getLogManager().addLogger(l); //NOTE: must anchor or this logger will be GC as LogManger keeps only weak references synchronized(anchoredLoggers) { //if(anchoredLoggers.contains(l) == false) { //not good enough as depends on equals() boolean found = false; // make sure that anchored list has no duplicates to avoid memory leak ... for (Iterator i = anchoredLoggers.listIterator() ; i.hasNext(); ) { Object o = i.next(); if(o == l) { found = true; break; } } if(!found) { anchoredLoggers.add(l); } } } private static void setShowTime(boolean enable) { showTime = enable; } public static void formatTime(long time, StringBuffer buf) { long ms = time % 1000; time /= 1000; long ss = time % 60; time /= 60; long mm = time % 60; time /= 60; long hh = time % 24; if(hh < 10) buf.append('0'); buf.append(hh).append(':'); if(mm < 10) buf.append('0'); buf.append(mm).append(':'); if(ss < 10) buf.append('0'); buf.append(ss).append('.'); if(ms < 100) buf.append('0'); if(ms < 10) buf.append('0'); buf.append(ms); } // print logger state -- good for debugging public String toString() { StringBuffer buf = new StringBuffer(getClass().getName()+"={"); buf.append(getName()+":"+getLevel()); buf.append("}"); return buf.toString(); } //public String toString() { // return "[Logger name='"+name+"' level='"+level+"']"; //} private static class Location { String klass; String method; String fileName; int line; }; } /* * Indiana University Extreme! Lab Software License, Version 1.2 * * Copyright (C) 2002 The Trustees of Indiana University. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1) All redistributions of source code must retain the above * copyright notice, the list of authors in the original source * code, this list of conditions and the disclaimer listed in this * license; * * 2) All redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the disclaimer * listed in this license in the documentation and/or other * materials provided with the distribution; * * 3) Any documentation included with all redistributions must include * the following acknowledgement: * * "This product includes software developed by the Indiana * University Extreme! Lab. For further information please visit * http://www.extreme.indiana.edu/" * * Alternatively, this acknowledgment may appear in the software * itself, and wherever such third-party acknowledgments normally * appear. * * 4) The name "Indiana Univeristy" or "Indiana Univeristy * Extreme! Lab" shall not be used to endorse or promote * products derived from this software without prior written * permission from Indiana University. For written permission, * please contact http://www.extreme.indiana.edu/. * * 5) Products derived from this software may not use "Indiana * Univeristy" name nor may "Indiana Univeristy" appear in their name, * without prior written permission of the Indiana University. * * Indiana University provides no reassurances that the source code * provided does not infringe the patent or any other intellectual * property rights of any other entity. Indiana University disclaims any * liability to any recipient for claims brought by any other entity * based on infringement of intellectual property rights or otherwise. * * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA * UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT * SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR * OTHER PROPRIETARY RIGHTS. INDIANA UNIVERSITY MAKES NO WARRANTIES THAT * SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP * DOORS", "WORMS", OR OTHER HARMFUL CODE. LICENSEE ASSUMES THE ENTIRE * RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS, * AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING * SOFTWARE. */