michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.background.common.log; michael@0: michael@0: import java.io.PrintWriter; michael@0: import java.util.Iterator; michael@0: import java.util.LinkedHashSet; michael@0: import java.util.Set; michael@0: michael@0: import org.mozilla.gecko.background.common.GlobalConstants; michael@0: import org.mozilla.gecko.background.common.log.writers.AndroidLevelCachingLogWriter; michael@0: import org.mozilla.gecko.background.common.log.writers.AndroidLogWriter; michael@0: import org.mozilla.gecko.background.common.log.writers.LogWriter; michael@0: import org.mozilla.gecko.background.common.log.writers.PrintLogWriter; michael@0: import org.mozilla.gecko.background.common.log.writers.SimpleTagLogWriter; michael@0: import org.mozilla.gecko.background.common.log.writers.ThreadLocalTagLogWriter; michael@0: michael@0: import android.util.Log; michael@0: michael@0: /** michael@0: * Logging helper class. Serializes all log operations (by synchronizing). michael@0: */ michael@0: public class Logger { michael@0: public static final String LOGGER_TAG = "Logger"; michael@0: public static final String DEFAULT_LOG_TAG = "GeckoLogger"; michael@0: michael@0: // For extra debugging. michael@0: public static boolean LOG_PERSONAL_INFORMATION = false; michael@0: michael@0: /** michael@0: * Allow each thread to use its own global log tag. This allows michael@0: * independent services to log as different sources. michael@0: * michael@0: * When your thread sets up logging, it should do something like the following: michael@0: * michael@0: * Logger.setThreadLogTag("MyTag"); michael@0: * michael@0: * The value is inheritable, so worker threads and such do not need to michael@0: * set the same log tag as their parent. michael@0: */ michael@0: private static final InheritableThreadLocal logTag = new InheritableThreadLocal() { michael@0: @Override michael@0: protected String initialValue() { michael@0: return DEFAULT_LOG_TAG; michael@0: } michael@0: }; michael@0: michael@0: public static void setThreadLogTag(final String logTag) { michael@0: Logger.logTag.set(logTag); michael@0: } michael@0: public static String getThreadLogTag() { michael@0: return Logger.logTag.get(); michael@0: } michael@0: michael@0: /** michael@0: * Current set of writers to which we will log. michael@0: *

michael@0: * We want logging to be available while running tests, so we initialize michael@0: * this set statically. michael@0: */ michael@0: protected final static Set logWriters; michael@0: static { michael@0: final Set defaultWriters = Logger.defaultLogWriters(); michael@0: logWriters = new LinkedHashSet(defaultWriters); michael@0: } michael@0: michael@0: /** michael@0: * Default set of log writers to log to. michael@0: */ michael@0: public final static Set defaultLogWriters() { michael@0: final String processedPackage = GlobalConstants.BROWSER_INTENT_PACKAGE.replace("org.mozilla.", ""); michael@0: michael@0: final Set defaultLogWriters = new LinkedHashSet(); michael@0: michael@0: final LogWriter log = new AndroidLogWriter(); michael@0: final LogWriter cache = new AndroidLevelCachingLogWriter(log); michael@0: michael@0: final LogWriter single = new SimpleTagLogWriter(processedPackage, new ThreadLocalTagLogWriter(Logger.logTag, cache)); michael@0: michael@0: defaultLogWriters.add(single); michael@0: return defaultLogWriters; michael@0: } michael@0: michael@0: public static synchronized void startLoggingTo(LogWriter logWriter) { michael@0: logWriters.add(logWriter); michael@0: } michael@0: michael@0: public static synchronized void startLoggingToWriters(Set writers) { michael@0: logWriters.addAll(writers); michael@0: } michael@0: michael@0: public static synchronized void stopLoggingTo(LogWriter logWriter) { michael@0: try { michael@0: logWriter.close(); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e); michael@0: } michael@0: logWriters.remove(logWriter); michael@0: } michael@0: michael@0: public static synchronized void stopLoggingToAll() { michael@0: for (LogWriter logWriter : logWriters) { michael@0: try { michael@0: logWriter.close(); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e); michael@0: } michael@0: } michael@0: logWriters.clear(); michael@0: } michael@0: michael@0: /** michael@0: * Write to only the default log writers. michael@0: */ michael@0: public static synchronized void resetLogging() { michael@0: stopLoggingToAll(); michael@0: logWriters.addAll(Logger.defaultLogWriters()); michael@0: } michael@0: michael@0: /** michael@0: * Start writing log output to stdout. michael@0: *

michael@0: * Use resetLogging to stop logging to stdout. michael@0: */ michael@0: public static synchronized void startLoggingToConsole() { michael@0: setThreadLogTag("Test"); michael@0: startLoggingTo(new PrintLogWriter(new PrintWriter(System.out, true))); michael@0: } michael@0: michael@0: // Synchronized version for other classes to use. michael@0: public static synchronized boolean shouldLogVerbose(String logTag) { michael@0: for (LogWriter logWriter : logWriters) { michael@0: if (logWriter.shouldLogVerbose(logTag)) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: public static void error(String tag, String message) { michael@0: Logger.error(tag, message, null); michael@0: } michael@0: michael@0: public static void warn(String tag, String message) { michael@0: Logger.warn(tag, message, null); michael@0: } michael@0: michael@0: public static void info(String tag, String message) { michael@0: Logger.info(tag, message, null); michael@0: } michael@0: michael@0: public static void debug(String tag, String message) { michael@0: Logger.debug(tag, message, null); michael@0: } michael@0: michael@0: public static void trace(String tag, String message) { michael@0: Logger.trace(tag, message, null); michael@0: } michael@0: michael@0: public static void pii(String tag, String message) { michael@0: if (LOG_PERSONAL_INFORMATION) { michael@0: Logger.debug(tag, "$$PII$$: " + message); michael@0: } michael@0: } michael@0: michael@0: public static synchronized void error(String tag, String message, Throwable error) { michael@0: Iterator it = logWriters.iterator(); michael@0: while (it.hasNext()) { michael@0: LogWriter writer = it.next(); michael@0: try { michael@0: writer.error(tag, message, error); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e); michael@0: it.remove(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: public static synchronized void warn(String tag, String message, Throwable error) { michael@0: Iterator it = logWriters.iterator(); michael@0: while (it.hasNext()) { michael@0: LogWriter writer = it.next(); michael@0: try { michael@0: writer.warn(tag, message, error); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e); michael@0: it.remove(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: public static synchronized void info(String tag, String message, Throwable error) { michael@0: Iterator it = logWriters.iterator(); michael@0: while (it.hasNext()) { michael@0: LogWriter writer = it.next(); michael@0: try { michael@0: writer.info(tag, message, error); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e); michael@0: it.remove(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: public static synchronized void debug(String tag, String message, Throwable error) { michael@0: Iterator it = logWriters.iterator(); michael@0: while (it.hasNext()) { michael@0: LogWriter writer = it.next(); michael@0: try { michael@0: writer.debug(tag, message, error); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e); michael@0: it.remove(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: public static synchronized void trace(String tag, String message, Throwable error) { michael@0: Iterator it = logWriters.iterator(); michael@0: while (it.hasNext()) { michael@0: LogWriter writer = it.next(); michael@0: try { michael@0: writer.trace(tag, message, error); michael@0: } catch (Exception e) { michael@0: Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e); michael@0: it.remove(); michael@0: } michael@0: } michael@0: } michael@0: }