重撸工具类之LogUtils

前言:日志工具类曾经封装过一个简单版的,但效果貌似并不是很好,借着这周末的时间想更进一步完善它,撸得结果还是比较如意的,下面就让我来为大家介绍一下它吧。

上车须知

该LogUtils工具类450行代码,大小不足16K,功能齐全,下面来介绍下它的使用方式吧。

虽然该工具类存在于Android开发人员不得不收集的代码(持续更新中)中,但还是推荐拷贝该类到自己的项目中,然后修改两处即可,把Utils.getContext()换成你们自己传入的context即可。

初始化推荐放在Application的onCreat()中,就像下面这样的。

@Override
public void onCreate() {
    super.onCreate();
    LogUtils.Builder lBuilder = new LogUtils.Builder();
}

如上是最简单的初始化,当然,我们可配置参数还有更多,具体介绍如下。

lBuilder = new LogUtils.Builder()
        .setLogSwitch(BuildConfig.DEBUG)// 设置log总开关,默认开
        .setGlobalTag("CMJ")// 设置log全局标签,默认为空
                            // 当全局标签不为空时,我们输出的log全部为该tag,
                            // 为空时,如果传入的tag为空那就显示类名,否则显示tag
        .setLog2FileSwitch(false)// 打印log时是否存到文件的开关,默认关
        .setBorderSwitch(true)// 输出日志是否带边框开关,默认开
        .setLogFilter(LogUtils.V);// log过滤器,和logcat过滤器同理,默认Verbose

下面就是使用方式了,总共包括9种,如下所示。

  • 日志相关→LogUtils.java→Demo
v   : Verbose日志
d   : Debug日志
i   : Info日志
w   : Warn日志
e   : Error日志
a   : Assert日志
file: log到文件
json: log字符串之json
xml : log字符串之xml

其中对基础log类型支持多参数输出,同时支持长字符串的输出。

下面是使用图例,让我们一起来体会一下吧。

使用默认设置

  • LogUtils.d("debug");
LogUtils.d("debug");
  • LogUtils.d("customTag", "debug");
LogUtils.d("customTag", "debug");
  • LogUtils.d(null);
LogUtils.d(null);
  • LogUtils.d("customTag", "debug0", "debug1");
LogUtils.d("customTag", "debug0", "debug1");
  • LogUtils.d(longStr);
重撸工具类之LogUtils_第1张图片
LogUtils.d(longStr);
  • LogUtils.file(longStr);
LogUtils.file(longStr);
  • LogUtils.json(json);
重撸工具类之LogUtils_第2张图片
LogUtils.json(json);
  • LogUtils.xml(xml);
重撸工具类之LogUtils_第3张图片
LogUtils.xml(xml);

设置文件开关为开

  • LogUtils.d("customTag", "debug0", "debug1");
LogUtils.d("customTag", "debug0", "debug1");

设置全局tag为"CMJ"

  • LogUtils.d("customTag", "debug");
LogUtils.d("customTag", "debug");

设置边框开关为关

  • LogUtils.xml(xml);
重撸工具类之LogUtils_第4张图片
LogUtils.xml(xml);

详情自己参考demo

具体路线

package com.blankj.utilcode.util;

import android.os.Environment;
import android.support.annotation.IntDef;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
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.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.Locale;

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;

/**
 * 
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/9/21
 *     desc  : 日志相关工具类
 * 
*/ public final class LogUtils { private LogUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } public static final int V = 0x01; public static final int D = 0x02; public static final int I = 0x04; public static final int W = 0x08; public static final int E = 0x10; public static final int A = 0x20; @IntDef({V, D, I, W, E, A}) @Retention(RetentionPolicy.SOURCE) public @interface TYPE { } private static final int FILE = 0xF1; private static final int JSON = 0xF2; private static final int XML = 0xF4; private static String dir; // log存储目录 private static boolean sLogSwitch = true; // log总开关 private static String sGlobalTag = null; // log标签 private static boolean sTagIsSpace = true; // log标签是否为空白 private static boolean sLog2FileSwitch = false;// log写入文件开关 private static boolean sLogBorderSwitch = true; // log边框开关 private static int sLogFilter = V; // log过滤器 private static final String TOP_BORDER = "╔═══════════════════════════════════════════════════════════════════════════════════════════════════"; private static final String LEFT_BORDER = "║ "; private static final String BOTTOM_BORDER = "╚═══════════════════════════════════════════════════════════════════════════════════════════════════"; private static final String LINE_SEPARATOR = System.getProperty("line.separator"); private static final int MAX_LEN = 4000; private static final String NULL_TIPS = "Log with null object."; private static final String NULL = "null"; private static final String ARGS = "args"; public static class Builder { public Builder() { if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { dir = Utils.getContext().getExternalCacheDir() + File.separator + "log" + File.separator; } else { dir = Utils.getContext().getCacheDir() + File.separator + "log" + File.separator; } } public Builder setGlobalTag(String tag) { if (!isSpace(tag)) { LogUtils.sGlobalTag = tag; sTagIsSpace = false; } else { LogUtils.sGlobalTag = ""; sTagIsSpace = true; } return this; } public Builder setLogSwitch(boolean logSwitch) { LogUtils.sLogSwitch = logSwitch; return this; } public Builder setLog2FileSwitch(boolean log2FileSwitch) { LogUtils.sLog2FileSwitch = log2FileSwitch; return this; } public Builder setBorderSwitch(boolean borderSwitch) { LogUtils.sLogBorderSwitch = borderSwitch; return this; } public Builder setLogFilter(@TYPE int logFilter) { LogUtils.sLogFilter = logFilter; return this; } } public static void v(Object contents) { log(V, sGlobalTag, contents); } public static void v(String tag, Object... contents) { log(V, tag, contents); } public static void d(Object contents) { log(D, sGlobalTag, contents); } public static void d(String tag, Object... contents) { log(D, tag, contents); } public static void i(Object contents) { log(I, sGlobalTag, contents); } public static void i(String tag, Object... contents) { log(I, tag, contents); } public static void w(Object contents) { log(W, sGlobalTag, contents); } public static void w(String tag, Object... contents) { log(W, tag, contents); } public static void e(Object contents) { log(E, sGlobalTag, contents); } public static void e(String tag, Object... contents) { log(E, tag, contents); } public static void a(Object contents) { log(A, sGlobalTag, contents); } public static void a(String tag, Object... contents) { log(A, tag, contents); } public static void file(Object contents) { log(FILE, sGlobalTag, contents); } public static void file(String tag, Object contents) { log(FILE, tag, contents); } public static void json(String contents) { log(JSON, sGlobalTag, contents); } public static void json(String tag, String contents) { log(JSON, tag, contents); } public static void xml(String contents) { log(XML, sGlobalTag, contents); } public static void xml(String tag, String contents) { log(XML, tag, contents); } private static void log(int type, String tag, Object... contents) { if (!sLogSwitch) return; final String[] processContents = processContents(type, tag, contents); tag = processContents[0]; String msg = processContents[1]; switch (type) { case V: case D: case I: case W: case E: case A: if (V == sLogFilter || type >= sLogFilter) { printLog(type, tag, msg); } if (sLog2FileSwitch) { print2File(tag, msg); } break; case FILE: print2File(tag, msg); break; case JSON: printLog(D, tag, msg); break; case XML: printLog(D, tag, msg); break; } } private static String[] processContents(int type, String tag, Object... contents) { StackTraceElement targetElement = Thread.currentThread().getStackTrace()[5]; String className = targetElement.getClassName(); String[] classNameInfo = className.split("\\."); if (classNameInfo.length > 0) { className = classNameInfo[classNameInfo.length - 1]; } if (className.contains("$")) { className = className.split("\\$")[0]; } if (!sTagIsSpace) {// 如果全局tag不为空,那就用全局tag tag = sGlobalTag; } else {// 全局tag为空时,如果传入的tag为空那就显示类名,否则显示tag tag = isSpace(tag) ? className : tag; } String head = new Formatter() .format("Thread: %s, %s(%s.java:%d)" + LINE_SEPARATOR, Thread.currentThread().getName(), targetElement.getMethodName(), className, targetElement.getLineNumber()) .toString(); String msg = NULL_TIPS; if (contents != null) { if (contents.length == 1) { Object object = contents[0]; msg = object == null ? NULL : object.toString(); if (type == JSON) { msg = formatJson(msg); } else if (type == XML) { msg = formatXml(msg); } } 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_SEPARATOR); } msg = sb.toString(); } } if (sLogBorderSwitch) { StringBuilder sb = new StringBuilder(); String[] lines = msg.split(LINE_SEPARATOR); for (String line : lines) { sb.append(LEFT_BORDER).append(line).append(LINE_SEPARATOR); } msg = sb.toString(); } return new String[]{tag, head + msg}; } 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; } 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_SEPARATOR); } catch (Exception e) { e.printStackTrace(); } return xml; } private static void printLog(int type, String tag, String msg) { if (sLogBorderSwitch) printBorder(type, tag, true); int len = msg.length(); int countOfSub = len / MAX_LEN; if (countOfSub > 0) { int index = 0; String sub; for (int i = 0; i < countOfSub; i++) { sub = msg.substring(index, index + MAX_LEN); printSubLog(type, tag, sub); index += MAX_LEN; } printSubLog(type, tag, msg.substring(index, len)); } else { printSubLog(type, tag, msg); } if (sLogBorderSwitch) printBorder(type, tag, false); } private static void printSubLog(final int type, final String tag, String msg) { if (sLogBorderSwitch) msg = LEFT_BORDER + msg; switch (type) { case V: Log.v(tag, msg); break; case D: Log.d(tag, msg); break; case I: Log.i(tag, msg); break; case W: Log.w(tag, msg); break; case E: Log.e(tag, msg); break; case A: Log.wtf(tag, msg); break; } } private static void printBorder(int type, String tag, boolean isTop) { String border = isTop ? TOP_BORDER : BOTTOM_BORDER; switch (type) { case V: Log.v(tag, border); break; case D: Log.d(tag, border); break; case I: Log.i(tag, border); break; case W: Log.w(tag, border); break; case E: Log.e(tag, border); break; case A: Log.wtf(tag, border); break; } } private synchronized static void print2File(final String tag, final String msg) { Date now = new Date(); String date = new SimpleDateFormat("MM-dd", Locale.getDefault()).format(now); final String fullPath = dir + date + ".txt"; if (!createOrExistsFile(fullPath)) { Log.e(tag, "log to " + fullPath + " failed!"); return; } String time = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", Locale.getDefault()).format(now); StringBuilder sb = new StringBuilder(); if (sLogBorderSwitch) sb.append(TOP_BORDER).append(LINE_SEPARATOR); sb.append(time) .append(tag) .append(": ") .append(msg) .append(LINE_SEPARATOR); if (sLogBorderSwitch) sb.append(BOTTOM_BORDER).append(LINE_SEPARATOR); final String dateLogContent = sb.toString(); new Thread(new Runnable() { @Override public void run() { BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(fullPath, true)); bw.write(dateLogContent); Log.d(tag, "log to " + fullPath + " success!"); } catch (IOException e) { e.printStackTrace(); Log.e(tag, "log to " + fullPath + " failed!"); } finally { try { if (bw != null) { bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }).start(); } private static boolean createOrExistsFile(String filePath) { return createOrExistsFile(isSpace(filePath) ? null : new File(filePath)); } private static boolean createOrExistsFile(File file) { if (file == null) return false; if (file.exists()) return file.isFile(); if (!createOrExistsDir(file.getParentFile())) return false; try { return file.createNewFile(); } catch (IOException e) { e.printStackTrace(); return false; } } private static boolean createOrExistsDir(File file) { return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); } private static boolean isSpace(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; } }

终点站

好了,终点站到了,如果对本次旅途满意的话,请给五星好评哦,毕竟老司机牺牲了很多时间才换来这么一份工具类。

你可能感兴趣的:(重撸工具类之LogUtils)