summaryrefslogtreecommitdiffstats
path: root/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log')
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java232
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java132
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java46
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java67
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java29
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java77
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java21
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java57
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java55
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java25
10 files changed, 741 insertions, 0 deletions
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java
new file mode 100644
index 000000000..2575717eb
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java
@@ -0,0 +1,232 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.writers.AndroidLevelCachingLogWriter;
+import org.mozilla.gecko.background.common.log.writers.AndroidLogWriter;
+import org.mozilla.gecko.background.common.log.writers.LogWriter;
+import org.mozilla.gecko.background.common.log.writers.PrintLogWriter;
+import org.mozilla.gecko.background.common.log.writers.SimpleTagLogWriter;
+import org.mozilla.gecko.background.common.log.writers.ThreadLocalTagLogWriter;
+
+import android.util.Log;
+
+/**
+ * Logging helper class. Serializes all log operations (by synchronizing).
+ */
+public class Logger {
+ public static final String LOGGER_TAG = "Logger";
+ public static final String DEFAULT_LOG_TAG = "GeckoLogger";
+
+ // For extra debugging.
+ public static boolean LOG_PERSONAL_INFORMATION = false;
+
+ /**
+ * Allow each thread to use its own global log tag. This allows
+ * independent services to log as different sources.
+ *
+ * When your thread sets up logging, it should do something like the following:
+ *
+ * Logger.setThreadLogTag("MyTag");
+ *
+ * The value is inheritable, so worker threads and such do not need to
+ * set the same log tag as their parent.
+ */
+ private static final InheritableThreadLocal<String> logTag = new InheritableThreadLocal<String>() {
+ @Override
+ protected String initialValue() {
+ return DEFAULT_LOG_TAG;
+ }
+ };
+
+ public static void setThreadLogTag(final String logTag) {
+ Logger.logTag.set(logTag);
+ }
+ public static String getThreadLogTag() {
+ return Logger.logTag.get();
+ }
+
+ /**
+ * Current set of writers to which we will log.
+ * <p>
+ * We want logging to be available while running tests, so we initialize
+ * this set statically.
+ */
+ protected final static Set<LogWriter> logWriters;
+ static {
+ final Set<LogWriter> defaultWriters = Logger.defaultLogWriters();
+ logWriters = new LinkedHashSet<LogWriter>(defaultWriters);
+ }
+
+ /**
+ * Default set of log writers to log to.
+ */
+ public final static Set<LogWriter> defaultLogWriters() {
+ final String processedPackage = GlobalConstants.BROWSER_INTENT_PACKAGE.replace("org.mozilla.", "");
+
+ final Set<LogWriter> defaultLogWriters = new LinkedHashSet<LogWriter>();
+
+ final LogWriter log = new AndroidLogWriter();
+ final LogWriter cache = new AndroidLevelCachingLogWriter(log);
+
+ final LogWriter single = new SimpleTagLogWriter(processedPackage, new ThreadLocalTagLogWriter(Logger.logTag, cache));
+
+ defaultLogWriters.add(single);
+ return defaultLogWriters;
+ }
+
+ public static synchronized void startLoggingTo(LogWriter logWriter) {
+ logWriters.add(logWriter);
+ }
+
+ public static synchronized void startLoggingToWriters(Set<LogWriter> writers) {
+ logWriters.addAll(writers);
+ }
+
+ public static synchronized void stopLoggingTo(LogWriter logWriter) {
+ try {
+ logWriter.close();
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e);
+ }
+ logWriters.remove(logWriter);
+ }
+
+ public static synchronized void stopLoggingToAll() {
+ for (LogWriter logWriter : logWriters) {
+ try {
+ logWriter.close();
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e);
+ }
+ }
+ logWriters.clear();
+ }
+
+ /**
+ * Write to only the default log writers.
+ */
+ public static synchronized void resetLogging() {
+ stopLoggingToAll();
+ logWriters.addAll(Logger.defaultLogWriters());
+ }
+
+ /**
+ * Start writing log output to stdout.
+ * <p>
+ * Use <code>resetLogging</code> to stop logging to stdout.
+ */
+ public static synchronized void startLoggingToConsole() {
+ setThreadLogTag("Test");
+ startLoggingTo(new PrintLogWriter(new PrintWriter(System.out, true)));
+ }
+
+ // Synchronized version for other classes to use.
+ public static synchronized boolean shouldLogVerbose(String logTag) {
+ for (LogWriter logWriter : logWriters) {
+ if (logWriter.shouldLogVerbose(logTag)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void error(String tag, String message) {
+ Logger.error(tag, message, null);
+ }
+
+ public static void warn(String tag, String message) {
+ Logger.warn(tag, message, null);
+ }
+
+ public static void info(String tag, String message) {
+ Logger.info(tag, message, null);
+ }
+
+ public static void debug(String tag, String message) {
+ Logger.debug(tag, message, null);
+ }
+
+ public static void trace(String tag, String message) {
+ Logger.trace(tag, message, null);
+ }
+
+ public static void pii(String tag, String message) {
+ if (LOG_PERSONAL_INFORMATION) {
+ Logger.debug(tag, "$$PII$$: " + message);
+ }
+ }
+
+ public static synchronized void error(String tag, String message, Throwable error) {
+ Iterator<LogWriter> it = logWriters.iterator();
+ while (it.hasNext()) {
+ LogWriter writer = it.next();
+ try {
+ writer.error(tag, message, error);
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
+ it.remove();
+ }
+ }
+ }
+
+ public static synchronized void warn(String tag, String message, Throwable error) {
+ Iterator<LogWriter> it = logWriters.iterator();
+ while (it.hasNext()) {
+ LogWriter writer = it.next();
+ try {
+ writer.warn(tag, message, error);
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
+ it.remove();
+ }
+ }
+ }
+
+ public static synchronized void info(String tag, String message, Throwable error) {
+ Iterator<LogWriter> it = logWriters.iterator();
+ while (it.hasNext()) {
+ LogWriter writer = it.next();
+ try {
+ writer.info(tag, message, error);
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
+ it.remove();
+ }
+ }
+ }
+
+ public static synchronized void debug(String tag, String message, Throwable error) {
+ Iterator<LogWriter> it = logWriters.iterator();
+ while (it.hasNext()) {
+ LogWriter writer = it.next();
+ try {
+ writer.debug(tag, message, error);
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
+ it.remove();
+ }
+ }
+ }
+
+ public static synchronized void trace(String tag, String message, Throwable error) {
+ Iterator<LogWriter> it = logWriters.iterator();
+ while (it.hasNext()) {
+ LogWriter writer = it.next();
+ try {
+ writer.trace(tag, message, error);
+ } catch (Exception e) {
+ Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
+ it.remove();
+ }
+ }
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java
new file mode 100644
index 000000000..ac4250a03
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java
@@ -0,0 +1,132 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import android.util.Log;
+
+/**
+ * Make a <code>LogWriter</code> only log when the Android log system says to.
+ */
+public class AndroidLevelCachingLogWriter extends LogWriter {
+ protected final LogWriter inner;
+
+ public AndroidLevelCachingLogWriter(LogWriter inner) {
+ this.inner = inner;
+ }
+
+ // I can't believe we have to implement this ourselves.
+ // These aren't synchronized (and neither are the setters) because
+ // the logging calls themselves are synchronized.
+ private Map<String, Boolean> isErrorLoggable = new IdentityHashMap<String, Boolean>();
+ private Map<String, Boolean> isWarnLoggable = new IdentityHashMap<String, Boolean>();
+ private Map<String, Boolean> isInfoLoggable = new IdentityHashMap<String, Boolean>();
+ private Map<String, Boolean> isDebugLoggable = new IdentityHashMap<String, Boolean>();
+ private Map<String, Boolean> isVerboseLoggable = new IdentityHashMap<String, Boolean>();
+
+ /**
+ * Empty the caches of log levels.
+ */
+ public void refreshLogLevels() {
+ isErrorLoggable = new IdentityHashMap<String, Boolean>();
+ isWarnLoggable = new IdentityHashMap<String, Boolean>();
+ isInfoLoggable = new IdentityHashMap<String, Boolean>();
+ isDebugLoggable = new IdentityHashMap<String, Boolean>();
+ isVerboseLoggable = new IdentityHashMap<String, Boolean>();
+ }
+
+ private boolean shouldLogError(String logTag) {
+ Boolean out = isErrorLoggable.get(logTag);
+ if (out != null) {
+ return out;
+ }
+ out = Log.isLoggable(logTag, Log.ERROR);
+ isErrorLoggable.put(logTag, out);
+ return out;
+ }
+
+ private boolean shouldLogWarn(String logTag) {
+ Boolean out = isWarnLoggable.get(logTag);
+ if (out != null) {
+ return out;
+ }
+ out = Log.isLoggable(logTag, Log.WARN);
+ isWarnLoggable.put(logTag, out);
+ return out;
+ }
+
+ private boolean shouldLogInfo(String logTag) {
+ Boolean out = isInfoLoggable.get(logTag);
+ if (out != null) {
+ return out;
+ }
+ out = Log.isLoggable(logTag, Log.INFO);
+ isInfoLoggable.put(logTag, out);
+ return out;
+ }
+
+ private boolean shouldLogDebug(String logTag) {
+ Boolean out = isDebugLoggable.get(logTag);
+ if (out != null) {
+ return out;
+ }
+ out = Log.isLoggable(logTag, Log.DEBUG);
+ isDebugLoggable.put(logTag, out);
+ return out;
+ }
+
+ @Override
+ public boolean shouldLogVerbose(String logTag) {
+ Boolean out = isVerboseLoggable.get(logTag);
+ if (out != null) {
+ return out;
+ }
+ out = Log.isLoggable(logTag, Log.VERBOSE);
+ isVerboseLoggable.put(logTag, out);
+ return out;
+ }
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ if (shouldLogError(tag)) {
+ inner.error(tag, message, error);
+ }
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ if (shouldLogWarn(tag)) {
+ inner.warn(tag, message, error);
+ }
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ if (shouldLogInfo(tag)) {
+ inner.info(tag, message, error);
+ }
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ if (shouldLogDebug(tag)) {
+ inner.debug(tag, message, error);
+ }
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ if (shouldLogVerbose(tag)) {
+ inner.trace(tag, message, error);
+ }
+ }
+
+ @Override
+ public void close() {
+ inner.close();
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java
new file mode 100644
index 000000000..9d309844d
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+import android.util.Log;
+
+/**
+ * Log to the Android log.
+ */
+public class AndroidLogWriter extends LogWriter {
+ @Override
+ public boolean shouldLogVerbose(String logTag) {
+ return true;
+ }
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ Log.e(tag, message, error);
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ Log.w(tag, message, error);
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ Log.i(tag, message, error);
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ Log.d(tag, message, error);
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ Log.v(tag, message, error);
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java
new file mode 100644
index 000000000..74c3608c4
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+import android.util.Log;
+
+/**
+ * A LogWriter that logs only if the message is as important as the specified
+ * level. For example, if the specified level is <code>Log.WARN</code>, only
+ * <code>warn</code> and <code>error</code> will log.
+ */
+public class LevelFilteringLogWriter extends LogWriter {
+ protected final LogWriter inner;
+ protected final int logLevel;
+
+ public LevelFilteringLogWriter(int logLevel, LogWriter inner) {
+ this.inner = inner;
+ this.logLevel = logLevel;
+ }
+
+ @Override
+ public void close() {
+ inner.close();
+ }
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ if (logLevel <= Log.ERROR) {
+ inner.error(tag, message, error);
+ }
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ if (logLevel <= Log.WARN) {
+ inner.warn(tag, message, error);
+ }
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ if (logLevel <= Log.INFO) {
+ inner.info(tag, message, error);
+ }
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ if (logLevel <= Log.DEBUG) {
+ inner.debug(tag, message, error);
+ }
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ if (logLevel <= Log.VERBOSE) {
+ inner.trace(tag, message, error);
+ }
+ }
+
+ @Override
+ public boolean shouldLogVerbose(String tag) {
+ return logLevel <= Log.VERBOSE;
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java
new file mode 100644
index 000000000..acfb09969
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+/**
+ * An abstract object that logs information in some way.
+ * <p>
+ * Intended to be composed with other log writers, for example a log
+ * writer could make all log entries have the same single log tag, or
+ * could ignore certain log levels, before delegating to an inner log
+ * writer.
+ */
+public abstract class LogWriter {
+ public abstract void error(String tag, String message, Throwable error);
+ public abstract void warn(String tag, String message, Throwable error);
+ public abstract void info(String tag, String message, Throwable error);
+ public abstract void debug(String tag, String message, Throwable error);
+ public abstract void trace(String tag, String message, Throwable error);
+
+ /**
+ * We expect <code>close</code> to be called only by static
+ * synchronized methods in class <code>Logger</code>.
+ */
+ public abstract void close();
+
+ public abstract boolean shouldLogVerbose(String tag);
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java
new file mode 100644
index 000000000..6e1f63de3
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java
@@ -0,0 +1,77 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+import java.io.PrintWriter;
+
+/**
+ * Log to a <code>PrintWriter</code>.
+ */
+public class PrintLogWriter extends LogWriter {
+ protected final PrintWriter pw;
+ protected boolean closed = false;
+
+ public static final String ERROR = " :: E :: ";
+ public static final String WARN = " :: W :: ";
+ public static final String INFO = " :: I :: ";
+ public static final String DEBUG = " :: D :: ";
+ public static final String VERBOSE = " :: V :: ";
+
+ public PrintLogWriter(PrintWriter pw) {
+ this.pw = pw;
+ }
+
+ protected void log(String tag, String message, Throwable error) {
+ if (closed) {
+ return;
+ }
+
+ pw.println(tag + message);
+ if (error != null) {
+ error.printStackTrace(pw);
+ }
+ }
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ log(tag, ERROR + message, error);
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ log(tag, WARN + message, error);
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ log(tag, INFO + message, error);
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ log(tag, DEBUG + message, error);
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ log(tag, VERBOSE + message, error);
+ }
+
+ @Override
+ public boolean shouldLogVerbose(String tag) {
+ return true;
+ }
+
+ @Override
+ public void close() {
+ if (closed) {
+ return;
+ }
+ if (pw != null) {
+ pw.close();
+ }
+ closed = true;
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java
new file mode 100644
index 000000000..a17654371
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java
@@ -0,0 +1,21 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+/**
+ * Make a <code>LogWriter</code> only log with a single string tag.
+ */
+public class SimpleTagLogWriter extends TagLogWriter {
+ final String tag;
+ public SimpleTagLogWriter(String tag, LogWriter inner) {
+ super(inner);
+ this.tag = tag;
+ }
+
+ @Override
+ protected String getMainTag() {
+ return tag;
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java
new file mode 100644
index 000000000..d6a9f5eb8
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class StringLogWriter extends LogWriter {
+ protected final StringWriter sw;
+ protected final PrintLogWriter inner;
+
+ public StringLogWriter() {
+ sw = new StringWriter();
+ inner = new PrintLogWriter(new PrintWriter(sw));
+ }
+
+ public String toString() {
+ return sw.toString();
+ }
+
+ @Override
+ public boolean shouldLogVerbose(String tag) {
+ return true;
+ }
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ inner.error(tag, message, error);
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ inner.warn(tag, message, error);
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ inner.info(tag, message, error);
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ inner.debug(tag, message, error);
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ inner.trace(tag, message, error);
+ }
+
+ @Override
+ public void close() {
+ inner.close();
+ }
+}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java
new file mode 100644
index 000000000..fbcd94a91
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+/**
+ * A @link{LogWriter} that logs each message under a parent tag.
+ */
+public abstract class TagLogWriter extends LogWriter {
+
+ protected final LogWriter inner;
+
+ public TagLogWriter(final LogWriter inner) {
+ super();
+ this.inner = inner;
+ }
+
+ protected abstract String getMainTag();
+
+ @Override
+ public void error(String tag, String message, Throwable error) {
+ inner.error(this.getMainTag(), tag + " :: " + message, error);
+ }
+
+ @Override
+ public void warn(String tag, String message, Throwable error) {
+ inner.warn(this.getMainTag(), tag + " :: " + message, error);
+ }
+
+ @Override
+ public void info(String tag, String message, Throwable error) {
+ inner.info(this.getMainTag(), tag + " :: " + message, error);
+ }
+
+ @Override
+ public void debug(String tag, String message, Throwable error) {
+ inner.debug(this.getMainTag(), tag + " :: " + message, error);
+ }
+
+ @Override
+ public void trace(String tag, String message, Throwable error) {
+ inner.trace(this.getMainTag(), tag + " :: " + message, error);
+ }
+
+ @Override
+ public boolean shouldLogVerbose(String tag) {
+ return inner.shouldLogVerbose(this.getMainTag());
+ }
+
+ @Override
+ public void close() {
+ inner.close();
+ }
+} \ No newline at end of file
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java
new file mode 100644
index 000000000..0c83504a0
--- /dev/null
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java
@@ -0,0 +1,25 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.background.common.log.writers;
+
+/**
+ * Log with a single global tag… but that tag can be different for each thread.
+ *
+ * Takes a @link{ThreadLocal} as a constructor parameter.
+ */
+public class ThreadLocalTagLogWriter extends TagLogWriter {
+
+ private final ThreadLocal<String> tag;
+
+ public ThreadLocalTagLogWriter(ThreadLocal<String> tag, LogWriter inner) {
+ super(inner);
+ this.tag = tag;
+ }
+
+ @Override
+ protected String getMainTag() {
+ return this.tag.get();
+ }
+}