1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
| final class LoggerPrinter implements Printer {
* Android's max limit for a log entry is ~4076 bytes, * so 4000 bytes is used as chunk size since default charset * is UTF-8 */ private static final int CHUNK_SIZE = 4000; * The minimum stack trace index, starts at this class after two native calls. */ private static final int MIN_STACK_OFFSET = 3; * tag is used for the Log, the name is a little different * in order to differentiate the logs easily with the filter */ private String tag; private final Settings settings = new Settings(); private final ThreadLocal<String> localTag = new ThreadLocal<>(); @Override public void d(Object object) { String message; if (object.getClass().isArray()) { message = Arrays.deepToString((Object[]) object); } else { message = object.toString(); } log(DEBUG, null, message); } * This method is synchronized in order to avoid messy of logs' order. */ private synchronized void log(int priority, Throwable throwable, String msg, Object... args) { if (settings.getLogLevel() == LogLevel.NONE) { return; } String tag = getTag(); String message = createMessage(msg, args); log(priority, tag, message, throwable); } * @return the appropriate tag based on local or global */ private String getTag() { String tag = localTag.get(); if (tag != null) { localTag.remove(); return tag; } return this.tag; } private String createMessage(String message, Object... args) { return args == null || args.length == 0 ? message : String.format(message, args); } @Override public synchronized void log(int priority, String tag, String message, Throwable throwable) { if (settings.getLogLevel() == LogLevel.NONE) { return; } if (throwable != null && message != null) { message += " : " + Helper.getStackTraceString(throwable); } if (throwable != null && message == null) { message = Helper.getStackTraceString(throwable); } if (message == null) { message = "No message/exception is set"; } int methodCount = getMethodCount(); if (Helper.isEmpty(message)) { message = "Empty/NULL log message"; }
logTopBorder(priority, tag); logHeaderContent(priority, tag, methodCount);
byte[] bytes = message.getBytes(); int length = bytes.length; if (length <= CHUNK_SIZE) { if (methodCount > 0) { logDivider(priority, tag); } logContent(priority, tag, message); logBottomBorder(priority, tag); return; } if (methodCount > 0) { logDivider(priority, tag); } for (int i = 0; i < length; i += CHUNK_SIZE) { int count = Math.min(length - i, CHUNK_SIZE); logContent(priority, tag, new String(bytes, i, count)); } logBottomBorder(priority, tag); } @SuppressWarnings("StringBufferReplaceableByString") private void logHeaderContent(int logType, String tag, int methodCount) { StackTraceElement[] trace = Thread.currentThread().getStackTrace(); if (settings.isShowThreadInfo()) { logChunk(logType, tag, HORIZONTAL_DOUBLE_LINE + " Thread: " + Thread.currentThread().getName()); logDivider(logType, tag); } String level = "";
int stackOffset = getStackOffset(trace) + settings.getMethodOffset();
if (methodCount + stackOffset > trace.length) { methodCount = trace.length - stackOffset - 1; }
for (int i = methodCount; i > 0; i--) { int stackIndex = i + stackOffset; if (stackIndex >= trace.length) { continue; } StringBuilder builder = new StringBuilder(); builder.append("║ ") .append(level) .append(getSimpleClassName(trace[stackIndex].getClassName())) .append(".") .append(trace[stackIndex].getMethodName()) .append(" ") .append(" (") .append(trace[stackIndex].getFileName()) .append(":") .append(trace[stackIndex].getLineNumber()) .append(")"); level += " "; logChunk(logType, tag, builder.toString()); } } * 通过chunk界别来通过LogAdapter输出 * * @param logType * @param tag * @param chunk */ private void logChunk(int logType, String tag, String chunk) { String finalTag = formatTag(tag); switch (logType) { case ERROR: settings.getLogAdapter().e(finalTag, chunk); break; case INFO: settings.getLogAdapter().i(finalTag, chunk); break; case VERBOSE: settings.getLogAdapter().v(finalTag, chunk); break; case WARN: settings.getLogAdapter().w(finalTag, chunk); break; case ASSERT: settings.getLogAdapter().wtf(finalTag, chunk); break; case DEBUG: default: settings.getLogAdapter().d(finalTag, chunk); break; } } * 显示分割线 * * @param logType * @param tag */ private void logDivider(int logType, String tag) { logChunk(logType, tag, MIDDLE_BORDER); }
* Determines the starting index of the stack trace, after method calls made by this class. * 找调用堆栈中最外层调用的index * * @param trace the stack trace * @return the stack offset */ private int getStackOffset(StackTraceElement[] trace) { for (int i = MIN_STACK_OFFSET; i < trace.length; i++) { StackTraceElement e = trace[i]; String name = e.getClassName(); if (!name.equals(LoggerPrinter.class.getName()) && !name.equals(Logger.class.getName())) { return --i; } } return -1; } private String getSimpleClassName(String name) { int lastIndex = name.lastIndexOf("."); return name.substring(lastIndex + 1); } private String formatTag(String tag) { if (!Helper.isEmpty(tag) && !Helper.equals(this.tag, tag)) { return this.tag + "-" + tag; } return this.tag; } * 如果对该条log设置了tag,那么进行tag处理 * * @param tag * @return */ private String formatTag(String tag) { if (!Helper.isEmpty(tag) && !Helper.equals(this.tag, tag)) { return this.tag + "-" + tag; } return this.tag; }
* 分行去显示内容 * * @param logType * @param tag * @param chunk */ private void logContent(int logType, String tag, String chunk) { String[] lines = chunk.split(System.getProperty("line.separator")); for (String line : lines) { logChunk(logType, tag, HORIZONTAL_DOUBLE_LINE + " " + line); } } private void logBottomBorder(int logType, String tag) { logChunk(logType, tag, BOTTOM_BORDER); } }
|