blob: fd070dfe6ccfa04d1167bfdbec246425061b5810 [file] [log] [blame]
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import androidx.annotation.Nullable;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.EnumSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.webrtc.Loggable;
/**
* Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but a custom
* logger implementing the Loggable interface can be injected along with a Severity. All subsequent
* log messages will then be redirected to the injected Loggable, except those with a severity lower
* than the specified severity, which will be discarded.
*
* It is also possible to switch to native logging (webrtc::LogMessage) if one
* of the following static functions are called from the app:
* - Logging.enableLogThreads
* - Logging.enableLogTimeStamps
* - Logging.enableLogToDebugOutput
*
* The priority goes:
* 1. Injected loggable
* 2. Native logging
* 3. Fallback logging.
* Only one method will be used at a time.
*
* Injecting a Loggable or using any of the enable... methods requires that the native library is
* loaded, using PeerConnectionFactory.initialize.
*/
public class Logging {
private static final Logger fallbackLogger = createFallbackLogger();
private static volatile boolean loggingEnabled;
@Nullable private static Loggable loggable;
private static Severity loggableSeverity;
private static Logger createFallbackLogger() {
final Logger fallbackLogger = Logger.getLogger("org.webrtc.Logging");
fallbackLogger.setLevel(Level.ALL);
return fallbackLogger;
}
static void injectLoggable(Loggable injectedLoggable, Severity severity) {
if (injectedLoggable != null) {
loggable = injectedLoggable;
loggableSeverity = severity;
}
}
static void deleteInjectedLoggable() {
loggable = null;
}
// Keep in sync with webrtc/rtc_base/logging.h:LoggingSeverity.
public enum Severity { LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE }
public static void enableLogThreads() {
nativeEnableLogThreads();
}
public static void enableLogTimeStamps() {
nativeEnableLogTimeStamps();
}
// Enable diagnostic logging for messages of `severity` to the platform debug
// output. On Android, the output will be directed to Logcat.
// Note: this function starts collecting the output of the RTC_LOG() macros.
// TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
@SuppressWarnings({"EnumOrdinal", "NoSynchronizedMethodCheck"})
public static synchronized void enableLogToDebugOutput(Severity severity) {
if (loggable != null) {
throw new IllegalStateException(
"Logging to native debug output not supported while Loggable is injected. "
+ "Delete the Loggable before calling this method.");
}
nativeEnableLogToDebugOutput(severity.ordinal());
loggingEnabled = true;
}
@SuppressWarnings("EnumOrdinal")
public static void log(Severity severity, String tag, String message) {
if (tag == null || message == null) {
throw new IllegalArgumentException("Logging tag or message may not be null.");
}
if (loggable != null) {
// Filter log messages below loggableSeverity.
if (severity.ordinal() < loggableSeverity.ordinal()) {
return;
}
loggable.onLogMessage(message, severity, tag);
return;
}
// Try native logging if no loggable is injected.
if (loggingEnabled) {
nativeLog(severity.ordinal(), tag, message);
return;
}
// Fallback to system log.
Level level;
switch (severity) {
case LS_ERROR:
level = Level.SEVERE;
break;
case LS_WARNING:
level = Level.WARNING;
break;
case LS_INFO:
level = Level.INFO;
break;
default:
level = Level.FINE;
break;
}
fallbackLogger.log(level, tag + ": " + message);
}
public static void d(String tag, String message) {
log(Severity.LS_INFO, tag, message);
}
public static void e(String tag, String message) {
log(Severity.LS_ERROR, tag, message);
}
public static void w(String tag, String message) {
log(Severity.LS_WARNING, tag, message);
}
public static void e(String tag, String message, Throwable e) {
log(Severity.LS_ERROR, tag, message);
log(Severity.LS_ERROR, tag, e.toString());
log(Severity.LS_ERROR, tag, getStackTraceString(e));
}
public static void w(String tag, String message, Throwable e) {
log(Severity.LS_WARNING, tag, message);
log(Severity.LS_WARNING, tag, e.toString());
log(Severity.LS_WARNING, tag, getStackTraceString(e));
}
public static void v(String tag, String message) {
log(Severity.LS_VERBOSE, tag, message);
}
private static String getStackTraceString(Throwable e) {
if (e == null) {
return "";
}
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
private static native void nativeEnableLogToDebugOutput(int nativeSeverity);
private static native void nativeEnableLogThreads();
private static native void nativeEnableLogTimeStamps();
private static native void nativeLog(int severity, String tag, String message);
}