├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── encodings.xml
└── vcs.xml
├── .travis.yml
├── LICENSE
├── README.md
├── art
├── how_it_works.png
├── logcat_options.png
├── logger-logo.png
└── logger_output.png
├── build.gradle
├── checkstyle.xml
├── gradle.properties
├── gradle
├── maven_push.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── logger
├── build.gradle
├── gradle.properties
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── orhanobut
│ │ └── logger
│ │ ├── AndroidLogAdapter.java
│ │ ├── CsvFormatStrategy.java
│ │ ├── DiskLogAdapter.java
│ │ ├── DiskLogStrategy.java
│ │ ├── FormatStrategy.java
│ │ ├── LogAdapter.java
│ │ ├── LogStrategy.java
│ │ ├── LogcatLogStrategy.java
│ │ ├── Logger.java
│ │ ├── LoggerPrinter.java
│ │ ├── PrettyFormatStrategy.java
│ │ ├── Printer.java
│ │ └── Utils.java
│ └── test
│ └── java
│ └── com.orhanobut.logger
│ ├── AndroidLogAdapterTest.kt
│ ├── CsvFormatStrategyTest.kt
│ ├── DiskLogAdapterTest.kt
│ ├── DiskLogStrategyTest.kt
│ ├── LogAssert.kt
│ ├── LogcatLogStrategyTest.kt
│ ├── LoggerPrinterTest.kt
│ ├── LoggerTest.kt
│ ├── PrettyFormatStrategyTest.kt
│ └── UtilsTest.kt
├── sample
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── orhanobut
│ │ └── sample
│ │ └── MainActivity.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ └── mipmap-xxxhdpi
│ └── ic_launcher.png
└── settings.gradle
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Please try to fill all questions below before submitting an issue.
2 |
3 | - Android studio version:
4 | - Android gradle plugin version:
5 | - Logger version:
6 | - Emulator/phone information:
7 | - If possible, please add how did you initialize Logger?
8 | - Is it flaky or does it happen all the time?
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | local.properties
2 |
3 | # Generated files
4 | build/
5 |
6 | # Mac store
7 | .DS_Store
8 |
9 | # Gradle files
10 | .gradle/
11 |
12 | /captures
13 |
14 | # Log Files
15 | *.log
16 |
17 | # IDEA/Android Studio
18 | *.iml
19 | *.ipr
20 | *.iws
21 | **/.idea/shelf
22 | **/.idea/workspace.xml
23 | **/.idea/tasks.xml
24 | **/.idea/datasources.xml
25 | **/.idea/dataSources.ids
26 | **/.idea/gradle.xml
27 | **/.idea/misc.xml
28 | **/.idea/modules.xml
29 | **/.idea/libraries
30 | **/.idea/dictionaries
31 | **/.idea/runConfigurations.xml
32 | .idea/caches
33 |
34 | # layout inspector view captures
35 | captures
36 | sample/libs/
37 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orhanobut/logger/c64a72c2ce3d0fcdebe829b091e3a530c94ca6bd/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/orhanobut/logger)
3 |
4 |
5 |
6 | ### Logger
7 | Simple, pretty and powerful logger for android
8 |
9 | ### Setup
10 | Download
11 | ```groovy
12 | implementation 'com.orhanobut:logger:2.2.0'
13 | ```
14 |
15 | Initialize
16 | ```java
17 | Logger.addLogAdapter(new AndroidLogAdapter());
18 | ```
19 | And use
20 | ```java
21 | Logger.d("hello");
22 | ```
23 |
24 | ### Output
25 |
26 |
27 |
28 | ### Options
29 | ```java
30 | Logger.d("debug");
31 | Logger.e("error");
32 | Logger.w("warning");
33 | Logger.v("verbose");
34 | Logger.i("information");
35 | Logger.wtf("What a Terrible Failure");
36 | ```
37 |
38 | String format arguments are supported
39 | ```java
40 | Logger.d("hello %s", "world");
41 | ```
42 |
43 | Collections are supported (only available for debug logs)
44 | ```java
45 | Logger.d(MAP);
46 | Logger.d(SET);
47 | Logger.d(LIST);
48 | Logger.d(ARRAY);
49 | ```
50 |
51 | Json and Xml support (output will be in debug level)
52 | ```java
53 | Logger.json(JSON_CONTENT);
54 | Logger.xml(XML_CONTENT);
55 | ```
56 |
57 | ### Advanced
58 | ```java
59 | FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
60 | .showThreadInfo(false) // (Optional) Whether to show thread info or not. Default true
61 | .methodCount(0) // (Optional) How many method line to show. Default 2
62 | .methodOffset(7) // (Optional) Hides internal method calls up to offset. Default 5
63 | .logStrategy(customLog) // (Optional) Changes the log strategy to print out. Default LogCat
64 | .tag("My custom tag") // (Optional) Global tag for every log. Default PRETTY_LOGGER
65 | .build();
66 |
67 | Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));
68 | ```
69 |
70 | ### Loggable
71 | Log adapter checks whether the log should be printed or not by checking this function.
72 | If you want to disable/hide logs for output, override `isLoggable` method.
73 | `true` will print the log message, `false` will ignore it.
74 | ```java
75 | Logger.addLogAdapter(new AndroidLogAdapter() {
76 | @Override public boolean isLoggable(int priority, String tag) {
77 | return BuildConfig.DEBUG;
78 | }
79 | });
80 | ```
81 |
82 | ### Save logs to the file
83 | //TODO: More information will be added later
84 | ```java
85 | Logger.addLogAdapter(new DiskLogAdapter());
86 | ```
87 |
88 | Add custom tag to Csv format strategy
89 | ```java
90 | FormatStrategy formatStrategy = CsvFormatStrategy.newBuilder()
91 | .tag("custom")
92 | .build();
93 |
94 | Logger.addLogAdapter(new DiskLogAdapter(formatStrategy));
95 | ```
96 |
97 | ### How it works
98 |
99 |
100 |
101 | ### More
102 | - Use filter for a better result. PRETTY_LOGGER or your custom tag
103 | - Make sure that wrap option is disabled
104 | - You can also simplify output by changing settings.
105 |
106 |
107 |
108 | - Timber Integration
109 | ```java
110 | // Set methodOffset to 5 in order to hide internal method calls
111 | Timber.plant(new Timber.DebugTree() {
112 | @Override protected void log(int priority, String tag, String message, Throwable t) {
113 | Logger.log(priority, tag, message, t);
114 | }
115 | });
116 | ```
117 |
118 | ### License
119 |
120 | Copyright 2018 Orhan Obut 121 | 122 | Licensed under the Apache License, Version 2.0 (the "License"); 123 | you may not use this file except in compliance with the License. 124 | You may obtain a copy of the License at 125 | 126 | http://www.apache.org/licenses/LICENSE-2.0 127 | 128 | Unless required by applicable law or agreed to in writing, software 129 | distributed under the License is distributed on an "AS IS" BASIS, 130 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131 | See the License for the specific language governing permissions and 132 | limitations under the License. 133 |134 | -------------------------------------------------------------------------------- /art/how_it_works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orhanobut/logger/c64a72c2ce3d0fcdebe829b091e3a530c94ca6bd/art/how_it_works.png -------------------------------------------------------------------------------- /art/logcat_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orhanobut/logger/c64a72c2ce3d0fcdebe829b091e3a530c94ca6bd/art/logcat_options.png -------------------------------------------------------------------------------- /art/logger-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orhanobut/logger/c64a72c2ce3d0fcdebe829b091e3a530c94ca6bd/art/logger-logo.png -------------------------------------------------------------------------------- /art/logger_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orhanobut/logger/c64a72c2ce3d0fcdebe829b091e3a530c94ca6bd/art/logger_output.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlinVersion = '1.2.51' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.0' 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | jcenter() 17 | } 18 | } 19 | 20 | subprojects { project -> 21 | group = GROUP 22 | version = VERSION_NAME 23 | 24 | apply plugin: 'checkstyle' 25 | 26 | task checkstyle(type: Checkstyle) { 27 | configFile rootProject.file('checkstyle.xml') 28 | source 'src/main/java' 29 | ignoreFailures false 30 | showViolations true 31 | include '**/*.java' 32 | 33 | classpath = files() 34 | } 35 | 36 | afterEvaluate { 37 | if (project.tasks.findByName('check')) { 38 | check.dependsOn('checkstyle') 39 | } 40 | } 41 | } 42 | 43 | task clean(type: Delete) { 44 | delete rootProject.buildDir 45 | } 46 | 47 | ext { 48 | minSdkVersion = 8 49 | targetSdkVersion = 28 50 | compileSdkVersion = 28 51 | buildToolsVersion = '28.0.2' 52 | } 53 | 54 | ext.deps = [ 55 | junit : 'junit:junit:4.12', 56 | truth : 'com.google.truth:truth:0.28', 57 | robolectric : 'org.robolectric:robolectric:3.3', 58 | mockito : "org.mockito:mockito-core:2.8.9", 59 | json : "org.json:json:20160810", 60 | supportAnnotations: 'androidx.annotation:annotation:1.0.0', 61 | kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" 62 | ] -------------------------------------------------------------------------------- /checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 |
14 | * ┌────────────────────────── 15 | * │ Method stack history 16 | * ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 17 | * │ Log message 18 | * └────────────────────────── 19 | *20 | */ 21 | public class AndroidLogAdapter implements LogAdapter { 22 | 23 | @NonNull private final FormatStrategy formatStrategy; 24 | 25 | public AndroidLogAdapter() { 26 | this.formatStrategy = PrettyFormatStrategy.newBuilder().build(); 27 | } 28 | 29 | public AndroidLogAdapter(@NonNull FormatStrategy formatStrategy) { 30 | this.formatStrategy = checkNotNull(formatStrategy); 31 | } 32 | 33 | @Override public boolean isLoggable(int priority, @Nullable String tag) { 34 | return true; 35 | } 36 | 37 | @Override public void log(int priority, @Nullable String tag, @NonNull String message) { 38 | formatStrategy.log(priority, tag, message); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /logger/src/main/java/com/orhanobut/logger/CsvFormatStrategy.java: -------------------------------------------------------------------------------- 1 | package com.orhanobut.logger; 2 | 3 | import android.os.Environment; 4 | import android.os.Handler; 5 | import android.os.HandlerThread; 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import java.io.File; 10 | import java.text.SimpleDateFormat; 11 | import java.util.Date; 12 | import java.util.Locale; 13 | 14 | import static com.orhanobut.logger.Utils.checkNotNull; 15 | 16 | /** 17 | * CSV formatted file logging for Android. 18 | * Writes to CSV the following data: 19 | * epoch timestamp, ISO8601 timestamp (human-readable), log level, tag, log message. 20 | */ 21 | public class CsvFormatStrategy implements FormatStrategy { 22 | 23 | private static final String NEW_LINE = System.getProperty("line.separator"); 24 | private static final String NEW_LINE_REPLACEMENT = "
10 | * ┌──────────────────────────────────────────── 11 | * │ LOGGER 12 | * ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 13 | * │ Standard logging mechanism 14 | * ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 15 | * │ But more pretty, simple and powerful 16 | * └──────────────────────────────────────────── 17 | *18 | * 19 | *
22 | * Logger.addLogAdapter(new AndroidLogAdapter());
23 | *
24 | *
25 | * And use the appropriate static Logger methods.
26 | *
27 | *
28 | * Logger.d("debug");
29 | * Logger.e("error");
30 | * Logger.w("warning");
31 | * Logger.v("verbose");
32 | * Logger.i("information");
33 | * Logger.wtf("What a Terrible Failure");
34 | *
35 | *
36 | *
38 | * Logger.d("hello %s", "world");
39 | *
40 | *
41 | *
43 | * Logger.d(MAP);
44 | * Logger.d(SET);
45 | * Logger.d(LIST);
46 | * Logger.d(ARRAY);
47 | *
48 | *
49 | *
51 | * Logger.json(JSON_CONTENT);
52 | * Logger.xml(XML_CONTENT);
53 | *
54 | *
55 | * 17 | * ┌────────────────────────── 18 | * │ Method stack history 19 | * ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 20 | * │ Thread information 21 | * ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 22 | * │ Log message 23 | * └────────────────────────── 24 | *25 | * 26 | *
28 | * FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
29 | * .showThreadInfo(false) // (Optional) Whether to show thread info or not. Default true
30 | * .methodCount(0) // (Optional) How many method line to show. Default 2
31 | * .methodOffset(7) // (Optional) Hides internal method calls up to offset. Default 5
32 | * .logStrategy(customLog) // (Optional) Changes the log strategy to print out. Default LogCat
33 | * .tag("My custom tag") // (Optional) Global tag for every log. Default PRETTY_LOGGER
34 | * .build();
35 | *
36 | */
37 | public class PrettyFormatStrategy implements FormatStrategy {
38 |
39 | /**
40 | * Android's max limit for a log entry is ~4076 bytes,
41 | * so 4000 bytes is used as chunk size since default charset
42 | * is UTF-8
43 | */
44 | private static final int CHUNK_SIZE = 4000;
45 |
46 | /**
47 | * The minimum stack trace index, starts at this class after two native calls.
48 | */
49 | private static final int MIN_STACK_OFFSET = 5;
50 |
51 | /**
52 | * Drawing toolbox
53 | */
54 | private static final char TOP_LEFT_CORNER = '┌';
55 | private static final char BOTTOM_LEFT_CORNER = '└';
56 | private static final char MIDDLE_CORNER = '├';
57 | private static final char HORIZONTAL_LINE = '│';
58 | private static final String DOUBLE_DIVIDER = "────────────────────────────────────────────────────────";
59 | private static final String SINGLE_DIVIDER = "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄";
60 | private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
61 | private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
62 | private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;
63 |
64 | private final int methodCount;
65 | private final int methodOffset;
66 | private final boolean showThreadInfo;
67 | @NonNull private final LogStrategy logStrategy;
68 | @Nullable private final String tag;
69 |
70 | private PrettyFormatStrategy(@NonNull Builder builder) {
71 | checkNotNull(builder);
72 |
73 | methodCount = builder.methodCount;
74 | methodOffset = builder.methodOffset;
75 | showThreadInfo = builder.showThreadInfo;
76 | logStrategy = builder.logStrategy;
77 | tag = builder.tag;
78 | }
79 |
80 | @NonNull public static Builder newBuilder() {
81 | return new Builder();
82 | }
83 |
84 | @Override public void log(int priority, @Nullable String onceOnlyTag, @NonNull String message) {
85 | checkNotNull(message);
86 |
87 | String tag = formatTag(onceOnlyTag);
88 |
89 | logTopBorder(priority, tag);
90 | logHeaderContent(priority, tag, methodCount);
91 |
92 | //get bytes of message with system's default charset (which is UTF-8 for Android)
93 | byte[] bytes = message.getBytes();
94 | int length = bytes.length;
95 | if (length <= CHUNK_SIZE) {
96 | if (methodCount > 0) {
97 | logDivider(priority, tag);
98 | }
99 | logContent(priority, tag, message);
100 | logBottomBorder(priority, tag);
101 | return;
102 | }
103 | if (methodCount > 0) {
104 | logDivider(priority, tag);
105 | }
106 | for (int i = 0; i < length; i += CHUNK_SIZE) {
107 | int count = Math.min(length - i, CHUNK_SIZE);
108 | //create a new String with system's default charset (which is UTF-8 for Android)
109 | logContent(priority, tag, new String(bytes, i, count));
110 | }
111 | logBottomBorder(priority, tag);
112 | }
113 |
114 | private void logTopBorder(int logType, @Nullable String tag) {
115 | logChunk(logType, tag, TOP_BORDER);
116 | }
117 |
118 | @SuppressWarnings("StringBufferReplaceableByString")
119 | private void logHeaderContent(int logType, @Nullable String tag, int methodCount) {
120 | StackTraceElement[] trace = Thread.currentThread().getStackTrace();
121 | if (showThreadInfo) {
122 | logChunk(logType, tag, HORIZONTAL_LINE + " Thread: " + Thread.currentThread().getName());
123 | logDivider(logType, tag);
124 | }
125 | String level = "";
126 |
127 | int stackOffset = getStackOffset(trace) + methodOffset;
128 |
129 | //corresponding method count with the current stack may exceeds the stack trace. Trims the count
130 | if (methodCount + stackOffset > trace.length) {
131 | methodCount = trace.length - stackOffset - 1;
132 | }
133 |
134 | for (int i = methodCount; i > 0; i--) {
135 | int stackIndex = i + stackOffset;
136 | if (stackIndex >= trace.length) {
137 | continue;
138 | }
139 | StringBuilder builder = new StringBuilder();
140 | builder.append(HORIZONTAL_LINE)
141 | .append(' ')
142 | .append(level)
143 | .append(getSimpleClassName(trace[stackIndex].getClassName()))
144 | .append(".")
145 | .append(trace[stackIndex].getMethodName())
146 | .append(" ")
147 | .append(" (")
148 | .append(trace[stackIndex].getFileName())
149 | .append(":")
150 | .append(trace[stackIndex].getLineNumber())
151 | .append(")");
152 | level += " ";
153 | logChunk(logType, tag, builder.toString());
154 | }
155 | }
156 |
157 | private void logBottomBorder(int logType, @Nullable String tag) {
158 | logChunk(logType, tag, BOTTOM_BORDER);
159 | }
160 |
161 | private void logDivider(int logType, @Nullable String tag) {
162 | logChunk(logType, tag, MIDDLE_BORDER);
163 | }
164 |
165 | private void logContent(int logType, @Nullable String tag, @NonNull String chunk) {
166 | checkNotNull(chunk);
167 |
168 | String[] lines = chunk.split(System.getProperty("line.separator"));
169 | for (String line : lines) {
170 | logChunk(logType, tag, HORIZONTAL_LINE + " " + line);
171 | }
172 | }
173 |
174 | private void logChunk(int priority, @Nullable String tag, @NonNull String chunk) {
175 | checkNotNull(chunk);
176 |
177 | logStrategy.log(priority, tag, chunk);
178 | }
179 |
180 | private String getSimpleClassName(@NonNull String name) {
181 | checkNotNull(name);
182 |
183 | int lastIndex = name.lastIndexOf(".");
184 | return name.substring(lastIndex + 1);
185 | }
186 |
187 | /**
188 | * Determines the starting index of the stack trace, after method calls made by this class.
189 | *
190 | * @param trace the stack trace
191 | * @return the stack offset
192 | */
193 | private int getStackOffset(@NonNull StackTraceElement[] trace) {
194 | checkNotNull(trace);
195 |
196 | for (int i = MIN_STACK_OFFSET; i < trace.length; i++) {
197 | StackTraceElement e = trace[i];
198 | String name = e.getClassName();
199 | if (!name.equals(LoggerPrinter.class.getName()) && !name.equals(Logger.class.getName())) {
200 | return --i;
201 | }
202 | }
203 | return -1;
204 | }
205 |
206 | @Nullable private String formatTag(@Nullable String tag) {
207 | if (!Utils.isEmpty(tag) && !Utils.equals(this.tag, tag)) {
208 | return this.tag + "-" + tag;
209 | }
210 | return this.tag;
211 | }
212 |
213 | public static class Builder {
214 | int methodCount = 2;
215 | int methodOffset = 0;
216 | boolean showThreadInfo = true;
217 | @Nullable LogStrategy logStrategy;
218 | @Nullable String tag = "PRETTY_LOGGER";
219 |
220 | private Builder() {
221 | }
222 |
223 | @NonNull public Builder methodCount(int val) {
224 | methodCount = val;
225 | return this;
226 | }
227 |
228 | @NonNull public Builder methodOffset(int val) {
229 | methodOffset = val;
230 | return this;
231 | }
232 |
233 | @NonNull public Builder showThreadInfo(boolean val) {
234 | showThreadInfo = val;
235 | return this;
236 | }
237 |
238 | @NonNull public Builder logStrategy(@Nullable LogStrategy val) {
239 | logStrategy = val;
240 | return this;
241 | }
242 |
243 | @NonNull public Builder tag(@Nullable String tag) {
244 | this.tag = tag;
245 | return this;
246 | }
247 |
248 | @NonNull public PrettyFormatStrategy build() {
249 | if (logStrategy == null) {
250 | logStrategy = new LogcatLogStrategy();
251 | }
252 | return new PrettyFormatStrategy(this);
253 | }
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------
/logger/src/main/java/com/orhanobut/logger/Printer.java:
--------------------------------------------------------------------------------
1 | package com.orhanobut.logger;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | /**
7 | * A proxy interface to enable additional operations.
8 | * Contains all possible Log message usages.
9 | */
10 | public interface Printer {
11 |
12 | void addAdapter(@NonNull LogAdapter adapter);
13 |
14 | Printer t(@Nullable String tag);
15 |
16 | void d(@NonNull String message, @Nullable Object... args);
17 |
18 | void d(@Nullable Object object);
19 |
20 | void e(@NonNull String message, @Nullable Object... args);
21 |
22 | void e(@Nullable Throwable throwable, @NonNull String message, @Nullable Object... args);
23 |
24 | void w(@NonNull String message, @Nullable Object... args);
25 |
26 | void i(@NonNull String message, @Nullable Object... args);
27 |
28 | void v(@NonNull String message, @Nullable Object... args);
29 |
30 | void wtf(@NonNull String message, @Nullable Object... args);
31 |
32 | /**
33 | * Formats the given json content and print it
34 | */
35 | void json(@Nullable String json);
36 |
37 | /**
38 | * Formats the given xml content and print it
39 | */
40 | void xml(@Nullable String xml);
41 |
42 | void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable throwable);
43 |
44 | void clearLogAdapters();
45 | }
46 |
--------------------------------------------------------------------------------
/logger/src/main/java/com/orhanobut/logger/Utils.java:
--------------------------------------------------------------------------------
1 | package com.orhanobut.logger;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import java.io.PrintWriter;
7 | import java.io.StringWriter;
8 | import java.net.UnknownHostException;
9 | import java.util.Arrays;
10 |
11 | import static com.orhanobut.logger.Logger.ASSERT;
12 | import static com.orhanobut.logger.Logger.DEBUG;
13 | import static com.orhanobut.logger.Logger.ERROR;
14 | import static com.orhanobut.logger.Logger.INFO;
15 | import static com.orhanobut.logger.Logger.VERBOSE;
16 | import static com.orhanobut.logger.Logger.WARN;
17 |
18 | /**
19 | * Provides convenient methods to some common operations
20 | */
21 | final class Utils {
22 |
23 | private Utils() {
24 | // Hidden constructor.
25 | }
26 |
27 | /**
28 | * Returns true if the string is null or 0-length.
29 | *
30 | * @param str the string to be examined
31 | * @return true if str is null or zero length
32 | */
33 | static boolean isEmpty(CharSequence str) {
34 | return str == null || str.length() == 0;
35 | }
36 |
37 | /**
38 | * Returns true if a and b are equal, including if they are both null.
39 | * Note: In platform versions 1.1 and earlier, this method only worked well if 40 | * both the arguments were instances of String.
41 | * 42 | * @param a first CharSequence to check 43 | * @param b second CharSequence to check 44 | * @return true if a and b are equal 45 | *
46 | * NOTE: Logic slightly change due to strict policy on CI -
47 | * "Inner assignments should be avoided"
48 | */
49 | static boolean equals(CharSequence a, CharSequence b) {
50 | if (a == b) return true;
51 | if (a != null && b != null) {
52 | int length = a.length();
53 | if (length == b.length()) {
54 | if (a instanceof String && b instanceof String) {
55 | return a.equals(b);
56 | } else {
57 | for (int i = 0; i < length; i++) {
58 | if (a.charAt(i) != b.charAt(i)) return false;
59 | }
60 | return true;
61 | }
62 | }
63 | }
64 | return false;
65 | }
66 |
67 | /**
68 | * Copied from "android.util.Log.getStackTraceString()" in order to avoid usage of Android stack
69 | * in unit tests.
70 | *
71 | * @return Stack trace in form of String
72 | */
73 | static String getStackTraceString(Throwable tr) {
74 | if (tr == null) {
75 | return "";
76 | }
77 |
78 | // This is to reduce the amount of log spew that apps do in the non-error
79 | // condition of the network being unavailable.
80 | Throwable t = tr;
81 | while (t != null) {
82 | if (t instanceof UnknownHostException) {
83 | return "";
84 | }
85 | t = t.getCause();
86 | }
87 |
88 | StringWriter sw = new StringWriter();
89 | PrintWriter pw = new PrintWriter(sw);
90 | tr.printStackTrace(pw);
91 | pw.flush();
92 | return sw.toString();
93 | }
94 |
95 | static String logLevel(int value) {
96 | switch (value) {
97 | case VERBOSE:
98 | return "VERBOSE";
99 | case DEBUG:
100 | return "DEBUG";
101 | case INFO:
102 | return "INFO";
103 | case WARN:
104 | return "WARN";
105 | case ERROR:
106 | return "ERROR";
107 | case ASSERT:
108 | return "ASSERT";
109 | default:
110 | return "UNKNOWN";
111 | }
112 | }
113 |
114 | public static String toString(Object object) {
115 | if (object == null) {
116 | return "null";
117 | }
118 | if (!object.getClass().isArray()) {
119 | return object.toString();
120 | }
121 | if (object instanceof boolean[]) {
122 | return Arrays.toString((boolean[]) object);
123 | }
124 | if (object instanceof byte[]) {
125 | return Arrays.toString((byte[]) object);
126 | }
127 | if (object instanceof char[]) {
128 | return Arrays.toString((char[]) object);
129 | }
130 | if (object instanceof short[]) {
131 | return Arrays.toString((short[]) object);
132 | }
133 | if (object instanceof int[]) {
134 | return Arrays.toString((int[]) object);
135 | }
136 | if (object instanceof long[]) {
137 | return Arrays.toString((long[]) object);
138 | }
139 | if (object instanceof float[]) {
140 | return Arrays.toString((float[]) object);
141 | }
142 | if (object instanceof double[]) {
143 | return Arrays.toString((double[]) object);
144 | }
145 | if (object instanceof Object[]) {
146 | return Arrays.deepToString((Object[]) object);
147 | }
148 | return "Couldn't find a correct type for the object";
149 | }
150 |
151 | @NonNull static