diff --git a/termux-shared/src/main/java/com/termux/shared/logger/Logger.java b/termux-shared/src/main/java/com/termux/shared/logger/Logger.java index 0560625b..0794c61c 100644 --- a/termux-shared/src/main/java/com/termux/shared/logger/Logger.java +++ b/termux-shared/src/main/java/com/termux/shared/logger/Logger.java @@ -12,6 +12,7 @@ import com.termux.shared.termux.TermuxConstants; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,7 +28,25 @@ public class Logger { public static final int DEFAULT_LOG_LEVEL = LOG_LEVEL_NORMAL; private static int CURRENT_LOG_LEVEL = DEFAULT_LOG_LEVEL; - public static final int LOGGER_ENTRY_SIZE_LIMIT_IN_BYTES = 4 * 1024; // 4KB + /** + * The maximum size of the log entry payload that can be written to the logger. An attempt to + * write more than this amount will result in a truncated log entry. + * + * The limit is 4068 but this includes log tag and log level prefix "D/" before log tag and ": " + * suffix after it. + * + * #define LOGGER_ENTRY_MAX_PAYLOAD 4068 + * https://cs.android.com/android/_/android/platform/system/core/+/android10-release:liblog/include/log/log_read.h;l=127 + */ + public static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068; // 4068 bytes + + /** + * The maximum safe size of the log entry payload that can be written to the logger, based on + * {@link #LOGGER_ENTRY_MAX_PAYLOAD}. Using 4000 as a safe limit to give log tag and its + * prefix/suffix max 68 characters for itself. Use "log*Extended()" functions to use max possible + * limit if tag is already known. + */ + public static final int LOGGER_ENTRY_MAX_SAFE_PAYLOAD = 4000; // 4000 bytes @@ -44,6 +63,40 @@ public class Logger { Log.v(getFullTag(tag), message); } + public static void logExtendedMessage(int logLevel, String tag, String message) { + if (message == null) return; + + int cutOffIndex; + int nextNewlineIndex; + String prefix = ""; + + // -8 for prefix "(xx/xx)" (max 99 sections), - log tag length, -4 for log tag prefix "D/" and suffix ": " + int maxEntrySize = LOGGER_ENTRY_MAX_PAYLOAD - 8 - getFullTag(tag).length() - 4; + + List messagesList = new ArrayList<>(); + + while(!message.isEmpty()) { + if (message.length() > maxEntrySize) { + cutOffIndex = maxEntrySize; + nextNewlineIndex = message.lastIndexOf('\n', cutOffIndex); + if (nextNewlineIndex != -1) { + cutOffIndex = nextNewlineIndex + 1; + } + messagesList.add(message.substring(0, cutOffIndex)); + message = message.substring(cutOffIndex); + } else { + messagesList.add(message); + break; + } + } + + for(int i=0; i 1) + prefix = "(" + (i + 1) + "/" + messagesList.size() + ")\n"; + logMessage(logLevel, tag, prefix + messagesList.get(i)); + } + } + public static void logError(String tag, String message) { @@ -54,6 +107,14 @@ public class Logger { logMessage(Log.ERROR, DEFAULT_LOG_TAG, message); } + public static void logErrorExtended(String tag, String message) { + logExtendedMessage(Log.ERROR, tag, message); + } + + public static void logErrorExtended(String message) { + logExtendedMessage(Log.ERROR, DEFAULT_LOG_TAG, message); + } + public static void logWarn(String tag, String message) { @@ -64,6 +125,14 @@ public class Logger { logMessage(Log.WARN, DEFAULT_LOG_TAG, message); } + public static void logWarnExtended(String tag, String message) { + logExtendedMessage(Log.WARN, tag, message); + } + + public static void logWarnExtended(String message) { + logExtendedMessage(Log.WARN, DEFAULT_LOG_TAG, message); + } + public static void logInfo(String tag, String message) { @@ -74,6 +143,14 @@ public class Logger { logMessage(Log.INFO, DEFAULT_LOG_TAG, message); } + public static void logInfoExtended(String tag, String message) { + logExtendedMessage(Log.INFO, tag, message); + } + + public static void logInfoExtended(String message) { + logExtendedMessage(Log.INFO, DEFAULT_LOG_TAG, message); + } + public static void logDebug(String tag, String message) { @@ -84,6 +161,14 @@ public class Logger { logMessage(Log.DEBUG, DEFAULT_LOG_TAG, message); } + public static void logDebugExtended(String tag, String message) { + logExtendedMessage(Log.DEBUG, tag, message); + } + + public static void logDebugExtended(String message) { + logExtendedMessage(Log.DEBUG, DEFAULT_LOG_TAG, message); + } + public static void logVerbose(String tag, String message) { @@ -94,6 +179,14 @@ public class Logger { logMessage(Log.VERBOSE, DEFAULT_LOG_TAG, message); } + public static void logVerboseExtended(String tag, String message) { + logExtendedMessage(Log.VERBOSE, tag, message); + } + + public static void logVerboseExtended(String message) { + logExtendedMessage(Log.VERBOSE, DEFAULT_LOG_TAG, message); + } + public static void logErrorAndShowToast(Context context, String tag, String message) { @@ -126,48 +219,103 @@ public class Logger { + public static void logStackTraceWithMessage(String tag, String message, Throwable throwable, boolean getSuppressed) { + Logger.logErrorExtended(tag, getMessageAndStackTraceString(message, throwable, getSuppressed)); + } + public static void logStackTraceWithMessage(String tag, String message, Throwable throwable) { - if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) - Log.e(getFullTag(tag), getMessageAndStackTraceString(message, throwable)); + logStackTraceWithMessage(tag, message, throwable, true); + } + + public static void logStackTraceWithMessage(String message, Throwable throwable, boolean getSuppressed) { + logStackTraceWithMessage(DEFAULT_LOG_TAG, message, throwable, getSuppressed); } public static void logStackTraceWithMessage(String message, Throwable throwable) { - logStackTraceWithMessage(DEFAULT_LOG_TAG, message, throwable); + logStackTraceWithMessage(DEFAULT_LOG_TAG, message, throwable, true); + } + + + public static void logStackTrace(String tag, Throwable throwable, boolean getSuppressed) { + logStackTraceWithMessage(tag, null, throwable, getSuppressed); } public static void logStackTrace(String tag, Throwable throwable) { - logStackTraceWithMessage(tag, null, throwable); + logStackTraceWithMessage(tag, null, throwable, true); + } + + + public static void logStackTrace(Throwable throwable, boolean getSuppressed) { + logStackTraceWithMessage(DEFAULT_LOG_TAG, null, throwable, getSuppressed); } public static void logStackTrace(Throwable throwable) { - logStackTraceWithMessage(DEFAULT_LOG_TAG, null, throwable); + logStackTraceWithMessage(DEFAULT_LOG_TAG, null, throwable, true); } - public static void logStackTracesWithMessage(String tag, String message, List throwableList) { - if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) - Log.e(getFullTag(tag), getMessageAndStackTracesString(message, throwableList)); + + + public static void logStackTracesWithMessage(String tag, String message, List throwablesList, boolean getSuppressed) { + Logger.logErrorExtended(tag, getMessageAndStackTracesString(message, throwablesList, getSuppressed)); } + public static void logStackTracesWithMessage(String tag, String message, List throwablesList) { + Logger.logErrorExtended(tag, getMessageAndStackTracesString(message, throwablesList, true)); + } + + + public static String getMessageAndStackTraceString(String message, Throwable throwable) { + return getMessageAndStackTraceString(message, throwable, true); + } + + public static String getMessageAndStackTraceString(String message, Throwable throwable, boolean getSuppressed) { if (message == null && throwable == null) return null; else if (message != null && throwable != null) - return message + ":\n" + getStackTraceString(throwable); + return message + ":\n" + getStackTraceString(throwable, getSuppressed); else if (throwable == null) return message; else - return getStackTraceString(throwable); + return getStackTraceString(throwable, getSuppressed); } - public static String getMessageAndStackTracesString(String message, List throwableList) { - if (message == null && (throwableList == null || throwableList.size() == 0)) + + + public static String getMessageAndStackTracesString(String message, List throwablesList) { + return getMessageAndStackTracesString(message, throwablesList, true); + } + + public static String getMessageAndStackTracesString(String message, List throwablesList, boolean getSuppressed) { + if (message == null && (throwablesList == null || throwablesList.size() == 0)) return null; - else if (message != null && (throwableList != null && throwableList.size() != 0)) - return message + ":\n" + getStackTracesString(null, getStackTraceStringArray(throwableList)); - else if (throwableList == null || throwableList.size() == 0) + else if (message != null && (throwablesList != null && throwablesList.size() != 0)) + return message + ":\n" + getStackTracesString(null, getStackTracesStringArray(throwablesList, getSuppressed)); + else if (throwablesList == null || throwablesList.size() == 0) return message; else - return getStackTracesString(null, getStackTraceStringArray(throwableList)); + return getStackTracesString(null, getStackTracesStringArray(throwablesList, getSuppressed)); + } + + + + public static String getStackTraceString(Throwable throwable, boolean getSuppressed) { + if (throwable == null) return null; + + StringBuilder stackTraceString = new StringBuilder(); + stackTraceString.append(getStackTraceString(throwable)); + + if (getSuppressed) { + Throwable[] suppressedThrowablesArray = throwable.getSuppressed(); + if (suppressedThrowablesArray != null && suppressedThrowablesArray.length > 0) { + for (Throwable suppressedThrowable : suppressedThrowablesArray) { + if (suppressedThrowable == null) continue; + stackTraceString.append("\n\n").append(getStackTraceString(suppressedThrowable)); + } + } + } + + return stackTraceString.toString(); } public static String getStackTraceString(Throwable throwable) { @@ -182,27 +330,40 @@ public class Logger { pw.close(); stackTraceString = errors.toString(); errors.close(); - } catch (IOException e1) { - e1.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); } return stackTraceString; } - public static String[] getStackTraceStringArray(Throwable throwable) { - return getStackTraceStringArray(Collections.singletonList(throwable)); + + + public static String[] getStackTracesStringArray(Throwable throwable, boolean getSuppressed) { + return getStackTracesStringArray(Collections.singletonList(throwable), getSuppressed); } - public static String[] getStackTraceStringArray(List throwableList) { - if (throwableList == null) return null; + public static String[] getStackTracesStringArray(Throwable throwable) { + return getStackTracesStringArray(Collections.singletonList(throwable), true); + } - final String[] stackTraceStringArray = new String[throwableList.size()]; - for (int i = 0; i < throwableList.size(); i++) { - stackTraceStringArray[i] = getStackTraceString(throwableList.get(i)); + public static String[] getStackTracesStringArray(List throwablesList) { + return getStackTracesStringArray(throwablesList, true); + + } + + public static String[] getStackTracesStringArray(List throwablesList, boolean getSuppressed) { + if (throwablesList == null) return null; + + final String[] stackTraceStringArray = new String[throwablesList.size()]; + for (int i = 0; i < throwablesList.size(); i++) { + stackTraceStringArray[i] = getStackTraceString(throwablesList.get(i), getSuppressed); } return stackTraceStringArray; } + + public static String getStackTracesString(String label, String[] stackTraceStringArray) { if (label == null) label = "StackTraces:"; StringBuilder stackTracesString = new StringBuilder(label);