Repository: firebase/firebase-admin-java
Pull request #53 (2017-07-06 21:45:47)

SLF4J Integration
We wish to use [SLF4J](https://www.slf4j.org/) as the logging interface in the Admin SDK. 

* Replaced the `Log` class in the internal package with calls to SLF4J
* Deprecated the logging interfaces in the database package. These will be removed in a future release.
* Modified `LogWrapper` to log to SLF4J when available, and log to the old interface when not. This is a temporary solution to avoid the breaking change. When we remove the deprecated logging stuff in the future, we can get rid of this as well.


Patch:
diff --git a/pom.xml b/pom.xml
index 5ec30e7..20133de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -329,6 +329,11 @@
             <artifactId>guava</artifactId>
             <version>20.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.25</version>
+        </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
diff --git a/src/main/java/com/google/firebase/FirebaseApp.java b/src/main/java/com/google/firebase/FirebaseApp.java
index c316819..38f2c3d 100644
--- a/src/main/java/com/google/firebase/FirebaseApp.java
+++ b/src/main/java/com/google/firebase/FirebaseApp.java
@@ -33,7 +33,6 @@ import com.google.firebase.internal.FirebaseAppStore;
 import com.google.firebase.internal.FirebaseExecutors;
 import com.google.firebase.internal.FirebaseService;
 import com.google.firebase.internal.GetTokenResult;
-import com.google.firebase.internal.Log;
 import com.google.firebase.internal.NonNull;
 import com.google.firebase.internal.Nullable;
 import com.google.firebase.tasks.Continuation;
@@ -51,6 +50,8 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The entry point of Firebase SDKs. It holds common configuration and state for Firebase APIs. Most
@@ -64,6 +65,8 @@ import java.util.concurrent.atomic.AtomicReference;
  */
 public class FirebaseApp {
 
+  private static final Logger logger = LoggerFactory.getLogger(FirebaseApp.class);
+
   /** A map of (name, FirebaseApp) instances. */
   private static final Map<String, FirebaseApp> instances = new HashMap<>();
 
@@ -360,9 +363,8 @@ public class FirebaseApp {
                     if (refreshDelay > 0) {
                       tokenRefresher.scheduleRefresh(refreshDelay);
                     } else {
-                      Log.w("FirebaseApp", "Token expiry ("
-                          + googleOAuthToken.getExpiryTime() + ") is less than 5 minutes in the "
-                          + "future. Not scheduling a proactive refresh.");
+                      logger.warn("Token expiry ({}) is less than 5 minutes in the future. Not "
+                          + "scheduling a proactive refresh.", googleOAuthToken.getAccessToken());
                     }
                   }
                 }
diff --git a/src/main/java/com/google/firebase/database/FirebaseDatabase.java b/src/main/java/com/google/firebase/database/FirebaseDatabase.java
index 388175a..25f0349 100644
--- a/src/main/java/com/google/firebase/database/FirebaseDatabase.java
+++ b/src/main/java/com/google/firebase/database/FirebaseDatabase.java
@@ -263,6 +263,9 @@ public class FirebaseDatabase {
    * diagnostic logging, and {@link Logger.Level#NONE NONE} to disable all logging.
    *
    * @param logLevel The desired minimum log level
+   * @deprecated This method will be removed in a future release. Use SLF4J-based logging instead.
+   *     For example, add the slf4j-simple.jar to the classpath to log to STDERR. See
+   *     <a href="https://www.slf4j.org/manual.html">SLF4J user manual</a> for more details.
    */
   public synchronized void setLogLevel(Logger.Level logLevel) {
     synchronized (lock) {
diff --git a/src/main/java/com/google/firebase/database/Logger.java b/src/main/java/com/google/firebase/database/Logger.java
index 19353bf..aa56ed8 100644
--- a/src/main/java/com/google/firebase/database/Logger.java
+++ b/src/main/java/com/google/firebase/database/Logger.java
@@ -16,10 +16,18 @@
 
 package com.google.firebase.database;
 
-/** This interface is used to setup logging for Firebase Database. */
+/**
+ * This interface is used to setup logging for Firebase Database.
+ *
+ * @deprecated Use SLF4J-based logging
+ */
 public interface Logger {
 
-  /** The log levels used by the Firebase Database library */
+  /**
+   * The log levels used by the Firebase Database library
+   *
+   * @deprecated Use SLF4J-based logging
+   */
   enum Level {
     DEBUG,
     INFO,
diff --git a/src/main/java/com/google/firebase/database/connection/Connection.java b/src/main/java/com/google/firebase/database/connection/Connection.java
index 9eac0be..a64a162 100644
--- a/src/main/java/com/google/firebase/database/connection/Connection.java
+++ b/src/main/java/com/google/firebase/database/connection/Connection.java
@@ -54,7 +54,7 @@ class Connection implements WebsocketConnection.Delegate {
     long connId = connectionIds++;
     this.hostInfo = hostInfo;
     this.delegate = delegate;
-    this.logger = new LogWrapper(context.getLogger(), "Connection", "conn_" + connId);
+    this.logger = new LogWrapper(context.getLogger(), Connection.class, "conn_" + connId);
     this.state = State.REALTIME_CONNECTING;
     this.conn = new WebsocketConnection(context, hostInfo, cachedHost, this, optLastSessionId);
   }
diff --git a/src/main/java/com/google/firebase/database/connection/PersistentConnectionImpl.java b/src/main/java/com/google/firebase/database/connection/PersistentConnectionImpl.java
index 374dcaa..ce887a6 100644
--- a/src/main/java/com/google/firebase/database/connection/PersistentConnectionImpl.java
+++ b/src/main/java/com/google/firebase/database/connection/PersistentConnectionImpl.java
@@ -135,7 +135,7 @@ public class PersistentConnectionImpl implements Connection.Delegate, Persistent
     this.outstandingPuts = new HashMap<>();
     this.onDisconnectRequestQueue = new ArrayList<>();
     this.retryHelper =
-        new RetryHelper.Builder(this.executorService, context.getLogger(), "ConnectionRetryHelper")
+        new RetryHelper.Builder(this.executorService, context.getLogger(), RetryHelper.class)
             .withMinDelayAfterFailure(1000)
             .withRetryExponent(1.3)
             .withMaxDelay(30 * 1000)
@@ -143,7 +143,7 @@ public class PersistentConnectionImpl implements Connection.Delegate, Persistent
             .build();
 
     long connId = connectionIds++;
-    this.logger = new LogWrapper(context.getLogger(), "PersistentConnection", "pc_" + connId);
+    this.logger = new LogWrapper(context.getLogger(), PersistentConnection.class, "pc_" + connId);
     this.lastSessionId = null;
     doIdleCheck();
   }
diff --git a/src/main/java/com/google/firebase/database/connection/WebsocketConnection.java b/src/main/java/com/google/firebase/database/connection/WebsocketConnection.java
index 1fb164f..12afdfd 100644
--- a/src/main/java/com/google/firebase/database/connection/WebsocketConnection.java
+++ b/src/main/java/com/google/firebase/database/connection/WebsocketConnection.java
@@ -62,7 +62,8 @@ class WebsocketConnection {
     this.executorService = connectionContext.getExecutorService();
     this.delegate = delegate;
     long connId = connectionId++;
-    logger = new LogWrapper(connectionContext.getLogger(), "WebSocket", "ws_" + connId);
+    logger = new LogWrapper(connectionContext.getLogger(), WebsocketConnection.class,
+        "ws_" + connId);
     conn = createConnection(hostInfo, optCachedHost, optLastSessionId);
   }
 
diff --git a/src/main/java/com/google/firebase/database/connection/util/RetryHelper.java b/src/main/java/com/google/firebase/database/connection/util/RetryHelper.java
index f8054fc..2563a30 100644
--- a/src/main/java/com/google/firebase/database/connection/util/RetryHelper.java
+++ b/src/main/java/com/google/firebase/database/connection/util/RetryHelper.java
@@ -125,7 +125,7 @@ public class RetryHelper {
     private long retryMaxDelay = 30 * 1000;
     private double retryExponent = 1.3;
 
-    public Builder(ScheduledExecutorService service, Logger logger, String tag) {
+    public Builder(ScheduledExecutorService service, Logger logger, Class tag) {
       this.service = service;
       this.logger = new LogWrapper(logger, tag);
     }
diff --git a/src/main/java/com/google/firebase/database/core/Context.java b/src/main/java/com/google/firebase/database/core/Context.java
index 34c5ce9..d691fac 100644
--- a/src/main/java/com/google/firebase/database/core/Context.java
+++ b/src/main/java/com/google/firebase/database/core/Context.java
@@ -141,29 +141,21 @@ public class Context {
     }
   }
 
-  public List<String> getOptDebugLogComponents() {
-    return this.loggedComponents;
-  }
-
-  public Logger.Level getLogLevel() {
-    return this.logLevel;
-  }
-
-  public Logger getLogger() {
-    return this.logger;
+  public LogWrapper getLogger(String component) {
+    return new LogWrapper(logger, component, null);
   }
 
-  public LogWrapper getLogger(String component) {
+  public LogWrapper getLogger(Class component) {
     return new LogWrapper(logger, component);
   }
 
-  public LogWrapper getLogger(String component, String prefix) {
+  public LogWrapper getLogger(Class component, String prefix) {
     return new LogWrapper(logger, component, prefix);
   }
 
   public ConnectionContext getConnectionContext() {
     return new ConnectionContext(
-        this.getLogger(),
+        this.logger,
         wrapAuthTokenProvider(this.getAuthTokenProvider()),
         this.getExecutorService(),
         this.isPersistenceEnabled(),
diff --git a/src/main/java/com/google/firebase/database/core/GaePlatform.java b/src/main/java/com/google/firebase/database/core/GaePlatform.java
index 5ab3d78..4438f54 100644
--- a/src/main/java/com/google/firebase/database/core/GaePlatform.java
+++ b/src/main/java/com/google/firebase/database/core/GaePlatform.java
@@ -89,7 +89,7 @@ class GaePlatform implements Platform {
 
   @Override
   public RunLoop newRunLoop(final Context context) {
-    final LogWrapper logger = context.getLogger("RunLoop");
+    final LogWrapper logger = context.getLogger(RunLoop.class);
     return new DefaultRunLoop(getGaeThreadFactory(), /* periodicRestart= */ true, context) {
       @Override
       public void handleException(Throwable e) {
diff --git a/src/main/java/com/google/firebase/database/core/JvmPlatform.java b/src/main/java/com/google/firebase/database/core/JvmPlatform.java
index 17f0826..f6985fd 100644
--- a/src/main/java/com/google/firebase/database/core/JvmPlatform.java
+++ b/src/main/java/com/google/firebase/database/core/JvmPlatform.java
@@ -55,7 +55,7 @@ class JvmPlatform implements Platform {
 
   @Override
   public RunLoop newRunLoop(final Context context) {
-    final LogWrapper logger = context.getLogger("RunLoop");
+    final LogWrapper logger = context.getLogger(RunLoop.class);
     return new DefaultRunLoop() {
       @Override
       public void handleException(Throwable e) {
diff --git a/src/main/java/com/google/firebase/database/core/Repo.java b/src/main/java/com/google/firebase/database/core/Repo.java
index 9f7d3da..8c4e2e2 100644
--- a/src/main/java/com/google/firebase/database/core/Repo.java
+++ b/src/main/java/com/google/firebase/database/core/Repo.java
@@ -92,9 +92,9 @@ public class Repo implements PersistentConnection.Delegate {
     this.ctx = ctx;
     this.database = database;
 
-    operationLogger = this.ctx.getLogger("RepoOperation");
-    transactionLogger = this.ctx.getLogger("Transaction");
-    dataLogger = this.ctx.getLogger("DataOperation");
+    operationLogger = this.ctx.getLogger(Repo.class);
+    transactionLogger = this.ctx.getLogger(Repo.class.getName() + ".Transaction");
+    dataLogger = this.ctx.getLogger(Repo.class.getName() + ".DataOperation");
 
     this.eventRaiser = new EventRaiser(this.ctx);
 
diff --git a/src/main/java/com/google/firebase/database/core/SyncTree.java b/src/main/java/com/google/firebase/database/core/SyncTree.java
index 7c2c894..17fcad4 100644
--- a/src/main/java/com/google/firebase/database/core/SyncTree.java
+++ b/src/main/java/com/google/firebase/database/core/SyncTree.java
@@ -105,7 +105,7 @@ public class SyncTree {
     this.keepSyncedQueries = new HashSet<>();
     this.listenProvider = listenProvider;
     this.persistenceManager = persistenceManager;
-    this.logger = context.getLogger("SyncTree");
+    this.logger = context.getLogger(SyncTree.class);
   }
 
   public boolean isEmpty() {
diff --git a/src/main/java/com/google/firebase/database/core/persistence/DefaultPersistenceManager.java b/src/main/java/com/google/firebase/database/core/persistence/DefaultPersistenceManager.java
index 744b250..1bc5462 100644
--- a/src/main/java/com/google/firebase/database/core/persistence/DefaultPersistenceManager.java
+++ b/src/main/java/com/google/firebase/database/core/persistence/DefaultPersistenceManager.java
@@ -51,7 +51,7 @@ public class DefaultPersistenceManager implements PersistenceManager {
   public DefaultPersistenceManager(
       Context ctx, PersistenceStorageEngine engine, CachePolicy cachePolicy, Clock clock) {
     this.storageLayer = engine;
-    this.logger = ctx.getLogger("Persistence");
+    this.logger = ctx.getLogger(PersistenceManager.class);
     this.trackedQueryManager = new TrackedQueryManager(storageLayer, logger, clock);
     this.cachePolicy = cachePolicy;
   }
diff --git a/src/main/java/com/google/firebase/database/core/view/EventRaiser.java b/src/main/java/com/google/firebase/database/core/view/EventRaiser.java
index 3f7361a..47579ab 100644
--- a/src/main/java/com/google/firebase/database/core/view/EventRaiser.java
+++ b/src/main/java/com/google/firebase/database/core/view/EventRaiser.java
@@ -38,7 +38,7 @@ public class EventRaiser {
 
   public EventRaiser(Context ctx) {
     eventTarget = ctx.getEventTarget();
-    logger = ctx.getLogger("EventRaiser");
+    logger = ctx.getLogger(EventRaiser.class);
   }
 
   public void raiseEvents(final List<? extends Event> events) {
diff --git a/src/main/java/com/google/firebase/database/logging/LogWrapper.java b/src/main/java/com/google/firebase/database/logging/LogWrapper.java
index a64fc20..21e28e5 100644
--- a/src/main/java/com/google/firebase/database/logging/LogWrapper.java
+++ b/src/main/java/com/google/firebase/database/logging/LogWrapper.java
@@ -18,19 +18,37 @@ package com.google.firebase.database.logging;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import org.slf4j.LoggerFactory;
 
-/** User: greg Date: 6/12/13 Time: 2:23 PM */
+/**
+ * Legacy logging interface for database implementation. This class attempts to reconcile SLF4J
+ * with the old logging implementation of the Admin SDK. When SLF4J is available, logs using that
+ * API. Otherwise falls back to the old logging implementation. This prevents individual log
+ * statements from being written to both log APIs.
+ *
+ * @deprecated This class will be removed in a future release, and SLF4J will be used universally
+ *     throughout the codebase.
+ */
 public class LogWrapper {
 
+  private final org.slf4j.Logger slf4jLogger;
   private final Logger logger;
   private final String component;
   private final String prefix;
 
-  public LogWrapper(Logger logger, String component) {
+  public LogWrapper(Logger logger, Class component) {
     this(logger, component, null);
   }
 
+  public LogWrapper(Logger logger, Class component, String prefix) {
+    this.slf4jLogger = LoggerFactory.getLogger(component);
+    this.logger = logger;
+    this.component = component.getName();
+    this.prefix = prefix;
+  }
+
   public LogWrapper(Logger logger, String component, String prefix) {
+    this.slf4jLogger = LoggerFactory.getLogger(component);
     this.logger = logger;
     this.component = component;
     this.prefix = prefix;
@@ -44,8 +62,12 @@ public class LogWrapper {
   }
 
   public void error(String message, Throwable e) {
-    String logMsg = toLog(message) + "\n" + exceptionStacktrace(e);
-    logger.onLogMessage(Logger.Level.ERROR, component, logMsg, now());
+    if (slf4jLogger.isErrorEnabled()) {
+      slf4jLogger.error(toLog(message), e);
+    } else {
+      String logMsg = toLog(message) + "\n" + exceptionStacktrace(e);
+      logger.onLogMessage(Logger.Level.ERROR, component, logMsg, now());
+    }
   }
 
   public void warn(String message) {
@@ -53,15 +75,23 @@ public class LogWrapper {
   }
 
   public void warn(String message, Throwable e) {
-    String logMsg = toLog(message);
-    if (e != null) {
-      logMsg = logMsg + "\n" + exceptionStacktrace(e);
+    if (slf4jLogger.isWarnEnabled()) {
+      slf4jLogger.warn(toLog(message), e);
+    } else {
+      String logMsg = toLog(message);
+      if (e != null) {
+        logMsg = logMsg + "\n" + exceptionStacktrace(e);
+      }
+      logger.onLogMessage(Logger.Level.WARN, component, logMsg, now());
     }
-    logger.onLogMessage(Logger.Level.WARN, component, logMsg, now());
   }
 
   public void info(String message) {
-    logger.onLogMessage(Logger.Level.INFO, component, toLog(message), now());
+    if (slf4jLogger.isInfoEnabled()) {
+      slf4jLogger.info(toLog(message));
+    } else {
+      logger.onLogMessage(Logger.Level.INFO, component, toLog(message), now());
+    }
   }
 
   public void debug(String message, Object... args) {
@@ -70,7 +100,9 @@ public class LogWrapper {
 
   /** Log a non-fatal exception. Typically something like an IO error on a failed connection */
   public void debug(String message, Throwable e, Object... args) {
-    if (this.logsDebug()) {
+    if (slf4jLogger.isDebugEnabled()) {
+      slf4jLogger.debug(toLog(message, args), e);
+    } else {
       String logMsg = toLog(message, args);
       if (e != null) {
         logMsg = logMsg + "\n" + exceptionStacktrace(e);
@@ -80,7 +112,8 @@ public class LogWrapper {
   }
 
   public boolean logsDebug() {
-    return this.logger.getLogLevel().ordinal() <= Logger.Level.DEBUG.ordinal();
+    return this.logger.getLogLevel().ordinal() <= Logger.Level.DEBUG.ordinal()
+        || slf4jLogger.isDebugEnabled();
   }
 
   private long now() {
diff --git a/src/main/java/com/google/firebase/database/logging/Logger.java b/src/main/java/com/google/firebase/database/logging/Logger.java
index f187299..7fd2e6e 100644
--- a/src/main/java/com/google/firebase/database/logging/Logger.java
+++ b/src/main/java/com/google/firebase/database/logging/Logger.java
@@ -19,6 +19,8 @@ package com.google.firebase.database.logging;
 /**
  * Private (internal) logging interface used by Firebase Database. See {@link
  * com.google.firebase.database.core.DatabaseConfig DatabaseConfig} for more information.
+ *
+ * @deprecated Use SLF4J-based logging
  */
 public interface Logger {
 
diff --git a/src/main/java/com/google/firebase/database/utilities/encoding/CustomClassMapper.java b/src/main/java/com/google/firebase/database/utilities/encoding/CustomClassMapper.java
index 156d99f..28542c1 100644
--- a/src/main/java/com/google/firebase/database/utilities/encoding/CustomClassMapper.java
+++ b/src/main/java/com/google/firebase/database/utilities/encoding/CustomClassMapper.java
@@ -24,7 +24,6 @@ import com.google.firebase.database.GenericTypeIndicator;
 import com.google.firebase.database.IgnoreExtraProperties;
 import com.google.firebase.database.PropertyName;
 import com.google.firebase.database.ThrowOnExtraProperties;
-import com.google.firebase.internal.Log;
 
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
@@ -45,11 +44,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /** Helper class to convert to/from custom POJO classes and plain Java types. */
 public class CustomClassMapper {
 
-  private static final String LOG_TAG = "ClassMapper";
+  private static final Logger logger = LoggerFactory.getLogger(CustomClassMapper.class);
 
   private static final ConcurrentMap<Class<?>, BeanMapper<?>> mappers = new ConcurrentHashMap<>();
 
@@ -740,8 +741,7 @@ public class CustomClassMapper {
           if (this.throwOnUnknownProperties) {
             throw new DatabaseException(message);
           } else if (this.warnOnUnknownProperties) {
-            // TODO: replace Android logging with "our" logging
-            Log.w(LOG_TAG, message);
+            logger.warn(message);
           }
         }
       }
diff --git a/src/main/java/com/google/firebase/internal/GaeThreadFactory.java b/src/main/java/com/google/firebase/internal/GaeThreadFactory.java
index d154eea..6150c37 100644
--- a/src/main/java/com/google/firebase/internal/GaeThreadFactory.java
+++ b/src/main/java/com/google/firebase/internal/GaeThreadFactory.java
@@ -22,6 +22,8 @@ import java.lang.reflect.InvocationTargetException;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * GaeThreadFactory is a thread factory that works on App Engine. It uses background threads on
@@ -31,9 +33,10 @@ import java.util.concurrent.atomic.AtomicReference;
  */
 public class GaeThreadFactory implements ThreadFactory {
 
+  private static final Logger logger = LoggerFactory.getLogger(GaeThreadFactory.class);
+
   public static final ScheduledExecutorService DEFAULT_EXECUTOR =
       new GaeScheduledExecutorService("FirebaseDefault");
-  private static final String TAG = "GaeThreadFactory";
   private static final String GAE_THREAD_MANAGER_CLASS = "com.google.appengine.api.ThreadManager";
   private static final GaeThreadFactory instance = new GaeThreadFactory();
   private final AtomicReference<ThreadFactoryWrapper> threadFactory = new AtomicReference<>(null);
@@ -115,10 +118,8 @@ public class GaeThreadFactory implements ThreadFactory {
         thread = threadFactory.newThread(r);
         usesBackgroundThreads = true;
       } catch (IllegalStateException e) {
-        Log.w(
-            TAG,
-            "Falling back to GAE's request-scoped threads. Firebase requires "
-                + "manually-scaled instances for most operations.");
+        logger.warn("Falling back to GAE's request-scoped threads. Firebase requires "
+            + "manually-scaled instances for most operations.");
         threadFactory = createRequestScopedFactory();
         thread = threadFactory.newThread(r);
       }
@@ -130,10 +131,8 @@ public class GaeThreadFactory implements ThreadFactory {
           new ThreadFactory() {
             @Override
             public Thread newThread(Runnable r) {
-              Log.w(
-                  TAG,
-                  "Failed to initialize native GAE thread factory. "
-                      + "GaeThreadFactory cannot be used in a non-GAE environment.");
+              logger.warn("Failed to initialize native GAE thread factory. "
+                  + "GaeThreadFactory cannot be used in a non-GAE environment.");
               return null;
             }
           };
diff --git a/src/main/java/com/google/firebase/internal/Log.java b/src/main/java/com/google/firebase/internal/Log.java
deleted file mode 100644
index 90cbe93..0000000
--- a/src/main/java/com/google/firebase/internal/Log.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * 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.firebase.internal;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/** Provides a logging interface for Firebase implementations. */
-// TODO: Remove this or replace logging internally.
-public final class Log {
-
-  private static final String PARENT_LOGGER_NAME = "com.google.firebase";
-  private static final String LOG_PREFIX = PARENT_LOGGER_NAME + ".";
-  private static final Logger PARENT_LOGGER = Logger.getLogger(PARENT_LOGGER_NAME);
-  private static final Level WTF_LEVEL = new Level("WTF", 1100) {};
-
-  private Log() {}
-
-  /**
-   * Logs a message. Log levels correspond as follows:
-   *
-   * <ul>
-   *   <li>WTF -> Level.SEVERE
-   *   <li>ERROR -> Level.SEVERE
-   *   <li>WARN -> Level.WARNING
-   *   <li>INFO -> Level.INFO
-   *   <li>DEBUG -> Level.FINE
-   *   <li>VERBOSE -> Level.FINER
-   * </ul>
-   */
-  private static void log(Level level, String tag, String msg, Throwable thrown) {
-    Logger.getLogger(LOG_PREFIX + tag).log(level, msg, thrown);
-  }
-
-  // CSOFF: MethodName
-  public static void d(String tag, String msg) {
-    log(Level.FINE, tag, msg, null);
-  }
-
-  public static void i(String tag, String msg) {
-    log(Level.INFO, tag, msg, null);
-  }
-
-  public static void w(String tag, String msg) {
-    log(Level.WARNING, tag, msg, null);
-  }
-  // CSON: MethodName
-
-  public static void wtf(String tag, String msg, Throwable thrown) {
-    log(WTF_LEVEL, tag, msg, thrown);
-  }
-}
diff --git a/src/main/java/com/google/firebase/internal/RevivingScheduledExecutor.java b/src/main/java/com/google/firebase/internal/RevivingScheduledExecutor.java
index 833fa9a..a381367 100644
--- a/src/main/java/com/google/firebase/internal/RevivingScheduledExecutor.java
+++ b/src/main/java/com/google/firebase/internal/RevivingScheduledExecutor.java
@@ -29,6 +29,8 @@ import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * RevivingScheduledExecutor is an implementation of ScheduledThreadPoolExecutor that uses one
@@ -37,7 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger;
  */
 public class RevivingScheduledExecutor extends ScheduledThreadPoolExecutor {
 
-  private static final String TAG = "RevivingScheduledExecutor";
+  private static final Logger logger = LoggerFactory.getLogger(RevivingScheduledExecutor.class);
 
   /** Exception to throw to shut down the core threads. */
   private static final RuntimeException REVIVE_THREAD_EXCEPTION =
@@ -92,7 +94,7 @@ public class RevivingScheduledExecutor extends ScheduledThreadPoolExecutor {
         new ThreadFactory() {
           @Override
           public Thread newThread(Runnable r) {
-            Log.d(TAG, "Creating new thread for: " + threadName);
+            logger.debug("Creating new thread for: {}", threadName);
             Thread thread = threadFactory.newThread(r);
             try {
               thread.setName(threadName);


Test patch:
diff --git a/src/test/java/com/google/firebase/database/core/persistence/TrackedQueryManagerTest.java b/src/test/java/com/google/firebase/database/core/persistence/TrackedQueryManagerTest.java
index e7feafa..66b5a51 100644
--- a/src/test/java/com/google/firebase/database/core/persistence/TrackedQueryManagerTest.java
+++ b/src/test/java/com/google/firebase/database/core/persistence/TrackedQueryManagerTest.java
@@ -67,7 +67,7 @@ public class TrackedQueryManagerTest {
       engine = e;
     }
     LogWrapper logWrapper =
-        new LogWrapper(new DefaultLogger(Logger.Level.WARN, null), "TrackedQueryManagerTest");
+        new LogWrapper(new DefaultLogger(Logger.Level.WARN, null), TrackedQueryManagerTest.class);
     return new TrackedQueryManager(engine, logWrapper, clock);
   }