/* * Copyright 2008 The Microlog project @sourceforge.net * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.code.microlog4android; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.util.Log; import com.google.code.microlog4android.appender.Appender; import com.google.code.microlog4android.factory.DefaultAppenderFactory; import com.google.code.microlog4android.repository.CommonLoggerRepository; /** * The <code>Logger</code> class is used for logging. * * This is similar to the Log4j <code>Logger</code> class. The method names are * the same, but we do not claim that they are 100% compatible. * * You have the ability to use named loggers as in Log4j. If you want to save * memory, you could use unnamed loggers. * * @author Johan Karlsson (johan.karlsson@jayway.se) * @author Darius Katz * @author Karsten Ohme * @since 0.1 */ public final class Logger { private static final String TAG = "Microlog.Logger"; public static final Level DEFAULT_LOG_LEVEL = Level.DEBUG; public static final String DEFAULT_CLIENT_ID = "Microlog"; private CommonLoggerRepository commonLoggerRepository = null; private String clientID = DEFAULT_CLIENT_ID; private String name; private Level level; private static final StopWatch stopWatch = new StopWatch(); private final static List<Appender> appenderList = new ArrayList<Appender>(4); private static boolean firstLogEvent = true; /** * Create a logger with the specified <code>name</code>. The * <code>LoggerFactory</code> should be used for creating * <code>Logger</code> objects. * * @param name * the name of the logger. */ public Logger(String name) { this.name = name; } public Logger(String name, CommonLoggerRepository commonLoggerRepository) { this.name = name; this.commonLoggerRepository = commonLoggerRepository; } public synchronized void setCommonRepository(final CommonLoggerRepository commonLoggerRepository) { this.commonLoggerRepository = commonLoggerRepository; } /** * Get the log level. * * @return the log <code>Level</code>. */ public Level getLevel() { return level; } /** * Set the log level. * * @param level * The logLevel to set. * @throws IllegalArgumentException * if the <code>level</code> is null. */ public void setLevel(Level level) throws IllegalArgumentException { if (level == null) { throw new IllegalArgumentException("The level must not be null."); } this.level = level; } /** * Get the effective log level. If we have a hierarchy of loggers, this is * searched to get the effective level. * * @return the effective logger level. */ public Level getEffectiveLevel() { Level effectiveLevel = level; if (effectiveLevel == null && !name.equals("")) { if(commonLoggerRepository == null) { throw new IllegalStateException("CommonLoggerRepository has not been set"); } else { effectiveLevel = commonLoggerRepository.getEffectiveLevel(name); } } return effectiveLevel; } /** * Get the client ID. * * @return the clientID */ public String getClientID() { return clientID; } /** * Set the client ID. * * @param clientID * the clientID to set */ public void setClientID(String clientID) { this.clientID = clientID; } /** * Get the name of the <code>Logger</code>. * * @return the name of the <code>Logger</code>. */ public String getName() { return name; } /** * Add the specified appender to the output appenders. * * @param appender * the <code>Appender</code> to add. * @throws IllegalArgumentException * if the <code>appender</code> is <code>null</code>. */ public void addAppender(Appender appender) throws IllegalArgumentException { if (appender == null) { throw new IllegalArgumentException("Appender not allowed to be null"); } if (!appenderList.contains(appender)) { appenderList.add(appender); } } /** * Remove the specified appender from the appender list. * * @param appender * the <code>Appender</code> to remove. */ public void removeAppender(Appender appender) throws IllegalArgumentException { if (appender == null) { throw new IllegalArgumentException("The appender must not be null."); } if (appender.isLogOpen()) { try { appender.close(); } catch (IOException e) { Log.e(TAG, "Failed to close appender. " + e); } } appenderList.remove(appender); } /** * Remove all the appenders. * */ public void removeAllAppenders() { for (Appender appender : appenderList) { if (appender.isLogOpen()) { try { appender.close(); } catch (IOException e) { Log.e(TAG, "Failed to close appender. " + e); } } } appenderList.clear(); } /** * Get the number of appenders. * * @return the number of appenders. */ public int getNumberOfAppenders() { return appenderList.size(); } /** * Get the specified appender, starting at index = 0. * * @param index * the index of the appender. * @return the appender. */ public Appender getAppender(int index) { return appenderList.get(index); } /** * Log the message at the specified level. * * @param level * the <code>Level</code> to log at. * @param message * the message to log. * @throws IllegalArgumentException * if the <code>level</code> is <code>null</code>. */ public void log(Level level, Object message) throws IllegalArgumentException { log(level, message, null); } /** * Log the message and the Throwable object at the specified level. * * @param level * the log level * @param message * the message to log. * @param t * the <code>Throwable</code> object. * @throws IllegalArgumentException * if the <code>level</code> is <code>null</code>. */ public void log(Level level, Object message, Throwable t) throws IllegalArgumentException { if (level == null) { throw new IllegalArgumentException("The level must not be null."); } if (getEffectiveLevel().toInt() <= level.toInt() && level.toInt() > Level.OFF_INT) { if (firstLogEvent == true) { addDefaultAppender(); try { open(); } catch (IOException e) { Log.e(TAG, "Failed to open the log. " + e); } stopWatch.start(); firstLogEvent = false; } for (Appender appender : appenderList) { appender.doLog(clientID, name, stopWatch.getCurrentTime(), level, message, t); } } } private void addDefaultAppender() { if(appenderList.size() == 0) { Log.w(TAG, "Warning! No appender is set, using LogCatAppender with PatternFormatter"); Appender appender = DefaultAppenderFactory.createDefaultAppender(); addAppender(appender); } } /** * Is this <code>Logger</code> enabled for TRACE level? * * @return true if logging is enabled. */ public boolean isTraceEnabled() { Level effectiveLevel = getEffectiveLevel(); return effectiveLevel.toInt() <= Level.TRACE_INT; } /** * Log the message at <code>Level.TRACE</code> level. * * @param message * the message to log. */ public void trace(Object message) { log(Level.TRACE, message, null); } /** * Log the message and the <code>Throwable</code> object at * <code>Level.TRACE</code>. * * @param message * the message to log. * @param t * the Throwable object to log. */ public void trace(Object message, Throwable t) { log(Level.TRACE, message, t); } /** * Is this <code>Logger</code> enabled for DEBUG level? * * @return true if logging is enabled. */ public boolean isDebugEnabled() { Level effectiveLevel = getEffectiveLevel(); return effectiveLevel.toInt() <= Level.DEBUG_INT; } /** * Log the message at <code>Level.DEBUG</code> level. * * @param message * the message to log. */ public void debug(Object message) { log(Level.DEBUG, message, null); } /** * Log the message and the <code>Throwable</code> object at * <code>Level.DEBUG</code> level. * * @param message * the message to log. * @param t * the <code>Throwable</code> object to log. */ public void debug(Object message, Throwable t) { log(Level.DEBUG, message, t); } /** * Is this <code>Logger</code> enabled for INFO level? * * @return true if the <code>Level.INFO</code> level is enabled. */ public boolean isInfoEnabled() { Level effectiveLevel = getEffectiveLevel(); return effectiveLevel.toInt() <= Level.INFO_INT; } /** * Log the specified message at <code>Level.INFO</code> level. * * @param message * the message to log. */ public void info(Object message) { log(Level.INFO, message, null); } /** * Log the specified message and the <code>Throwable</code> at * <code>Level.INFO</code> level. * * @param message * the message to log. * @param t * the <code>Throwable</code> to log. */ public void info(Object message, Throwable t) { log(Level.INFO, message, t); } /** * Log the specified message at <code>Level.WARN</code> level. * * @param message * the message to log. */ public void warn(Object message) { log(Level.WARN, message, null); } /** * Log the specified message and <code>Throwable</code> object at * <code>Level.WARN</code> level. * * @param message * the object to log. * @param t * the <code>Throwable</code> to log. */ public void warn(Object message, Throwable t) { log(Level.WARN, message, t); } /** * Log the specified message at ERROR level. * * @param message * the object to log. */ public void error(Object message) { log(Level.ERROR, message, null); } /** * Log the specified message and Throwable object at ERROR level. * * @param message * the object to log. * @param t * the <code>Throwable</code> to log. */ public void error(Object message, Throwable t) { log(Level.ERROR, message, t); } /** * Log the specified message at FATAL level. * * @param message * the object to log. */ public void fatal(Object message) { log(Level.FATAL, message, null); } /** * Log the specified message and Throwable object at FATAL level. * * @param message * the object to log. * @param t * the <code>Throwable</code> to log. */ public void fatal(Object message, Throwable t) { log(Level.FATAL, message, t); } /** * @see java.lang.Object#toString() */ public String toString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(super.toString()); stringBuffer.append('['); for (Appender appender : appenderList) { stringBuffer.append(appender); stringBuffer.append(';'); } stringBuffer.append(']'); return stringBuffer.toString(); } /** * Reset the Logger, i.e. remove all appenders and set the log level to the * default level. */ public synchronized void resetLogger() { Logger.appenderList.clear(); Logger.stopWatch.stop(); Logger.stopWatch.reset(); Logger.firstLogEvent = true; } /** * Open the log. The logging is now turned on. */ void open() throws IOException { for (Appender appender : appenderList) { appender.open(); } } /** * Close the log. From this point on, no logging is done. * * @throws IOException * if the <code>Logger</code> failed to close. */ public void close() throws IOException { for (Appender appender : appenderList) { appender.close(); } stopWatch.stop(); Logger.firstLogEvent = true; } }