1
1
package app .revanced .extension .shared ;
2
2
3
+ import static app .revanced .extension .shared .settings .BaseSettings .DEBUG ;
4
+ import static app .revanced .extension .shared .settings .BaseSettings .DEBUG_STACKTRACE ;
5
+ import static app .revanced .extension .shared .settings .BaseSettings .DEBUG_TOAST_ON_ERROR ;
6
+
3
7
import android .util .Log ;
8
+
4
9
import androidx .annotation .NonNull ;
5
10
import androidx .annotation .Nullable ;
6
- import app .revanced .extension .shared .settings .BaseSettings ;
7
11
8
12
import java .io .PrintWriter ;
9
13
import java .io .StringWriter ;
10
14
11
- import static app .revanced .extension .shared .settings .BaseSettings .*;
12
-
15
+ import app .revanced .extension .shared .settings .BaseSettings ;
16
+ import app .revanced .extension .shared .settings .preference .LogBufferManager ;
17
+
18
+ /**
19
+ * ReVanced specific logger. Logging is done to standard device log (accessible thru ADB),
20
+ * and additionally accessible thru {@link LogBufferManager}.
21
+ *
22
+ * All methods are thread safe.
23
+ */
13
24
public class Logger {
14
25
15
26
/**
16
27
* Log messages using lambdas.
17
28
*/
18
29
@ FunctionalInterface
19
30
public interface LogMessage {
31
+ /**
32
+ * @return Logger string message. This method is only called if logging is enabled.
33
+ */
20
34
@ NonNull
21
35
String buildMessageString ();
36
+ }
22
37
23
- /**
24
- * @return For outer classes, this returns {@link Class#getSimpleName()}.
25
- * For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
26
- * <br>
27
- * For example, each of these classes return 'SomethingView':
28
- * <code>
29
- * com.company.SomethingView
30
- * com.company.SomethingView$StaticClass
31
- * com.company.SomethingView$1
32
- * </code>
33
- */
34
- private String findOuterClassSimpleName () {
35
- var selfClass = this .getClass ();
38
+ private enum LogLevel {
39
+ DEBUG ,
40
+ INFO ,
41
+ ERROR
42
+ }
36
43
37
- String fullClassName = selfClass .getName ();
38
- final int dollarSignIndex = fullClassName .indexOf ('$' );
39
- if (dollarSignIndex < 0 ) {
40
- return selfClass .getSimpleName (); // Already an outer class.
41
- }
44
+ private static final String REVANCED_LOG_TAG = "revanced" ;
45
+
46
+ private static final String LOGGER_CLASS_NAME = Logger .class .getName ();
42
47
43
- // Class is inner, static, or anonymous.
44
- // Parse the simple name full name.
45
- // A class with no package returns index of -1, but incrementing gives index zero which is correct.
46
- final int simpleClassNameStartIndex = fullClassName .lastIndexOf ('.' ) + 1 ;
47
- return fullClassName .substring (simpleClassNameStartIndex , dollarSignIndex );
48
+ /**
49
+ * @return For outer classes, this returns {@link Class#getSimpleName()}.
50
+ * For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
51
+ * <br>
52
+ * For example, each of these classes returns 'SomethingView':
53
+ * <code>
54
+ * com.company.SomethingView
55
+ * com.company.SomethingView$StaticClass
56
+ * com.company.SomethingView$1
57
+ * </code>
58
+ */
59
+ private static String getOuterClassSimpleName (Object obj ) {
60
+ Class <?> logClass = obj .getClass ();
61
+ String fullClassName = logClass .getName ();
62
+ final int dollarSignIndex = fullClassName .indexOf ('$' );
63
+ if (dollarSignIndex < 0 ) {
64
+ return logClass .getSimpleName (); // Already an outer class.
48
65
}
66
+
67
+ // Class is inner, static, or anonymous.
68
+ // Parse the simple name full name.
69
+ // A class with no package returns index of -1, but incrementing gives index zero which is correct.
70
+ final int simpleClassNameStartIndex = fullClassName .lastIndexOf ('.' ) + 1 ;
71
+ return fullClassName .substring (simpleClassNameStartIndex , dollarSignIndex );
49
72
}
50
73
51
- private static final String REVANCED_LOG_PREFIX = "revanced: " ;
74
+ /**
75
+ * Internal method to handle logging to Android Log and {@link LogBufferManager}.
76
+ * Appends the log message, stack trace (if enabled), and exception (if present) to logBuffer
77
+ * with class name but without 'revanced:' prefix.
78
+ *
79
+ * @param logLevel The log level.
80
+ * @param message Log message object.
81
+ * @param ex Optional exception.
82
+ * @param includeStackTrace If the current stack should be included.
83
+ * @param showToast If a toast is to be shown.
84
+ */
85
+ private static void logInternal (LogLevel logLevel , LogMessage message , @ Nullable Throwable ex ,
86
+ boolean includeStackTrace , boolean showToast ) {
87
+ // It's very important that no Settings are used in this method,
88
+ // as this code is used when a context is not set and thus referencing
89
+ // a setting will crash the app.
90
+ String messageString = message .buildMessageString ();
91
+ String className = getOuterClassSimpleName (message );
92
+
93
+ StringBuilder logBuilder = new StringBuilder (className .length () + 2
94
+ + messageString .length ());
95
+ logBuilder .append (className ).append (": " ).append (messageString );
96
+
97
+ String toastMessage = showToast ? logBuilder .toString () : null ;
98
+
99
+ // Append exception message if present.
100
+ if (ex != null ) {
101
+ var exceptionMessage = ex .getMessage ();
102
+ if (exceptionMessage != null ) {
103
+ logBuilder .append ("\n Exception: " ).append (exceptionMessage );
104
+ }
105
+ }
106
+
107
+ if (includeStackTrace ) {
108
+ var sw = new StringWriter ();
109
+ new Throwable ().printStackTrace (new PrintWriter (sw ));
110
+ String stackTrace = sw .toString ();
111
+ // Remove the stacktrace elements of this class.
112
+ final int loggerIndex = stackTrace .lastIndexOf (LOGGER_CLASS_NAME );
113
+ final int loggerBegins = stackTrace .indexOf ('\n' , loggerIndex );
114
+ logBuilder .append (stackTrace , loggerBegins , stackTrace .length ());
115
+ }
116
+
117
+ String logText = logBuilder .toString ();
118
+ LogBufferManager .appendToLogBuffer (logText );
119
+
120
+ switch (logLevel ) {
121
+ case DEBUG :
122
+ if (ex == null ) Log .d (REVANCED_LOG_TAG , logText );
123
+ else Log .d (REVANCED_LOG_TAG , logText , ex );
124
+ break ;
125
+ case INFO :
126
+ if (ex == null ) Log .i (REVANCED_LOG_TAG , logText );
127
+ else Log .i (REVANCED_LOG_TAG , logText , ex );
128
+ break ;
129
+ case ERROR :
130
+ if (ex == null ) Log .e (REVANCED_LOG_TAG , logText );
131
+ else Log .e (REVANCED_LOG_TAG , logText , ex );
132
+ break ;
133
+ }
134
+
135
+ if (toastMessage != null ) {
136
+ Utils .showToastLong (toastMessage );
137
+ }
138
+ }
52
139
53
140
/**
54
141
* Logs debug messages under the outer class name of the code calling this method.
55
- * Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()}
56
- * so the performance cost of building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
142
+ * <p>
143
+ * Whenever possible, the log string should be constructed entirely inside
144
+ * {@link LogMessage#buildMessageString()} so the performance cost of
145
+ * building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
57
146
*/
58
- public static void printDebug (@ NonNull LogMessage message ) {
147
+ public static void printDebug (LogMessage message ) {
59
148
printDebug (message , null );
60
149
}
61
150
62
151
/**
63
152
* Logs debug messages under the outer class name of the code calling this method.
64
- * Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()}
65
- * so the performance cost of building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
153
+ * <p>
154
+ * Whenever possible, the log string should be constructed entirely inside
155
+ * {@link LogMessage#buildMessageString()} so the performance cost of
156
+ * building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
66
157
*/
67
- public static void printDebug (@ NonNull LogMessage message , @ Nullable Exception ex ) {
158
+ public static void printDebug (LogMessage message , @ Nullable Exception ex ) {
68
159
if (DEBUG .get ()) {
69
- String logMessage = message .buildMessageString ();
70
- String logTag = REVANCED_LOG_PREFIX + message .findOuterClassSimpleName ();
71
-
72
- if (DEBUG_STACKTRACE .get ()) {
73
- var builder = new StringBuilder (logMessage );
74
- var sw = new StringWriter ();
75
- new Throwable ().printStackTrace (new PrintWriter (sw ));
76
-
77
- builder .append ('\n' ).append (sw );
78
- logMessage = builder .toString ();
79
- }
80
-
81
- if (ex == null ) {
82
- Log .d (logTag , logMessage );
83
- } else {
84
- Log .d (logTag , logMessage , ex );
85
- }
160
+ logInternal (LogLevel .DEBUG , message , ex , DEBUG_STACKTRACE .get (), false );
86
161
}
87
162
}
88
163
89
164
/**
90
165
* Logs information messages using the outer class name of the code calling this method.
91
166
*/
92
- public static void printInfo (@ NonNull LogMessage message ) {
167
+ public static void printInfo (LogMessage message ) {
93
168
printInfo (message , null );
94
169
}
95
170
96
171
/**
97
172
* Logs information messages using the outer class name of the code calling this method.
98
173
*/
99
- public static void printInfo (@ NonNull LogMessage message , @ Nullable Exception ex ) {
100
- String logTag = REVANCED_LOG_PREFIX + message .findOuterClassSimpleName ();
101
- String logMessage = message .buildMessageString ();
102
- if (ex == null ) {
103
- Log .i (logTag , logMessage );
104
- } else {
105
- Log .i (logTag , logMessage , ex );
106
- }
174
+ public static void printInfo (LogMessage message , @ Nullable Exception ex ) {
175
+ logInternal (LogLevel .INFO , message , ex , DEBUG_STACKTRACE .get (), false );
107
176
}
108
177
109
178
/**
110
179
* Logs exceptions under the outer class name of the code calling this method.
180
+ * Appends the log message, exception (if present), and toast message (if enabled) to logBuffer.
111
181
*/
112
- public static void printException (@ NonNull LogMessage message ) {
182
+ public static void printException (LogMessage message ) {
113
183
printException (message , null );
114
184
}
115
185
@@ -122,35 +192,23 @@ public static void printException(@NonNull LogMessage message) {
122
192
* @param message log message
123
193
* @param ex exception (optional)
124
194
*/
125
- public static void printException (@ NonNull LogMessage message , @ Nullable Throwable ex ) {
126
- String messageString = message .buildMessageString ();
127
- String outerClassSimpleName = message .findOuterClassSimpleName ();
128
- String logMessage = REVANCED_LOG_PREFIX + outerClassSimpleName ;
129
- if (ex == null ) {
130
- Log .e (logMessage , messageString );
131
- } else {
132
- Log .e (logMessage , messageString , ex );
133
- }
134
- if (DEBUG_TOAST_ON_ERROR .get ()) {
135
- Utils .showToastLong (outerClassSimpleName + ": " + messageString );
136
- }
195
+ public static void printException (LogMessage message , @ Nullable Throwable ex ) {
196
+ logInternal (LogLevel .ERROR , message , ex , DEBUG_STACKTRACE .get (), DEBUG_TOAST_ON_ERROR .get ());
137
197
}
138
198
139
199
/**
140
200
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
141
201
* Normally this method should not be used.
142
202
*/
143
- public static void initializationInfo (@ NonNull Class <?> callingClass , @ NonNull String message ) {
144
- Log . i ( REVANCED_LOG_PREFIX + callingClass . getSimpleName () , message );
203
+ public static void initializationInfo (LogMessage message ) {
204
+ logInternal ( LogLevel . INFO , message , null , false , false );
145
205
}
146
206
147
207
/**
148
208
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
149
209
* Normally this method should not be used.
150
210
*/
151
- public static void initializationException (@ NonNull Class <?> callingClass , @ NonNull String message ,
152
- @ Nullable Exception ex ) {
153
- Log .e (REVANCED_LOG_PREFIX + callingClass .getSimpleName (), message , ex );
211
+ public static void initializationException (LogMessage message , @ Nullable Exception ex ) {
212
+ logInternal (LogLevel .ERROR , message , ex , false , false );
154
213
}
155
-
156
- }
214
+ }
0 commit comments