revanced-integrations/app/src/main/java/app/revanced/integrations/utils/LogHelper.java

143 lines
5.3 KiB
Java

package app.revanced.integrations.utils;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.PrintWriter;
import java.io.StringWriter;
import app.revanced.integrations.settings.SettingsEnum;
public class LogHelper {
/**
* Log messages using lambdas.
*/
public interface LogMessage {
@NonNull
String buildMessageString();
/**
* @return For outer classes, this returns {@link Class#getSimpleName()}.
* For inner, static, or anonymous classes, this returns the simple name of the enclosing class.<br>
* <br>
* For example, each of these classes return 'SomethingView':
* <code>
* com.company.SomethingView
* com.company.SomethingView$StaticClass
* com.company.SomethingView$1
* </code>
*/
private String findOuterClassSimpleName() {
var selfClass = this.getClass();
String fullClassName = selfClass.getName();
final int dollarSignIndex = fullClassName.indexOf('$');
if (dollarSignIndex == -1) {
return selfClass.getSimpleName(); // already an outer class
}
// class is inner, static, or anonymous
// parse the simple name full name
// a class with no package returns index of -1, but incrementing gives index zero which is correct
final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1;
return fullClassName.substring(simpleClassNameStartIndex, dollarSignIndex);
}
}
private static final String REVANCED_LOG_PREFIX = "revanced: ";
/**
* Logs debug messages under the outer class name of the code calling this method.
* Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()}
* so the performance cost of building strings is paid only if {@link SettingsEnum#DEBUG} is enabled.
*/
public static void printDebug(@NonNull LogMessage message) {
if (SettingsEnum.DEBUG.getBoolean()) {
var messageString = message.buildMessageString();
if (SettingsEnum.DEBUG_STACKTRACE.getBoolean()) {
var builder = new StringBuilder(messageString);
var sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));
builder.append('\n').append(sw);
messageString = builder.toString();
}
Log.d(REVANCED_LOG_PREFIX + message.findOuterClassSimpleName(), messageString);
}
}
/**
* Logs information messages using the outer class name of the code calling this method.
*/
public static void printInfo(@NonNull LogMessage message) {
printInfo(message, null);
}
/**
* Logs information messages using the outer class name of the code calling this method.
*/
public static void printInfo(@NonNull LogMessage message, @Nullable Exception ex) {
String logTag = REVANCED_LOG_PREFIX + message.findOuterClassSimpleName();
String logMessage = message.buildMessageString();
if (ex == null) {
Log.i(logTag, logMessage);
} else {
Log.i(logTag, logMessage, ex);
}
}
/**
* Logs exceptions under the outer class name of the code calling this method.
*/
public static void printException(@NonNull LogMessage message) {
printException(message, null, null);
}
/**
* Logs exceptions under the outer class name of the code calling this method.
*/
public static void printException(@NonNull LogMessage message, @Nullable Throwable ex) {
printException(message, ex, null);
}
/**
* Logs exceptions under the outer class name of the code calling this method.
* <p>
* If the calling code is showing it's own error toast,
* instead use {@link #printInfo(LogMessage, Exception)}
*
* @param message log message
* @param ex exception (optional)
* @param userToastMessage user specific toast message to show instead of the log message (optional)
*/
public static void printException(@NonNull LogMessage message, @Nullable Throwable ex,
@Nullable String userToastMessage) {
String messageString = message.buildMessageString();
String outerClassSimpleName = message.findOuterClassSimpleName();
String logMessage = REVANCED_LOG_PREFIX + outerClassSimpleName;
if (ex == null) {
Log.e(logMessage, messageString);
} else {
Log.e(logMessage, messageString, ex);
}
if (SettingsEnum.DEBUG_SHOW_TOAST_ON_ERROR.getBoolean()) {
String toastMessageToDisplay = (userToastMessage != null)
? userToastMessage
: outerClassSimpleName + ": " + messageString;
ReVancedUtils.runOnMainThread(() -> {
Context context = ReVancedUtils.getContext();
if (context != null) {
Toast.makeText(context, toastMessageToDisplay, Toast.LENGTH_LONG).show();
}
});
}
}
}