|
@@ -0,0 +1,665 @@
|
|
|
+package com.common.lib_base.utils.log;
|
|
|
+
|
|
|
+import android.annotation.SuppressLint;
|
|
|
+import android.os.Build;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import androidx.annotation.IntDef;
|
|
|
+import androidx.annotation.IntRange;
|
|
|
+
|
|
|
+import com.blankj.utilcode.util.FileIOUtils;
|
|
|
+import com.blankj.utilcode.util.FileUtils;
|
|
|
+import com.blankj.utilcode.util.PathUtils;
|
|
|
+import com.common.lib_base.BuildConfig;
|
|
|
+import com.common.lib_base.CommonApplication;
|
|
|
+import com.google.gson.Gson;
|
|
|
+import com.google.gson.GsonBuilder;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
+
|
|
|
+import org.json.JSONArray;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.StringReader;
|
|
|
+import java.io.StringWriter;
|
|
|
+import java.lang.annotation.Retention;
|
|
|
+import java.lang.annotation.RetentionPolicy;
|
|
|
+import java.text.Format;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Calendar;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Formatter;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+import javax.xml.transform.OutputKeys;
|
|
|
+import javax.xml.transform.Source;
|
|
|
+import javax.xml.transform.Transformer;
|
|
|
+import javax.xml.transform.TransformerFactory;
|
|
|
+import javax.xml.transform.stream.StreamResult;
|
|
|
+import javax.xml.transform.stream.StreamSource;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <pre>
|
|
|
+ * @author yangchong
|
|
|
+ * blog :
|
|
|
+ * time : 2018/07/2
|
|
|
+ * desc : Log 相关工具类
|
|
|
+ * revise:
|
|
|
+ * </pre>
|
|
|
+ */
|
|
|
+public final class CommonLogUtils {
|
|
|
+
|
|
|
+ /*
|
|
|
+ getConfig : 获取 log 配置
|
|
|
+ Config.setLogSwitch : 设置 log 总开关
|
|
|
+ Config.setConsoleSwitch : 设置 log 控制台开关
|
|
|
+ Config.setGlobalTag : 设置 log 全局 tag
|
|
|
+ Config.setLogHeadSwitch : 设置 log 头部信息开关
|
|
|
+ Config.setLog2FileSwitch : 设置 log 文件开关
|
|
|
+ Config.setDir : 设置 log 文件存储目录
|
|
|
+ Config.setFilePrefix : 设置 log 文件前缀
|
|
|
+ Config.setBorderSwitch : 设置 log 边框开关
|
|
|
+ Config.setSingleTagSwitch: 设置 log 单一 tag 开关(为美化 AS 3.1 的 Logcat)
|
|
|
+ Config.setConsoleFilter : 设置 log 控制台过滤器
|
|
|
+ Config.setFileFilter : 设置 log 文件过滤器
|
|
|
+ Config.setStackDeep : 设置 log 栈深度
|
|
|
+ Config.setStackOffset : 设置 log 栈偏移
|
|
|
+ log : 自定义 tag 的 type 日志
|
|
|
+ v : tag 为类名的 Verbose 日志
|
|
|
+ vTag : 自定义 tag 的 Verbose 日志
|
|
|
+ d : tag 为类名的 Debug 日志
|
|
|
+ dTag : 自定义 tag 的 Debug 日志
|
|
|
+ i : tag 为类名的 Info 日志
|
|
|
+ iTag : 自定义 tag 的 Info 日志
|
|
|
+ w : tag 为类名的 Warn 日志
|
|
|
+ wTag : 自定义 tag 的 Warn 日志
|
|
|
+ e : tag 为类名的 Error 日志
|
|
|
+ eTag : 自定义 tag 的 Error 日志
|
|
|
+ a : tag 为类名的 Assert 日志
|
|
|
+ aTag : 自定义 tag 的 Assert 日志
|
|
|
+ file : log 到文件
|
|
|
+ json : log 字符串之 json
|
|
|
+ xml : log 字符串之 xml
|
|
|
+ */
|
|
|
+
|
|
|
+ public static final int V = Log.VERBOSE;
|
|
|
+ public static final int D = Log.DEBUG;
|
|
|
+ public static final int I = Log.INFO;
|
|
|
+ public static final int W = Log.WARN;
|
|
|
+ public static final int E = Log.ERROR;
|
|
|
+
|
|
|
+ @IntDef({V, D, I, W, E})
|
|
|
+ @Retention(RetentionPolicy.SOURCE)
|
|
|
+ private @interface TYPE {
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final char[] T = new char[]{'V', 'D', 'I', 'W', 'E', 'A'};
|
|
|
+
|
|
|
+ private static final int FILE = 0x10;
|
|
|
+ private static final int JSON = 0x20;
|
|
|
+ private static final int XML = 0x30;
|
|
|
+
|
|
|
+ private static final String FILE_SEP = System.getProperty("file.separator");
|
|
|
+ // 换行符,功能和"\n"是一致的,但是此种写法屏蔽了 Windows和Linux的区别 ,更保险一些
|
|
|
+ private static final String LINE_SEP = System.getProperty("line.separator");
|
|
|
+ private static final String TOP_CORNER = "┌";
|
|
|
+ private static final String MIDDLE_CORNER = "├";
|
|
|
+ private static final String LEFT_BORDER = "│ ";
|
|
|
+ private static final String BOTTOM_CORNER = "└";
|
|
|
+ private static final String SIDE_DIVIDER = "────────────────────────────────────────────────────────";
|
|
|
+ private static final String MIDDLE_DIVIDER = "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄";
|
|
|
+ private static final String TOP_BORDER = TOP_CORNER + SIDE_DIVIDER + SIDE_DIVIDER;
|
|
|
+ private static final String MIDDLE_BORDER = MIDDLE_CORNER + MIDDLE_DIVIDER + MIDDLE_DIVIDER;
|
|
|
+ private static final String BOTTOM_BORDER = BOTTOM_CORNER + SIDE_DIVIDER + SIDE_DIVIDER;
|
|
|
+ private static final int MAX_LEN = 4000;
|
|
|
+ @SuppressLint("SimpleDateFormat")
|
|
|
+ private static final Format FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ");
|
|
|
+ private static final String NOTHING = "log nothing";
|
|
|
+ private static final String NULL = BuildConfig.LOG_TAG;
|
|
|
+ private static final String ARGS = "args";
|
|
|
+ private static final Config CONFIG = new Config();
|
|
|
+
|
|
|
+ private static String sDefaultDir;// log 默认存储目录
|
|
|
+ private static String sDir; // log 存储目录
|
|
|
+ private static String sFilePrefix = "hwmcLog";// log 文件前缀
|
|
|
+ private static boolean sLogSwitch = true; // log 总开关,默认开
|
|
|
+ private static boolean sLog2ConsoleSwitch = true; // logcat 是否打印,默认打印
|
|
|
+ private static String sGlobalTag = BuildConfig.LOG_TAG; // log 标签
|
|
|
+ private static boolean sTagIsSpace = true; // log 标签是否为空白
|
|
|
+ private static boolean sLogHeadSwitch = true; // log 头部开关,默认开
|
|
|
+ private static boolean sLog2FileSwitch = false; // log 写入文件开关,默认关
|
|
|
+ private static boolean sLogBorderSwitch = true; // log 边框开关,默认开
|
|
|
+ private static int sConsoleFilter = V; // log 控制台过滤器
|
|
|
+ private static int sFileFilter = V; // log 文件过滤器
|
|
|
+ private static int sStackDeep = 1; // log 栈深度
|
|
|
+
|
|
|
+ private CommonLogUtils() {
|
|
|
+ throw new UnsupportedOperationException("u can't instantiate me...");
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Config getConfig() {
|
|
|
+ return CONFIG;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void v(final Object... contents) {
|
|
|
+ log(V, sGlobalTag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void vTag(final String tag, final Object... contents) {
|
|
|
+ log(V, tag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void d(final Object... contents) {
|
|
|
+ log(D, sGlobalTag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void dTag(final String tag, final Object... contents) {
|
|
|
+ log(D, tag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void i(final Object... contents) {
|
|
|
+ log(I, sGlobalTag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void iTag(final String tag, final Object... contents) {
|
|
|
+ log(I, tag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void w(final Object... contents) {
|
|
|
+ log(W, sGlobalTag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void wTag(final String tag, final Object... contents) {
|
|
|
+ log(W, tag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void e(final Object... contents) {
|
|
|
+ log(E, sGlobalTag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void eTag(final String tag, final Object... contents) {
|
|
|
+ log(E, tag, contents);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void file(final Object content) {
|
|
|
+ log(FILE | D, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void file(@TYPE final int type, final Object content) {
|
|
|
+ log(FILE | type, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void file(final String tag, final Object content) {
|
|
|
+ log(FILE | D, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void file(@TYPE final int type, final String tag, final Object content) {
|
|
|
+ log(FILE | type, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void json(final String content) {
|
|
|
+ log(JSON | D, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void json(@TYPE final int type, final String content) {
|
|
|
+ log(JSON | type, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void json(final String tag, final String content) {
|
|
|
+ log(JSON | D, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void json(@TYPE final int type, final String tag, final String content) {
|
|
|
+ log(JSON | type, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void xml(final String content) {
|
|
|
+ log(XML | D, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void xml(@TYPE final int type, final String content) {
|
|
|
+ log(XML | type, sGlobalTag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void xml(final String tag, final String content) {
|
|
|
+ log(XML | D, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void xml(@TYPE final int type, final String tag, final String content) {
|
|
|
+ log(XML | type, tag, content);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void log(final int type, final String tag, final Object... contents) {
|
|
|
+ if (!sLogSwitch || (!sLog2ConsoleSwitch && !sLog2FileSwitch)) return;
|
|
|
+ int type_low = type & 0x0f, type_high = type & 0xf0;
|
|
|
+ if (type_low < sConsoleFilter && type_low < sFileFilter) return;
|
|
|
+ final TagHead tagHead = processTagAndHead(tag);
|
|
|
+// Log.e("TEST", "tagHead--" + tagHead.toString());
|
|
|
+ String body = processBody(type_high, contents);
|
|
|
+// Log.e("TEST", "body--" + body.toString());
|
|
|
+ if (sLog2ConsoleSwitch && type_low >= sConsoleFilter && type_high != FILE) {
|
|
|
+ print2Console(type_low, tagHead.tag, tagHead.consoleHead, body);
|
|
|
+ }
|
|
|
+ if ((sLog2FileSwitch || type_high == FILE) && type_low >= sFileFilter) {
|
|
|
+// print2File(type_low, tagHead.tag, tagHead.fileHead + body);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static TagHead processTagAndHead(String tag) {
|
|
|
+ if (!sTagIsSpace && !sLogHeadSwitch) {
|
|
|
+ tag = sGlobalTag;
|
|
|
+ } else {
|
|
|
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
|
|
|
+ StackTraceElement targetElement = stackTrace[3];
|
|
|
+ String methodName = targetElement.getMethodName();
|
|
|
+// Log.e("TEST", "methodName--"+methodName);
|
|
|
+ String fileName = targetElement.getFileName();
|
|
|
+// Log.e("TEST", "fileName--"+fileName);
|
|
|
+ String className;
|
|
|
+ // 混淆可能会导致获取为空 加-keepattributes SourceFile,LineNumberTable
|
|
|
+ if (fileName == null) {
|
|
|
+ className = targetElement.getClassName();
|
|
|
+ String[] classNameInfo = className.split("\\.");
|
|
|
+ if (classNameInfo.length > 0) {
|
|
|
+ className = classNameInfo[classNameInfo.length - 1];
|
|
|
+ }
|
|
|
+ int index = className.indexOf('$');
|
|
|
+ if (index != -1) {
|
|
|
+ className = className.substring(0, index);
|
|
|
+ }
|
|
|
+ fileName = className + ".java";
|
|
|
+ } else {
|
|
|
+ int index = fileName.indexOf('.');// 混淆可能导致文件名被改变从而找不到"."
|
|
|
+ className = index == -1 ? fileName : fileName.substring(0, index);
|
|
|
+ }
|
|
|
+ if (sTagIsSpace) tag = isSpace(tag) ? className : tag;
|
|
|
+ if (sLogHeadSwitch) {
|
|
|
+ String tName = Thread.currentThread().getName();
|
|
|
+ final String head = new Formatter()
|
|
|
+ .format("%s, %s(%s:%d)",
|
|
|
+ tName,
|
|
|
+ targetElement.getMethodName(),
|
|
|
+ fileName,
|
|
|
+ targetElement.getLineNumber())
|
|
|
+ .toString();
|
|
|
+ final String fileHead = " [" + head + "]: ";
|
|
|
+ if (sStackDeep <= 1) {
|
|
|
+// Log.e("TEST", "sStackDeep-<= 1");
|
|
|
+ return new TagHead(tag, new String[]{head}, fileHead);
|
|
|
+ } else {
|
|
|
+// Log.e("TEST", "sStackDeep-> 1");
|
|
|
+ final String[] consoleHead =
|
|
|
+ new String[Math.min(sStackDeep, stackTrace.length - 3)];
|
|
|
+ consoleHead[0] = head;
|
|
|
+ int spaceLen = tName.length() + 2;
|
|
|
+ String space = new Formatter().format("%" + spaceLen + "s", "").toString();
|
|
|
+ for (int i = 1, len = consoleHead.length; i < len; ++i) {
|
|
|
+ targetElement = stackTrace[i + 3];
|
|
|
+ consoleHead[i] = new Formatter()
|
|
|
+ .format("%s%s(%s:%d)",
|
|
|
+ space,
|
|
|
+ targetElement.getMethodName(),
|
|
|
+ targetElement.getFileName(),
|
|
|
+ targetElement.getLineNumber())
|
|
|
+ .toString();
|
|
|
+
|
|
|
+// Log.e("TEST", "MethodName--" + targetElement.getMethodName());
|
|
|
+
|
|
|
+ }
|
|
|
+// Log.e("TEST", "tag--" + tag);
|
|
|
+// Log.e("TEST", "consoleHead--" + consoleHead);
|
|
|
+// Log.e("TEST", "fileHead--" + fileHead);
|
|
|
+ return new TagHead(tag, consoleHead, fileHead);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return new TagHead(tag, null, ": ");
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String processBody(final int type, final Object... contents) {
|
|
|
+ String body = NULL;
|
|
|
+ if (contents != null) {
|
|
|
+ if (contents.length == 1) {
|
|
|
+ Object object = contents[0];
|
|
|
+ if (object != null) body = object.toString();
|
|
|
+ if (type == JSON) {
|
|
|
+ body = formatJson(body);
|
|
|
+ } else if (type == XML) {
|
|
|
+ body = formatXml(body);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (int i = 0, len = contents.length; i < len; ++i) {
|
|
|
+ Object content = contents[i];
|
|
|
+ sb.append(ARGS)
|
|
|
+ .append("[")
|
|
|
+ .append(i)
|
|
|
+ .append("]")
|
|
|
+ .append(" = ")
|
|
|
+ .append(content == null ? NULL : content.toString())
|
|
|
+ .append(LINE_SEP);
|
|
|
+ }
|
|
|
+ body = sb.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return body.length() == 0 ? NOTHING : body;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析json
|
|
|
+ *
|
|
|
+ * @param json json
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String formatJson(String json) {
|
|
|
+ try {
|
|
|
+ if (json.startsWith("{")) {
|
|
|
+ json = new JSONObject(json).toString(4);
|
|
|
+ } else if (json.startsWith("[")) {
|
|
|
+ json = new JSONArray(json).toString(4);
|
|
|
+ }
|
|
|
+ } catch (JSONException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return json;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析xml
|
|
|
+ *
|
|
|
+ * @param xml xml
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String formatXml(String xml) {
|
|
|
+ try {
|
|
|
+ Source xmlInput = new StreamSource(new StringReader(xml));
|
|
|
+ StreamResult xmlOutput = new StreamResult(new StringWriter());
|
|
|
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
|
|
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
|
|
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
|
|
+ transformer.transform(xmlInput, xmlOutput);
|
|
|
+ xml = xmlOutput.getWriter().toString().replaceFirst(">", ">" + LINE_SEP);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return xml;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void print2Console(final int type,
|
|
|
+ final String tag,
|
|
|
+ final String[] head,
|
|
|
+ final String msg) {
|
|
|
+ printBorder(type, tag, true);
|
|
|
+ printHead(type, tag, head);
|
|
|
+ printMsg(type, tag, msg);
|
|
|
+ printBorder(type, tag, false);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void printBorder(final int type, final String tag, boolean isTop) {
|
|
|
+ if (sLogBorderSwitch) {
|
|
|
+ Log.println(type, tag, isTop ? TOP_BORDER : BOTTOM_BORDER);
|
|
|
+// saveLog(LogType.Logcat, isTop ? TOP_BORDER : BOTTOM_BORDER);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void printHead(final int type, final String tag, final String[] head) {
|
|
|
+ if (head != null) {
|
|
|
+ for (String aHead : head) {
|
|
|
+ Log.println(type, tag, sLogBorderSwitch ? LEFT_BORDER + aHead : aHead);
|
|
|
+ Log.i("TEST", "type--" + type);
|
|
|
+ Log.i("TEST", "tag--" + tag);
|
|
|
+ Log.i("TEST", sLogBorderSwitch ? LEFT_BORDER + aHead : aHead + " printHead ");
|
|
|
+// saveLog(LogType.Logcat, sLogBorderSwitch ? LEFT_BORDER + aHead : aHead);
|
|
|
+ }
|
|
|
+ if (sLogBorderSwitch) {
|
|
|
+ Log.println(type, tag, MIDDLE_BORDER);
|
|
|
+ Log.i("TEST", MIDDLE_BORDER + " sLogBorderSwitch ");
|
|
|
+// saveLog(LogType.Logcat, MIDDLE_BORDER);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void printMsg(final int type, final String tag, final String msg) {
|
|
|
+ int len = msg.length();
|
|
|
+ int countOfSub = len / MAX_LEN;
|
|
|
+ if (countOfSub > 0) {
|
|
|
+ int index = 0;
|
|
|
+ for (int i = 0; i < countOfSub; i++) {
|
|
|
+ printSubMsg(type, tag, msg.substring(index, index + MAX_LEN));
|
|
|
+ index += MAX_LEN;
|
|
|
+ }
|
|
|
+ if (index != len) {
|
|
|
+ printSubMsg(type, tag, msg.substring(index, len));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ printSubMsg(type, tag, msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void printSubMsg(final int type, final String tag, final String msg) {
|
|
|
+ if (!sLogBorderSwitch) {
|
|
|
+ Log.println(type, tag, msg);
|
|
|
+// saveLog(LogType.Logcat, msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String[] lines = msg.split(LINE_SEP);
|
|
|
+ for (String line : lines) {
|
|
|
+ Log.println(type, tag, LEFT_BORDER + line);
|
|
|
+// saveLog(LogType.Logcat, LEFT_BORDER + line);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将日志写入到文件中,思路是先拼接字符串,然后再写入文件
|
|
|
+ *
|
|
|
+ * @param type 类型
|
|
|
+ * @param tag tag
|
|
|
+ * @param msg msg
|
|
|
+ */
|
|
|
+ private static void print2File(final int type, final String tag, final String msg) {
|
|
|
+ Date now = new Date(System.currentTimeMillis());
|
|
|
+ String format = FORMAT.format(now);
|
|
|
+ String date = format.substring(0, 5);
|
|
|
+ String time = format.substring(6);
|
|
|
+ final String fullPath =
|
|
|
+ (sDir == null ? sDefaultDir : sDir) + sFilePrefix + "-" + date + ".txt";
|
|
|
+ if (!createOrExistsFile(fullPath)) {
|
|
|
+ Log.e(tag, "log to " + fullPath + " failed!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ sb.append(time)
|
|
|
+ .append(T[type - V])
|
|
|
+ .append("/")
|
|
|
+ .append(tag)
|
|
|
+ .append(msg)
|
|
|
+ .append(LINE_SEP);
|
|
|
+ final String content = sb.toString();
|
|
|
+
|
|
|
+ //一边打印日志一边写入文件
|
|
|
+// if (PrintToFileUtil.input2File(content, fullPath)) {
|
|
|
+// Log.d(tag, "log to " + fullPath + " success!");
|
|
|
+// } else {
|
|
|
+// Log.e(tag, "log to " + fullPath + " failed!");
|
|
|
+// }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean createOrExistsFile(final String filePath) {
|
|
|
+ File file = new File(filePath);
|
|
|
+ if (file.exists()) return file.isFile();
|
|
|
+ if (!createOrExistsDir(file.getParentFile())) return false;
|
|
|
+ try {
|
|
|
+ boolean isCreate = file.createNewFile();
|
|
|
+// if (isCreate) {
|
|
|
+// String head = PrintToFileUtil.printDeviceInfo();
|
|
|
+// PrintToFileUtil.input2File(head, filePath);
|
|
|
+// }
|
|
|
+ return isCreate;
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static boolean createOrExistsDir(final File file) {
|
|
|
+ return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断是否为空
|
|
|
+ *
|
|
|
+ * @param s s
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static boolean isSpace(final String s) {
|
|
|
+ if (s == null) return true;
|
|
|
+ for (int i = 0, len = s.length(); i < len; ++i) {
|
|
|
+ if (!Character.isWhitespace(s.charAt(i))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * config 采用builder模式
|
|
|
+ */
|
|
|
+ public static class Config {
|
|
|
+ private Config() {
|
|
|
+ if (sDefaultDir != null) return;
|
|
|
+// if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
|
|
+// && MyApplication.getContext().getExternalCacheDir() != null)
|
|
|
+// sDefaultDir = MyApplication.getContext().getExternalCacheDir() + FILE_SEP + "log" + FILE_SEP;
|
|
|
+// else {
|
|
|
+// sDefaultDir = MyApplication.getContext().getCacheDir() + FILE_SEP + "log" + FILE_SEP;
|
|
|
+// }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setLogSwitch(final boolean logSwitch) {
|
|
|
+ sLogSwitch = logSwitch;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setConsoleSwitch(final boolean consoleSwitch) {
|
|
|
+ sLog2ConsoleSwitch = consoleSwitch;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setGlobalTag(final String tag) {
|
|
|
+ if (isSpace(tag)) {
|
|
|
+ sGlobalTag = "";
|
|
|
+ sTagIsSpace = true;
|
|
|
+ } else {
|
|
|
+ sGlobalTag = tag;
|
|
|
+ sTagIsSpace = false;
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setLogHeadSwitch(final boolean logHeadSwitch) {
|
|
|
+ sLogHeadSwitch = logHeadSwitch;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setLog2FileSwitch(final boolean log2FileSwitch) {
|
|
|
+ sLog2FileSwitch = log2FileSwitch;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setDir(final String dir) {
|
|
|
+ if (isSpace(dir)) {
|
|
|
+ sDir = null;
|
|
|
+ } else {
|
|
|
+ sDir = dir.endsWith(FILE_SEP) ? dir : dir + FILE_SEP;
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setDir(final File dir) {
|
|
|
+ sDir = dir == null ? null : dir.getAbsolutePath() + FILE_SEP;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setFilePrefix(final String filePrefix) {
|
|
|
+ if (isSpace(filePrefix)) {
|
|
|
+ sFilePrefix = "ycLog";
|
|
|
+ } else {
|
|
|
+ sFilePrefix = filePrefix;
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setBorderSwitch(final boolean borderSwitch) {
|
|
|
+ sLogBorderSwitch = borderSwitch;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setConsoleFilter(@TYPE final int consoleFilter) {
|
|
|
+ sConsoleFilter = consoleFilter;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setFileFilter(@TYPE final int fileFilter) {
|
|
|
+ sFileFilter = fileFilter;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Config setStackDeep(@IntRange(from = 1) final int stackDeep) {
|
|
|
+ sStackDeep = stackDeep;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toString() {
|
|
|
+ return "switch: " + sLogSwitch
|
|
|
+ + LINE_SEP + "console: " + sLog2ConsoleSwitch
|
|
|
+ + LINE_SEP + "tag: " + (sTagIsSpace ? "null" : sGlobalTag)
|
|
|
+ + LINE_SEP + "head: " + sLogHeadSwitch
|
|
|
+ + LINE_SEP + "file: " + sLog2FileSwitch
|
|
|
+ + LINE_SEP + "dir: " + (sDir == null ? sDefaultDir : sDir)
|
|
|
+ + LINE_SEP + "filePrefix" + sFilePrefix
|
|
|
+ + LINE_SEP + "border: " + sLogBorderSwitch
|
|
|
+ + LINE_SEP + "consoleFilter: " + T[sConsoleFilter - V]
|
|
|
+ + LINE_SEP + "fileFilter: " + T[sFileFilter - V]
|
|
|
+ + LINE_SEP + "stackDeep: " + sStackDeep;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class TagHead {
|
|
|
+ String tag;
|
|
|
+ String[] consoleHead;
|
|
|
+ String fileHead;
|
|
|
+
|
|
|
+ TagHead(String tag, String[] consoleHead, String fileHead) {
|
|
|
+ this.tag = tag;
|
|
|
+ this.consoleHead = consoleHead;
|
|
|
+ this.fileHead = fileHead;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String toString() {
|
|
|
+ return "TagHead{" +
|
|
|
+ "tag='" + tag + '\'' +
|
|
|
+ ", consoleHead=" + Arrays.toString(consoleHead) +
|
|
|
+ ", fileHead='" + fileHead + '\'' +
|
|
|
+ '}';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|