Buckets:
NaTo1000/termux-app-bucket / termux-shared /src /main /java /com /termux /shared /logger /Logger.java
| package com.termux.shared.logger; | |
| import android.content.Context; | |
| import android.os.Handler; | |
| import android.os.Looper; | |
| import android.util.Log; | |
| import android.widget.Toast; | |
| import androidx.annotation.NonNull; | |
| import com.termux.shared.R; | |
| import com.termux.shared.data.DataUtils; | |
| import java.io.IOException; | |
| import java.io.PrintWriter; | |
| import java.io.StringWriter; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.List; | |
| public class Logger { | |
| private static String DEFAULT_LOG_TAG = "Logger"; | |
| public static final int LOG_LEVEL_OFF = 0; // log nothing | |
| public static final int LOG_LEVEL_NORMAL = 1; // start logging error, warn and info messages and stacktraces | |
| public static final int LOG_LEVEL_DEBUG = 2; // start logging debug messages | |
| public static final int LOG_LEVEL_VERBOSE = 3; // start logging verbose messages | |
| public static final int DEFAULT_LOG_LEVEL = LOG_LEVEL_NORMAL; | |
| public static final int MAX_LOG_LEVEL = LOG_LEVEL_VERBOSE; | |
| private static int CURRENT_LOG_LEVEL = DEFAULT_LOG_LEVEL; | |
| /** | |
| * 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 | |
| public static void logMessage(int logPriority, String tag, String message) { | |
| if (logPriority == Log.ERROR && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) | |
| Log.e(getFullTag(tag), message); | |
| else if (logPriority == Log.WARN && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) | |
| Log.w(getFullTag(tag), message); | |
| else if (logPriority == Log.INFO && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) | |
| Log.i(getFullTag(tag), message); | |
| else if (logPriority == Log.DEBUG && CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) | |
| Log.d(getFullTag(tag), message); | |
| else if (logPriority == Log.VERBOSE && CURRENT_LOG_LEVEL >= LOG_LEVEL_VERBOSE) | |
| 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<String> 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<messagesList.size(); i++) { | |
| if (messagesList.size() > 1) | |
| prefix = "(" + (i + 1) + "/" + messagesList.size() + ")\n"; | |
| logMessage(logLevel, tag, prefix + messagesList.get(i)); | |
| } | |
| } | |
| public static void logError(String tag, String message) { | |
| logMessage(Log.ERROR, tag, message); | |
| } | |
| public static void logError(String message) { | |
| 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 logErrorPrivate(String tag, String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) | |
| logMessage(Log.ERROR, tag, message); | |
| } | |
| public static void logErrorPrivate(String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) | |
| logMessage(Log.ERROR, DEFAULT_LOG_TAG, message); | |
| } | |
| public static void logErrorPrivateExtended(String tag, String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) | |
| logExtendedMessage(Log.ERROR, tag, message); | |
| } | |
| public static void logErrorPrivateExtended(String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) | |
| logExtendedMessage(Log.ERROR, DEFAULT_LOG_TAG, message); | |
| } | |
| public static void logWarn(String tag, String message) { | |
| logMessage(Log.WARN, tag, message); | |
| } | |
| public static void logWarn(String message) { | |
| 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) { | |
| logMessage(Log.INFO, tag, message); | |
| } | |
| public static void logInfo(String message) { | |
| 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) { | |
| logMessage(Log.DEBUG, tag, message); | |
| } | |
| public static void logDebug(String message) { | |
| 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) { | |
| logMessage(Log.VERBOSE, tag, message); | |
| } | |
| public static void logVerbose(String message) { | |
| 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 logVerboseForce(String tag, String message) { | |
| Log.v(tag, message); | |
| } | |
| public static void logInfoAndShowToast(Context context, String tag, String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) { | |
| logInfo(tag, message); | |
| showToast(context, message, true); | |
| } | |
| } | |
| public static void logInfoAndShowToast(Context context, String message) { | |
| logInfoAndShowToast(context, DEFAULT_LOG_TAG, message); | |
| } | |
| public static void logErrorAndShowToast(Context context, String tag, String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) { | |
| logError(tag, message); | |
| showToast(context, message, true); | |
| } | |
| } | |
| public static void logErrorAndShowToast(Context context, String message) { | |
| logErrorAndShowToast(context, DEFAULT_LOG_TAG, message); | |
| } | |
| public static void logDebugAndShowToast(Context context, String tag, String message) { | |
| if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) { | |
| logDebug(tag, message); | |
| showToast(context, message, true); | |
| } | |
| } | |
| public static void logDebugAndShowToast(Context context, String message) { | |
| logDebugAndShowToast(context, DEFAULT_LOG_TAG, message); | |
| } | |
| public static void logStackTraceWithMessage(String tag, String message, Throwable throwable) { | |
| Logger.logErrorExtended(tag, getMessageAndStackTraceString(message, throwable)); | |
| } | |
| public static void logStackTraceWithMessage(String message, Throwable throwable) { | |
| logStackTraceWithMessage(DEFAULT_LOG_TAG, message, throwable); | |
| } | |
| public static void logStackTrace(String tag, Throwable throwable) { | |
| logStackTraceWithMessage(tag, null, throwable); | |
| } | |
| public static void logStackTrace(Throwable throwable) { | |
| logStackTraceWithMessage(DEFAULT_LOG_TAG, null, throwable); | |
| } | |
| public static void logStackTracesWithMessage(String tag, String message, List<Throwable> throwablesList) { | |
| Logger.logErrorExtended(tag, getMessageAndStackTracesString(message, throwablesList)); | |
| } | |
| public static String getMessageAndStackTraceString(String message, Throwable throwable) { | |
| if (message == null && throwable == null) | |
| return null; | |
| else if (message != null && throwable != null) | |
| return message + ":\n" + getStackTraceString(throwable); | |
| else if (throwable == null) | |
| return message; | |
| else | |
| return getStackTraceString(throwable); | |
| } | |
| public static String getMessageAndStackTracesString(String message, List<Throwable> throwablesList) { | |
| if (message == null && (throwablesList == null || throwablesList.size() == 0)) | |
| return null; | |
| else if (message != null && (throwablesList != null && throwablesList.size() != 0)) | |
| return message + ":\n" + getStackTracesString(null, getStackTracesStringArray(throwablesList)); | |
| else if (throwablesList == null || throwablesList.size() == 0) | |
| return message; | |
| else | |
| return getStackTracesString(null, getStackTracesStringArray(throwablesList)); | |
| } | |
| public static String getStackTraceString(Throwable throwable) { | |
| if (throwable == null) return null; | |
| String stackTraceString = null; | |
| try { | |
| StringWriter errors = new StringWriter(); | |
| PrintWriter pw = new PrintWriter(errors); | |
| throwable.printStackTrace(pw); | |
| pw.close(); | |
| stackTraceString = errors.toString(); | |
| errors.close(); | |
| } catch (IOException e) { | |
| e.printStackTrace(); | |
| } | |
| return stackTraceString; | |
| } | |
| public static String[] getStackTracesStringArray(Throwable throwable) { | |
| return getStackTracesStringArray(Collections.singletonList(throwable)); | |
| } | |
| public static String[] getStackTracesStringArray(List<Throwable> throwablesList) { | |
| 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)); | |
| } | |
| return stackTraceStringArray; | |
| } | |
| public static String getStackTracesString(String label, String[] stackTraceStringArray) { | |
| if (label == null) label = "StackTraces:"; | |
| StringBuilder stackTracesString = new StringBuilder(label); | |
| if (stackTraceStringArray == null || stackTraceStringArray.length == 0) { | |
| stackTracesString.append(" -"); | |
| } else { | |
| for (int i = 0; i != stackTraceStringArray.length; i++) { | |
| if (stackTraceStringArray.length > 1) | |
| stackTracesString.append("\n\nStacktrace ").append(i + 1); | |
| stackTracesString.append("\n```\n").append(stackTraceStringArray[i]).append("\n```\n"); | |
| } | |
| } | |
| return stackTracesString.toString(); | |
| } | |
| public static String getStackTracesMarkdownString(String label, String[] stackTraceStringArray) { | |
| if (label == null) label = "StackTraces"; | |
| StringBuilder stackTracesString = new StringBuilder("### " + label); | |
| if (stackTraceStringArray == null || stackTraceStringArray.length == 0) { | |
| stackTracesString.append("\n\n`-`"); | |
| } else { | |
| for (int i = 0; i != stackTraceStringArray.length; i++) { | |
| if (stackTraceStringArray.length > 1) | |
| stackTracesString.append("\n\n\n#### Stacktrace ").append(i + 1); | |
| stackTracesString.append("\n\n```\n").append(stackTraceStringArray[i]).append("\n```"); | |
| } | |
| } | |
| stackTracesString.append("\n##\n"); | |
| return stackTracesString.toString(); | |
| } | |
| public static String getSingleLineLogStringEntry(String label, Object object, String def) { | |
| if (object != null) | |
| return label + ": `" + object + "`"; | |
| else | |
| return label + ": " + def; | |
| } | |
| public static String getMultiLineLogStringEntry(String label, Object object, String def) { | |
| if (object != null) | |
| return label + ":\n```\n" + object + "\n```\n"; | |
| else | |
| return label + ": " + def; | |
| } | |
| public static void showToast(final Context context, final String toastText, boolean longDuration) { | |
| if (context == null || DataUtils.isNullOrEmpty(toastText)) return; | |
| new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(context, toastText, longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show()); | |
| } | |
| public static CharSequence[] getLogLevelsArray() { | |
| return new CharSequence[]{ | |
| String.valueOf(LOG_LEVEL_OFF), | |
| String.valueOf(LOG_LEVEL_NORMAL), | |
| String.valueOf(LOG_LEVEL_DEBUG), | |
| String.valueOf(LOG_LEVEL_VERBOSE) | |
| }; | |
| } | |
| public static CharSequence[] getLogLevelLabelsArray(Context context, CharSequence[] logLevels, boolean addDefaultTag) { | |
| if (logLevels == null) return null; | |
| CharSequence[] logLevelLabels = new CharSequence[logLevels.length]; | |
| for(int i=0; i<logLevels.length; i++) { | |
| logLevelLabels[i] = getLogLevelLabel(context, Integer.parseInt(logLevels[i].toString()), addDefaultTag); | |
| } | |
| return logLevelLabels; | |
| } | |
| public static String getLogLevelLabel(final Context context, final int logLevel, final boolean addDefaultTag) { | |
| String logLabel; | |
| switch (logLevel) { | |
| case LOG_LEVEL_OFF: logLabel = context.getString(R.string.log_level_off); break; | |
| case LOG_LEVEL_NORMAL: logLabel = context.getString(R.string.log_level_normal); break; | |
| case LOG_LEVEL_DEBUG: logLabel = context.getString(R.string.log_level_debug); break; | |
| case LOG_LEVEL_VERBOSE: logLabel = context.getString(R.string.log_level_verbose); break; | |
| default: logLabel = context.getString(R.string.log_level_unknown); break; | |
| } | |
| if (addDefaultTag && logLevel == DEFAULT_LOG_LEVEL) | |
| return logLabel + " (default)"; | |
| else | |
| return logLabel; | |
| } | |
| public static String getDefaultLogTag() { | |
| return DEFAULT_LOG_TAG; | |
| } | |
| /** | |
| * IllegalArgumentException will be thrown if tag.length() > 23 for Nougat (7.0) and prior releases. | |
| * https://developer.android.com/reference/android/util/Log#isLoggable(java.lang.String,%20int) */ | |
| public static void setDefaultLogTag( String defaultLogTag) { | |
| DEFAULT_LOG_TAG = defaultLogTag.length() >= 23 ? defaultLogTag.substring(0, 22) : defaultLogTag; | |
| } | |
| public static int getLogLevel() { | |
| return CURRENT_LOG_LEVEL; | |
| } | |
| public static int setLogLevel(Context context, int logLevel) { | |
| if (isLogLevelValid(logLevel)) | |
| CURRENT_LOG_LEVEL = logLevel; | |
| else | |
| CURRENT_LOG_LEVEL = DEFAULT_LOG_LEVEL; | |
| if (context != null) | |
| showToast(context, context.getString(R.string.log_level_value, getLogLevelLabel(context, CURRENT_LOG_LEVEL, false)),true); | |
| return CURRENT_LOG_LEVEL; | |
| } | |
| /** The colon character ":" must not exist inside the tag, otherwise the `logcat` command | |
| * filterspecs arguments `<tag>[:priority]` will not work and will throw `Invalid filter expression` | |
| * error. | |
| * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/logging/liblog/logprint.cpp;l=363 | |
| * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/logging/logcat/logcat.cpp;l=884 | |
| * */ | |
| public static String getFullTag(String tag) { | |
| if (DEFAULT_LOG_TAG.equals(tag)) | |
| return tag; | |
| else | |
| return DEFAULT_LOG_TAG + "." + tag; | |
| } | |
| public static boolean isLogLevelValid(Integer logLevel) { | |
| return (logLevel != null && logLevel >= LOG_LEVEL_OFF && logLevel <= MAX_LOG_LEVEL); | |
| } | |
| /** Check if custom log level is valid and >= {@link #CURRENT_LOG_LEVEL}. If custom log level is | |
| * not valid then {@link #LOG_LEVEL_VERBOSE} must be >= {@link #CURRENT_LOG_LEVEL}. */ | |
| public static boolean shouldEnableLoggingForCustomLogLevel(Integer customLogLevel) { | |
| if (CURRENT_LOG_LEVEL <= LOG_LEVEL_OFF) return false; | |
| if (customLogLevel == null) return CURRENT_LOG_LEVEL >= LOG_LEVEL_VERBOSE; // Use default app log level | |
| if (customLogLevel <= LOG_LEVEL_OFF) return false; | |
| customLogLevel = Logger.isLogLevelValid(customLogLevel) ? customLogLevel: Logger.LOG_LEVEL_VERBOSE; | |
| return (customLogLevel >= CURRENT_LOG_LEVEL); | |
| } | |
| } | |
Xet Storage Details
- Size:
- 18 kB
- Xet hash:
- ac0db9af84cce131c7611e3edfdd3a5b53555635b3c822635ddaf6c37d33d0f1
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.