1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 package org.webrtc; 12 13 import android.support.annotation.Nullable; 14 import java.io.PrintWriter; 15 import java.io.StringWriter; 16 import java.util.EnumSet; 17 import java.util.logging.Level; 18 import java.util.logging.Logger; 19 import org.webrtc.Loggable; 20 21 /** 22 * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but a custom 23 * logger implementing the Loggable interface can be injected along with a Severity. All subsequent 24 * log messages will then be redirected to the injected Loggable, except those with a severity lower 25 * than the specified severity, which will be discarded. 26 * 27 * It is also possible to switch to native logging (rtc::LogMessage) if one of the following static 28 * functions are called from the app: 29 * - Logging.enableLogThreads 30 * - Logging.enableLogTimeStamps 31 * - Logging.enableLogToDebugOutput 32 * 33 * The priority goes: 34 * 1. Injected loggable 35 * 2. Native logging 36 * 3. Fallback logging. 37 * Only one method will be used at a time. 38 * 39 * Injecting a Loggable or using any of the enable... methods requires that the native library is 40 * loaded, using PeerConnectionFactory.initialize. 41 */ 42 public class Logging { 43 private static final Logger fallbackLogger = createFallbackLogger(); 44 private static volatile boolean loggingEnabled; 45 @Nullable private static Loggable loggable; 46 private static Severity loggableSeverity; 47 createFallbackLogger()48 private static Logger createFallbackLogger() { 49 final Logger fallbackLogger = Logger.getLogger("org.webrtc.Logging"); 50 fallbackLogger.setLevel(Level.ALL); 51 return fallbackLogger; 52 } 53 injectLoggable(Loggable injectedLoggable, Severity severity)54 static void injectLoggable(Loggable injectedLoggable, Severity severity) { 55 if (injectedLoggable != null) { 56 loggable = injectedLoggable; 57 loggableSeverity = severity; 58 } 59 } 60 deleteInjectedLoggable()61 static void deleteInjectedLoggable() { 62 loggable = null; 63 } 64 65 // TODO(solenberg): Remove once dependent projects updated. 66 @Deprecated 67 public enum TraceLevel { 68 TRACE_NONE(0x0000), 69 TRACE_STATEINFO(0x0001), 70 TRACE_WARNING(0x0002), 71 TRACE_ERROR(0x0004), 72 TRACE_CRITICAL(0x0008), 73 TRACE_APICALL(0x0010), 74 TRACE_DEFAULT(0x00ff), 75 TRACE_MODULECALL(0x0020), 76 TRACE_MEMORY(0x0100), 77 TRACE_TIMER(0x0200), 78 TRACE_STREAM(0x0400), 79 TRACE_DEBUG(0x0800), 80 TRACE_INFO(0x1000), 81 TRACE_TERSEINFO(0x2000), 82 TRACE_ALL(0xffff); 83 84 public final int level; TraceLevel(int level)85 TraceLevel(int level) { 86 this.level = level; 87 } 88 } 89 90 // Keep in sync with webrtc/rtc_base/logging.h:LoggingSeverity. 91 public enum Severity { LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, LS_NONE } 92 enableLogThreads()93 public static void enableLogThreads() { 94 nativeEnableLogThreads(); 95 } 96 enableLogTimeStamps()97 public static void enableLogTimeStamps() { 98 nativeEnableLogTimeStamps(); 99 } 100 101 // TODO(solenberg): Remove once dependent projects updated. 102 @Deprecated enableTracing(String path, EnumSet<TraceLevel> levels)103 public static void enableTracing(String path, EnumSet<TraceLevel> levels) {} 104 105 // Enable diagnostic logging for messages of |severity| to the platform debug 106 // output. On Android, the output will be directed to Logcat. 107 // Note: this function starts collecting the output of the RTC_LOG() macros. 108 // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. 109 @SuppressWarnings("NoSynchronizedMethodCheck") enableLogToDebugOutput(Severity severity)110 public static synchronized void enableLogToDebugOutput(Severity severity) { 111 if (loggable != null) { 112 throw new IllegalStateException( 113 "Logging to native debug output not supported while Loggable is injected. " 114 + "Delete the Loggable before calling this method."); 115 } 116 nativeEnableLogToDebugOutput(severity.ordinal()); 117 loggingEnabled = true; 118 } 119 log(Severity severity, String tag, String message)120 public static void log(Severity severity, String tag, String message) { 121 if (tag == null || message == null) { 122 throw new IllegalArgumentException("Logging tag or message may not be null."); 123 } 124 if (loggable != null) { 125 // Filter log messages below loggableSeverity. 126 if (severity.ordinal() < loggableSeverity.ordinal()) { 127 return; 128 } 129 loggable.onLogMessage(message, severity, tag); 130 return; 131 } 132 133 // Try native logging if no loggable is injected. 134 if (loggingEnabled) { 135 nativeLog(severity.ordinal(), tag, message); 136 return; 137 } 138 139 // Fallback to system log. 140 Level level; 141 switch (severity) { 142 case LS_ERROR: 143 level = Level.SEVERE; 144 break; 145 case LS_WARNING: 146 level = Level.WARNING; 147 break; 148 case LS_INFO: 149 level = Level.INFO; 150 break; 151 default: 152 level = Level.FINE; 153 break; 154 } 155 fallbackLogger.log(level, tag + ": " + message); 156 } 157 d(String tag, String message)158 public static void d(String tag, String message) { 159 log(Severity.LS_INFO, tag, message); 160 } 161 e(String tag, String message)162 public static void e(String tag, String message) { 163 log(Severity.LS_ERROR, tag, message); 164 } 165 w(String tag, String message)166 public static void w(String tag, String message) { 167 log(Severity.LS_WARNING, tag, message); 168 } 169 e(String tag, String message, Throwable e)170 public static void e(String tag, String message, Throwable e) { 171 log(Severity.LS_ERROR, tag, message); 172 log(Severity.LS_ERROR, tag, e.toString()); 173 log(Severity.LS_ERROR, tag, getStackTraceString(e)); 174 } 175 w(String tag, String message, Throwable e)176 public static void w(String tag, String message, Throwable e) { 177 log(Severity.LS_WARNING, tag, message); 178 log(Severity.LS_WARNING, tag, e.toString()); 179 log(Severity.LS_WARNING, tag, getStackTraceString(e)); 180 } 181 v(String tag, String message)182 public static void v(String tag, String message) { 183 log(Severity.LS_VERBOSE, tag, message); 184 } 185 getStackTraceString(Throwable e)186 private static String getStackTraceString(Throwable e) { 187 if (e == null) { 188 return ""; 189 } 190 191 StringWriter sw = new StringWriter(); 192 PrintWriter pw = new PrintWriter(sw); 193 e.printStackTrace(pw); 194 return sw.toString(); 195 } 196 nativeEnableLogToDebugOutput(int nativeSeverity)197 private static native void nativeEnableLogToDebugOutput(int nativeSeverity); nativeEnableLogThreads()198 private static native void nativeEnableLogThreads(); nativeEnableLogTimeStamps()199 private static native void nativeEnableLogTimeStamps(); nativeLog(int severity, String tag, String message)200 private static native void nativeLog(int severity, String tag, String message); 201 } 202