termux-app

Форк
0
502 строки · 17.6 Кб
1
package com.termux.shared.logger;
2

3
import android.content.Context;
4
import android.os.Handler;
5
import android.os.Looper;
6
import android.util.Log;
7
import android.widget.Toast;
8

9
import androidx.annotation.NonNull;
10

11
import com.termux.shared.R;
12
import com.termux.shared.data.DataUtils;
13

14
import java.io.IOException;
15
import java.io.PrintWriter;
16
import java.io.StringWriter;
17
import java.util.ArrayList;
18
import java.util.Collections;
19
import java.util.List;
20

21
public class Logger {
22

23
    private static String DEFAULT_LOG_TAG = "Logger";
24

25
    public static final int LOG_LEVEL_OFF = 0; // log nothing
26
    public static final int LOG_LEVEL_NORMAL = 1; // start logging error, warn and info messages and stacktraces
27
    public static final int LOG_LEVEL_DEBUG = 2; // start logging debug messages
28
    public static final int LOG_LEVEL_VERBOSE = 3; // start logging verbose messages
29

30
    public static final int DEFAULT_LOG_LEVEL = LOG_LEVEL_NORMAL;
31
    public static final int MAX_LOG_LEVEL = LOG_LEVEL_VERBOSE;
32
    private static int CURRENT_LOG_LEVEL = DEFAULT_LOG_LEVEL;
33

34
    /**
35
     * The maximum size of the log entry payload that can be written to the logger. An attempt to
36
     * write more than this amount will result in a truncated log entry.
37
     *
38
     * The limit is 4068 but this includes log tag and log level prefix "D/" before log tag and ": "
39
     * suffix after it.
40
     *
41
     * #define LOGGER_ENTRY_MAX_PAYLOAD 4068
42
     * https://cs.android.com/android/_/android/platform/system/core/+/android10-release:liblog/include/log/log_read.h;l=127
43
     */
44
    public static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068; // 4068 bytes
45

46
    /**
47
     * The maximum safe size of the log entry payload that can be written to the logger, based on
48
     * {@link #LOGGER_ENTRY_MAX_PAYLOAD}. Using 4000 as a safe limit to give log tag and its
49
     * prefix/suffix max 68 characters for itself. Use "log*Extended()" functions to use max possible
50
     * limit if tag is already known.
51
     */
52
    public static final int LOGGER_ENTRY_MAX_SAFE_PAYLOAD = 4000; // 4000 bytes
53

54

55

56
    public static void logMessage(int logPriority, String tag, String message) {
57
        if (logPriority == Log.ERROR && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL)
58
            Log.e(getFullTag(tag), message);
59
        else if (logPriority == Log.WARN && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL)
60
            Log.w(getFullTag(tag), message);
61
        else if (logPriority == Log.INFO && CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL)
62
            Log.i(getFullTag(tag), message);
63
        else if (logPriority == Log.DEBUG && CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG)
64
            Log.d(getFullTag(tag), message);
65
        else if (logPriority == Log.VERBOSE && CURRENT_LOG_LEVEL >= LOG_LEVEL_VERBOSE)
66
            Log.v(getFullTag(tag), message);
67
    }
68

69
    public static void logExtendedMessage(int logLevel, String tag, String message) {
70
        if (message == null) return;
71

72
        int cutOffIndex;
73
        int nextNewlineIndex;
74
        String prefix = "";
75

76
        // -8 for prefix "(xx/xx)" (max 99 sections), - log tag length, -4 for log tag prefix "D/" and suffix ": "
77
        int maxEntrySize = LOGGER_ENTRY_MAX_PAYLOAD - 8 - getFullTag(tag).length() - 4;
78

79
        List<String> messagesList = new ArrayList<>();
80

81
        while(!message.isEmpty()) {
82
            if (message.length() > maxEntrySize) {
83
                cutOffIndex = maxEntrySize;
84
                nextNewlineIndex = message.lastIndexOf('\n', cutOffIndex);
85
                if (nextNewlineIndex != -1) {
86
                    cutOffIndex = nextNewlineIndex + 1;
87
                }
88
                messagesList.add(message.substring(0, cutOffIndex));
89
                message = message.substring(cutOffIndex);
90
            } else {
91
                messagesList.add(message);
92
                break;
93
            }
94
        }
95

96
        for(int i=0; i<messagesList.size(); i++) {
97
            if (messagesList.size() > 1)
98
                prefix = "(" + (i + 1) + "/" + messagesList.size() + ")\n";
99
            logMessage(logLevel, tag, prefix + messagesList.get(i));
100
        }
101
    }
102

103

104

105
    public static void logError(String tag, String message) {
106
        logMessage(Log.ERROR, tag, message);
107
    }
108

109
    public static void logError(String message) {
110
        logMessage(Log.ERROR, DEFAULT_LOG_TAG, message);
111
    }
112

113
    public static void logErrorExtended(String tag, String message) {
114
        logExtendedMessage(Log.ERROR, tag, message);
115
    }
116

117
    public static void logErrorExtended(String message) {
118
        logExtendedMessage(Log.ERROR, DEFAULT_LOG_TAG, message);
119
    }
120

121

122

123
    public static void logErrorPrivate(String tag, String message) {
124
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG)
125
            logMessage(Log.ERROR, tag, message);
126
    }
127

128
    public static void logErrorPrivate(String message) {
129
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG)
130
            logMessage(Log.ERROR, DEFAULT_LOG_TAG, message);
131
    }
132

133
    public static void logErrorPrivateExtended(String tag, String message) {
134
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG)
135
            logExtendedMessage(Log.ERROR, tag, message);
136
    }
137

138
    public static void logErrorPrivateExtended(String message) {
139
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG)
140
            logExtendedMessage(Log.ERROR, DEFAULT_LOG_TAG, message);
141
    }
142

143

144

145
    public static void logWarn(String tag, String message) {
146
        logMessage(Log.WARN, tag, message);
147
    }
148

149
    public static void logWarn(String message) {
150
        logMessage(Log.WARN, DEFAULT_LOG_TAG, message);
151
    }
152

153
    public static void logWarnExtended(String tag, String message) {
154
        logExtendedMessage(Log.WARN, tag, message);
155
    }
156

157
    public static void logWarnExtended(String message) {
158
        logExtendedMessage(Log.WARN, DEFAULT_LOG_TAG, message);
159
    }
160

161

162

163
    public static void logInfo(String tag, String message) {
164
        logMessage(Log.INFO, tag, message);
165
    }
166

167
    public static void logInfo(String message) {
168
        logMessage(Log.INFO, DEFAULT_LOG_TAG, message);
169
    }
170

171
    public static void logInfoExtended(String tag, String message) {
172
        logExtendedMessage(Log.INFO, tag, message);
173
    }
174

175
    public static void logInfoExtended(String message) {
176
        logExtendedMessage(Log.INFO, DEFAULT_LOG_TAG, message);
177
    }
178

179

180

181
    public static void logDebug(String tag, String message) {
182
        logMessage(Log.DEBUG, tag, message);
183
    }
184

185
    public static void logDebug(String message) {
186
        logMessage(Log.DEBUG, DEFAULT_LOG_TAG, message);
187
    }
188

189
    public static void logDebugExtended(String tag, String message) {
190
        logExtendedMessage(Log.DEBUG, tag, message);
191
    }
192

193
    public static void logDebugExtended(String message) {
194
        logExtendedMessage(Log.DEBUG, DEFAULT_LOG_TAG, message);
195
    }
196

197

198

199
    public static void logVerbose(String tag, String message) {
200
        logMessage(Log.VERBOSE, tag, message);
201
    }
202

203
    public static void logVerbose(String message) {
204
        logMessage(Log.VERBOSE, DEFAULT_LOG_TAG, message);
205
    }
206

207
    public static void logVerboseExtended(String tag, String message) {
208
        logExtendedMessage(Log.VERBOSE, tag, message);
209
    }
210

211
    public static void logVerboseExtended(String message) {
212
        logExtendedMessage(Log.VERBOSE, DEFAULT_LOG_TAG, message);
213
    }
214

215
    public static void logVerboseForce(String tag, String message) {
216
        Log.v(tag, message);
217
    }
218

219

220

221
    public static void logInfoAndShowToast(Context context, String tag, String message) {
222
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) {
223
            logInfo(tag, message);
224
            showToast(context, message, true);
225
        }
226
    }
227

228
    public static void logInfoAndShowToast(Context context, String message) {
229
        logInfoAndShowToast(context, DEFAULT_LOG_TAG, message);
230
    }
231

232

233

234
    public static void logErrorAndShowToast(Context context, String tag, String message) {
235
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_NORMAL) {
236
            logError(tag, message);
237
            showToast(context, message, true);
238
        }
239
    }
240

241
    public static void logErrorAndShowToast(Context context, String message) {
242
        logErrorAndShowToast(context, DEFAULT_LOG_TAG, message);
243
    }
244

245

246

247
    public static void logDebugAndShowToast(Context context, String tag, String message) {
248
        if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) {
249
            logDebug(tag, message);
250
            showToast(context, message, true);
251
        }
252
    }
253

254
    public static void logDebugAndShowToast(Context context, String message) {
255
        logDebugAndShowToast(context, DEFAULT_LOG_TAG, message);
256
    }
257

258

259

260
    public static void logStackTraceWithMessage(String tag, String message, Throwable throwable) {
261
        Logger.logErrorExtended(tag, getMessageAndStackTraceString(message, throwable));
262
    }
263

264
    public static void logStackTraceWithMessage(String message, Throwable throwable) {
265
        logStackTraceWithMessage(DEFAULT_LOG_TAG, message, throwable);
266
    }
267

268
    public static void logStackTrace(String tag, Throwable throwable) {
269
        logStackTraceWithMessage(tag, null, throwable);
270
    }
271

272
    public static void logStackTrace(Throwable throwable) {
273
        logStackTraceWithMessage(DEFAULT_LOG_TAG, null, throwable);
274
    }
275

276

277

278
    public static void logStackTracesWithMessage(String tag, String message, List<Throwable> throwablesList) {
279
        Logger.logErrorExtended(tag, getMessageAndStackTracesString(message, throwablesList));
280
    }
281

282

283

284
    public static String getMessageAndStackTraceString(String message, Throwable throwable) {
285
        if (message == null && throwable == null)
286
            return null;
287
        else if (message != null && throwable != null)
288
            return message + ":\n" + getStackTraceString(throwable);
289
        else if (throwable == null)
290
            return message;
291
        else
292
            return getStackTraceString(throwable);
293
    }
294

295
    public static String getMessageAndStackTracesString(String message, List<Throwable> throwablesList) {
296
        if (message == null && (throwablesList == null || throwablesList.size() == 0))
297
            return null;
298
        else if (message != null && (throwablesList != null && throwablesList.size() != 0))
299
            return message + ":\n" + getStackTracesString(null, getStackTracesStringArray(throwablesList));
300
        else if (throwablesList == null || throwablesList.size() == 0)
301
            return message;
302
        else
303
            return getStackTracesString(null, getStackTracesStringArray(throwablesList));
304
    }
305

306

307

308
    public static String getStackTraceString(Throwable throwable) {
309
        if (throwable == null) return null;
310

311
        String stackTraceString = null;
312

313
        try {
314
            StringWriter errors = new StringWriter();
315
            PrintWriter pw = new PrintWriter(errors);
316
            throwable.printStackTrace(pw);
317
            pw.close();
318
            stackTraceString = errors.toString();
319
            errors.close();
320
        } catch (IOException e) {
321
            e.printStackTrace();
322
        }
323

324
        return stackTraceString;
325
    }
326

327

328

329
    public static String[] getStackTracesStringArray(Throwable throwable) {
330
        return getStackTracesStringArray(Collections.singletonList(throwable));
331
    }
332

333
    public static String[] getStackTracesStringArray(List<Throwable> throwablesList) {
334
        if (throwablesList == null) return null;
335
        final String[] stackTraceStringArray = new String[throwablesList.size()];
336
        for (int i = 0; i < throwablesList.size(); i++) {
337
            stackTraceStringArray[i] = getStackTraceString(throwablesList.get(i));
338
        }
339
        return stackTraceStringArray;
340
    }
341

342

343

344
    public static String getStackTracesString(String label, String[] stackTraceStringArray) {
345
        if (label == null) label = "StackTraces:";
346
        StringBuilder stackTracesString = new StringBuilder(label);
347

348
        if (stackTraceStringArray == null || stackTraceStringArray.length == 0) {
349
            stackTracesString.append(" -");
350
        } else {
351
            for (int i = 0; i != stackTraceStringArray.length; i++) {
352
                if (stackTraceStringArray.length > 1)
353
                    stackTracesString.append("\n\nStacktrace ").append(i + 1);
354

355
                stackTracesString.append("\n```\n").append(stackTraceStringArray[i]).append("\n```\n");
356
            }
357
        }
358

359
        return stackTracesString.toString();
360
    }
361

362
    public static String getStackTracesMarkdownString(String label, String[] stackTraceStringArray) {
363
        if (label == null) label = "StackTraces";
364
        StringBuilder stackTracesString = new StringBuilder("### " + label);
365

366
        if (stackTraceStringArray == null || stackTraceStringArray.length == 0) {
367
            stackTracesString.append("\n\n`-`");
368
        } else {
369
            for (int i = 0; i != stackTraceStringArray.length; i++) {
370
                if (stackTraceStringArray.length > 1)
371
                    stackTracesString.append("\n\n\n#### Stacktrace ").append(i + 1);
372

373
                stackTracesString.append("\n\n```\n").append(stackTraceStringArray[i]).append("\n```");
374
            }
375
        }
376

377
        stackTracesString.append("\n##\n");
378

379
        return stackTracesString.toString();
380
    }
381

382
    public static String getSingleLineLogStringEntry(String label, Object object, String def) {
383
        if (object != null)
384
            return label + ": `" + object + "`";
385
        else
386
            return  label + ": "  +  def;
387
    }
388

389
    public static String getMultiLineLogStringEntry(String label, Object object, String def) {
390
        if (object != null)
391
            return label + ":\n```\n" + object + "\n```\n";
392
        else
393
            return  label + ": "  +  def;
394
    }
395

396

397

398
    public static void showToast(final Context context, final String toastText, boolean longDuration) {
399
        if (context == null || DataUtils.isNullOrEmpty(toastText)) return;
400

401
        new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(context, toastText, longDuration ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT).show());
402
    }
403

404

405

406
    public static CharSequence[] getLogLevelsArray() {
407
        return new CharSequence[]{
408
            String.valueOf(LOG_LEVEL_OFF),
409
            String.valueOf(LOG_LEVEL_NORMAL),
410
            String.valueOf(LOG_LEVEL_DEBUG),
411
            String.valueOf(LOG_LEVEL_VERBOSE)
412
        };
413
    }
414

415
    public static CharSequence[] getLogLevelLabelsArray(Context context, CharSequence[] logLevels, boolean addDefaultTag) {
416
        if (logLevels == null) return null;
417

418
        CharSequence[] logLevelLabels = new CharSequence[logLevels.length];
419

420
        for(int i=0; i<logLevels.length; i++) {
421
            logLevelLabels[i] = getLogLevelLabel(context, Integer.parseInt(logLevels[i].toString()), addDefaultTag);
422
        }
423

424
        return logLevelLabels;
425
    }
426

427
    public static String getLogLevelLabel(final Context context, final int logLevel, final boolean addDefaultTag) {
428
        String logLabel;
429
        switch (logLevel) {
430
            case LOG_LEVEL_OFF: logLabel = context.getString(R.string.log_level_off); break;
431
            case LOG_LEVEL_NORMAL: logLabel = context.getString(R.string.log_level_normal); break;
432
            case LOG_LEVEL_DEBUG: logLabel = context.getString(R.string.log_level_debug); break;
433
            case LOG_LEVEL_VERBOSE: logLabel = context.getString(R.string.log_level_verbose); break;
434
            default: logLabel = context.getString(R.string.log_level_unknown); break;
435
        }
436

437
        if (addDefaultTag && logLevel == DEFAULT_LOG_LEVEL)
438
            return logLabel + " (default)";
439
        else
440
            return logLabel;
441
    }
442

443

444

445
    @NonNull
446
    public static String getDefaultLogTag() {
447
        return DEFAULT_LOG_TAG;
448
    }
449

450
    /**
451
     * IllegalArgumentException will be thrown if tag.length() > 23 for Nougat (7.0) and prior releases.
452
     * https://developer.android.com/reference/android/util/Log#isLoggable(java.lang.String,%20int) */
453
    public static void setDefaultLogTag(@NonNull String defaultLogTag) {
454
        DEFAULT_LOG_TAG = defaultLogTag.length() >= 23 ? defaultLogTag.substring(0, 22) : defaultLogTag;
455
    }
456

457

458

459
    public static int getLogLevel() {
460
        return CURRENT_LOG_LEVEL;
461
    }
462

463
    public static int setLogLevel(Context context, int logLevel) {
464
        if (isLogLevelValid(logLevel))
465
            CURRENT_LOG_LEVEL = logLevel;
466
        else
467
            CURRENT_LOG_LEVEL = DEFAULT_LOG_LEVEL;
468

469
        if (context != null)
470
            showToast(context, context.getString(R.string.log_level_value, getLogLevelLabel(context, CURRENT_LOG_LEVEL, false)),true);
471

472
        return CURRENT_LOG_LEVEL;
473
    }
474

475
    /** The colon character ":" must not exist inside the tag, otherwise the `logcat` command
476
     * filterspecs arguments `<tag>[:priority]` will not work and will throw `Invalid filter expression`
477
     * error.
478
     * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/logging/liblog/logprint.cpp;l=363
479
     * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/logging/logcat/logcat.cpp;l=884
480
     * */
481
    public static String getFullTag(String tag) {
482
        if (DEFAULT_LOG_TAG.equals(tag))
483
            return tag;
484
        else
485
            return DEFAULT_LOG_TAG + "." + tag;
486
    }
487

488
    public static boolean isLogLevelValid(Integer logLevel) {
489
        return (logLevel != null && logLevel >= LOG_LEVEL_OFF && logLevel <= MAX_LOG_LEVEL);
490
    }
491

492
    /** Check if custom log level is valid and >= {@link #CURRENT_LOG_LEVEL}. If custom log level is
493
     * not valid then {@link #LOG_LEVEL_VERBOSE} must be >= {@link #CURRENT_LOG_LEVEL}. */
494
    public static boolean shouldEnableLoggingForCustomLogLevel(Integer customLogLevel) {
495
        if (CURRENT_LOG_LEVEL <= LOG_LEVEL_OFF) return false;
496
        if (customLogLevel == null) return CURRENT_LOG_LEVEL >= LOG_LEVEL_VERBOSE; // Use default app log level
497
        if (customLogLevel <= LOG_LEVEL_OFF) return false;
498
        customLogLevel = Logger.isLogLevelValid(customLogLevel) ? customLogLevel: Logger.LOG_LEVEL_VERBOSE;
499
        return (customLogLevel >= CURRENT_LOG_LEVEL);
500
    }
501

502
}
503

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.