先上个效果图:

模板一:

模板二:


LOG常用的方法有以下5个:
Log.v() Log.d() Log.i() Log.w() Log.e() 。分别对应下图,除Assert

1、Verbose 的调试颜色为黑色的,任何消息都会输出,这里的v代表verbose啰嗦的意思,平时使用就是Log.v(“”,”“);

2、Debug 的输出颜色是蓝色的,仅输出debug调试的意思,但他会输出上层的信息,过滤起来可以通过DDMS的Logcat标签来选择.

3、Info 的输出为绿色,一般提示性的消息information,它不会输出Log.v和Log.d的信息,但会显示i、w和e的信息

4、Warn 的意思为橙色,可以看作为warning警告,一般需要我们注意优化Android代码,同时选择它后还会输出Log.e的信息。

5、Error 为红色,可以想到error错误,这里仅显示红色的错误信息,这些错误就需要我们认真的分析,查看栈的信息了。

6、Assert 表示断言失败后的错误消息,这类错误原本是不可能出现的错误,现在却出现了,是极其严重的错误类型。

Debug属于调试日志

其他五类Log的重要程度排序如下。
Assert > Error > Warn > Info > Verbose
推荐颜色:

  • Verbose:#000000
  • Debug :#0000FF
  • Info:#008700
  • Warn:#878700
  • Error:#FF0000
  • Assert:#8F0005

    Android Studio设置颜色步骤:

    File ->Setting ->Editor->Color&Fonts->Android Logcat

有个Log的工具类:https://github.com/orhanobut/logger

用法很简单:

//在Application中初始化一下
Logger.addLogAdapter(new AndroidLogAdapter());
//就可以用了
Logger.v("verbose");Logger.d("debug");Logger.i("information");Logger.w("warning");Logger.e("error");Logger.json("{\"a\": \"Hello\", \"b\": \"World\"}");Logger.xml("<note>\n" +"<to>George</to>\n" +"<from>John</from>\n" +"<heading>Reminder</heading>\n" +"<body>Don't forget the meeting!</body>\n" +"</note>");

好炫酷,好想自己写一个,看了看源码,试试写个简单的

先分析下源码的执行流程:
Logger.v
-> LoggerPrinter.log
-> AndroidLogAdapter.log
-> PrettyFormatStrategy.log
-> PrettyFormatStrategy.logChunk
-> LogcatLogStrategy.log 至此打印结束

多日志打印即循环执行此过程,此项目很好的使用了策略模式和Builder模式。

其中:

Printer 的实现类有:LoggerPrinter
LogAdapter 的实现类有:AndroidLogAdapter、DiskLogAdapter
FormatStrategy 的实现类有:CsvFormatStrategy、PrettyFormatStrategy
LogStrategy 的实现类有:DiskLogStrategy、LogcatLogStrategy

BuildConfig 里面是一些常量
Logger 一些具体的执行方法,调用LoggerPrinter 中的具体实现供客户端调用
Utils 工具类

下面仿照大佬的代码写个简单的吧

既然是简单的,就简单到底,就3个核心类(实际就一个):

1、IPrinter.java(定义一些接口)

package com.zx.logs;
public interface IPrinter {void v(String message, Object... args);void d(String message, Object... args);void i(String message, Object... args);void w(String message, Object... args);void e(String message, Object... args);void json(String json);void xml(String xml);void log(int priority, String message, Throwable throwable, Object... args);// priority    优先顺序// message     消息// tag         日志中tag,相当于Logcat Filter// throwable   子线程中打印日志,提取发生行数// args        String格式化字符串void log(int priority, String message, String tag, Throwable throwable, Object... args);}

2、Logs.java(暴露出来方法)

package com.zx.logs;
public class Logs {private static IPrinter iPrinter = new LogsPrinter();public static void v(String message, Object... args) {iPrinter.v(message, args);}public static void d(String message, Object... args) {iPrinter.d(message, args);}public static void i(String message, Object... args) {iPrinter.i(message, args);}public static void w(String message, Object... args) {iPrinter.w(message, args);}public static void e(String message, Object... args) {iPrinter.e(message, args);}public static void log(int priority, String tag, String message, Throwable throwable) {iPrinter.log(priority, tag, message, throwable);}public static void json(String json) {iPrinter.json(json);}public static void xml(String xml) {iPrinter.xml(xml);}}

3、LogsPrinter.java(大部分处理都在这里了)

package com.zx.logs;import android.text.TextUtils;
import android.util.Log;import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.UnknownHostException;import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;public class LogsPrinter implements IPrinter {//Android对日志项的最大限制是4076字节,所以4000个字节作为块的大小从默认的字符集private static final int CHUNK_SIZE = 4000;//最小堆栈private static final int MIN_STACK_OFFSET = 5;public static final int VERBOSE = 2;public static final int DEBUG = 3;public static final int INFO = 4;public static final int WARN = 5;public static final int ERROR = 6;public static final int ASSERT = 7;private static final int JSON_INDENT = 2;private String tag = "LogsPrinter";Pattern mPattern = new Pattern();public void setTag(String tag) {this.tag = tag;}@Overridepublic void v(String message, Object... args) {log(VERBOSE, message, args);}@Overridepublic void d(String message, Object... args) {log(DEBUG, message, args);}@Overridepublic void i(String message, Object... args) {log(INFO, message, args);}@Overridepublic void w(String message, Object... args) {log(WARN, message, args);}@Overridepublic void e(String message, Object... args) {log(ERROR, message, args);}@Overridepublic void json(String json) {if (TextUtils.isEmpty(json)) {d("Empty/Null json content");return;}try {json = json.trim();if (json.startsWith("{")) {JSONObject jsonObject = new JSONObject(json);String message = jsonObject.toString(JSON_INDENT);d(message);return;}if (json.startsWith("[")) {JSONArray jsonArray = new JSONArray(json);String message = jsonArray.toString(JSON_INDENT);d(message);return;}e("Invalid Json");} catch (JSONException e) {e("Invalid Json");}}@Overridepublic void xml(String xml) {if (TextUtils.isEmpty(xml)) {d("Empty/Null xml content");return;}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", "2");transformer.transform(xmlInput, xmlOutput);d(xmlOutput.getWriter().toString().replaceFirst(">", ">\n"));} catch (TransformerException e) {e("Invalid xml");}}private String getStackTraceString(Throwable tr) {if (tr == null) {return "";}// This is to reduce the amount of log spew that apps do in the non-error// condition of the network being unavailable.Throwable t = tr;while (t != null) {if (t instanceof UnknownHostException) {return "";}t = t.getCause();}StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw);tr.printStackTrace(pw);pw.flush();return sw.toString();}private synchronized void log(int priority, String message, Object... args) {log(priority, message, null, args);}@Overridepublic synchronized void log(int priority, String message, Throwable throwable, Object... args) {message = configMessage(message, throwable, args);logNext(priority, tag, message);}@Overridepublic synchronized void log(int priority, String message, String tag, Throwable throwable, Object... args) {message = configMessage(message, throwable, args);logNext(priority, tag, message);}private String configMessage(String message, Throwable throwable, Object... args) {message = createMessage(message, args);if (throwable != null && message != null) {message += " : " + getStackTraceString(throwable);}if (throwable != null && message == null) {message = getStackTraceString(throwable);}return message;}//大于0就显示打印日志位置int methodCount = 2;//是否显示线程信息 Thread: main(主线程中打印)或Thread: Thread-4(子线程中打印)boolean showThreadInfo = true;int methodOffset = 0;private synchronized void logNext(int priority, String tag, String message) {logTopBorder(priority, tag);logHeaderContent(priority, tag, methodCount);//得到系统的默认字符集的信息字节(Android是UTF-8)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);//create a new String with system's default charset (which is UTF-8 for Android)logContent(priority, tag, new String(bytes, i, count));}logBottomBorder(priority, tag);}//日志--顶部边框private void logTopBorder(int logType, String tag) {logChunk(logType, tag, mPattern.getTopBorder());}//日志--底部边框private void logBottomBorder(int logType, String tag) {logChunk(logType, tag, mPattern.getBottomBorder());}//日志--分割线private void logDivider(int logType, String tag) {logChunk(logType, tag, mPattern.getMiddleBorder());}@SuppressWarnings("StringBufferReplaceableByString")private void logHeaderContent(int logType, String tag, int methodCount) {//获取当前线程状态StackTraceElement[] trace = Thread.currentThread().getStackTrace();if (showThreadInfo) {logChunk(logType, tag, mPattern.getHorizontalLine() + " Thread: " + Thread.currentThread().getName());logDivider(logType, tag);}String level = "";int stackOffset = getStackOffset(trace) + methodOffset;//corresponding method count with the current stack may exceeds the stack trace. Trims the countif (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(mPattern.getHorizontalLine()).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());}}//日志--内容private void logContent(int logType, String tag, String chunk) {String[] lines = chunk.split(System.getProperty("line.separator"));for (String line : lines) {logChunk(logType, tag, mPattern.getHorizontalLine() + " " + line);}}private void logChunk(int priority, String tag, String chunk) {Log.println(priority, tag, chunk);}//确定堆栈跟踪的起始索引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(LogsPrinter.class.getName()) && !name.equals(Logs.class.getName())) {return --i;}}return -1;}//截取最后一次出现的位置的下一个private String getSimpleClassName(String name) {int lastIndex = name.lastIndexOf(".");return name.substring(lastIndex + 1);}//字符串格式化private String createMessage(String message, Object... args) {return args == null || args.length == 0 ? message : String.format(message, args);}
}

4、Pattern.java(一个模式选择类)

package com.zx.logs;
public class Pattern {private static final int SINGLE_LINE = 1;private static final int DOUBLE_LINE = 2;//模式切换private int type = SINGLE_LINE;private char topLeftCorner;private char bottomLeftCorner;private char middleCorner;private char horizontalLine;private String doubleDivider;private String singleDivider;private String topBorder;private String bottomBorder;private String middleBorder;private char getChar(char value1, char value2) {char corner = value1;switch (type) {case SINGLE_LINE:corner = value1;break;case DOUBLE_LINE:corner = value2;break;}return corner;}private String getString(String value1, String value2) {String corner = value1;switch (type) {case SINGLE_LINE:corner = value1;break;case DOUBLE_LINE:corner = value2;break;}return corner;}public char getTopLeftCorner() {topLeftCorner = getChar(SingleLine.TOP_LEFT_CORNER, DoubleLine.TOP_LEFT_CORNER);return topLeftCorner;}public char getBottomLeftCorner() {bottomLeftCorner = getChar(SingleLine.BOTTOM_LEFT_CORNER, DoubleLine.BOTTOM_LEFT_CORNER);return bottomLeftCorner;}public char getMiddleCorner() {middleCorner = getChar(SingleLine.MIDDLE_CORNER, DoubleLine.MIDDLE_CORNER);return middleCorner;}public char getHorizontalLine() {horizontalLine = getChar(SingleLine.HORIZONTAL_LINE, DoubleLine.HORIZONTAL_LINE);return horizontalLine;}public String getDoubleDivider() {doubleDivider = getString(SingleLine.DOUBLE_DIVIDER, DoubleLine.DOUBLE_DIVIDER);return doubleDivider;}public String getSingleDivider() {singleDivider = getString(SingleLine.SINGLE_DIVIDER, DoubleLine.SINGLE_DIVIDER);return singleDivider;}public String getTopBorder() {topBorder = getString(SingleLine.TOP_BORDER, DoubleLine.TOP_BORDER);return topBorder;}public String getBottomBorder() {bottomBorder = getString(SingleLine.BOTTOM_BORDER, DoubleLine.BOTTOM_BORDER);return bottomBorder;}public String getMiddleBorder() {middleBorder = getString(SingleLine.MIDDLE_BORDER, DoubleLine.MIDDLE_BORDER);return middleBorder;}static class SingleLine {private static final char TOP_LEFT_CORNER = '┌';private static final char BOTTOM_LEFT_CORNER = '└';private static final char MIDDLE_CORNER = '├';private static final char HORIZONTAL_LINE = '│';private static final String DOUBLE_DIVIDER = "────────────────────────────────────────────────────────";private static final String SINGLE_DIVIDER = "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄";private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;}static class DoubleLine {private static final char TOP_LEFT_CORNER = '╔';private static final char BOTTOM_LEFT_CORNER = '╚';private static final char MIDDLE_CORNER = '╟';private static final char HORIZONTAL_LINE = '║';private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════";private static final String SINGLE_DIVIDER = "────────────────────────────────────────────";private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;}}

客户端使用(比较简单,无需初始化,直接使用):

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void log(View view) {doLog();new Thread(new Runnable() {@Overridepublic void run() {doLog();}}).start();}private void doLog() {Logs.v("vvvvvvvvvvvvvvvvvvvvvvv");Logs.d("dddddddddddddddddddddddddd");Logs.i("iiiiiiiiiiiiiiiiiiiiiiiiiiiii");Logs.w("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwww");Logs.e("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");Logs.json("{\"a\": \"Hello\", \"b\": \"World\"}");Logs.xml("<note>\n" +"<to>George</to>\n" +"<from>John</from>\n" +"<heading>Reminder</heading>\n" +"<body>Don't forget the meeting!</body>\n" +"</note>");}
}

大功告成啦!

附:

大佬的源码中有3个类我没用到(即只提取了AndroidLogAdapter适配器的功能):
(作者完美使用了适配器模式+策略模式)

即另外一种情况下使用到的Log打印,因为在使用Logger打印的时候,需要在Application中进行适配器的设置:

//正常情况打印(默认选此配置)
Logger.addLogAdapter(new AndroidLogAdapter());
//保存日志到本地
Logger.addLogAdapter(new DiskLogAdapter());

从 Logger.v-> LoggerPrinter.log 之后,会根据适配器的设置选择使用AndroidLogAdapter或者DiskLogAdapter->DiskLogStrategy->CsvFormatStrategy

CsvFormatStrategy:保存日志到本地sd卡中是在根目录下一个logger文件,是.cvs文件

源码下载:
http://download.csdn.net/download/u013277740/10244736

最后啰嗦一句,重点提醒

Log打印框架都仅仅适用于调试(Debug)模式,如果要发布,千万要关掉Log打印,至于怎么关闭方法很多:Log框架自带的方法关闭、代码注释、混淆等等。。。

正式发布如果不禁掉,返回的json数据会进行格式转换,很消耗时间的,如果打印的日志在主线程,则会使APP变的卡顿

Android 自定义Log 多模式相关推荐

  1. android 自定义库,Android自定义Log库

    背景 我们在开发的时候肯定会打一些Log,特别是在调试代码或者bug的时候,我们都会打一些Log日志来记录,但是当我们发布正式版本的时候,尼玛,要一行一行的去掉,这就尴尬了. 懵逼状态 励志封装Log ...

  2. android 代码省电模式,我们将向您展示如何在Android8.0Oreo中自定义省电模式

    通过限制后台服务,禁用动画以及执行各种其他调整,Android上的节电模式可以非常有效地延长电池寿命.但是,它采用了一些额外的措施,其中一些措施似乎过分或不必要.例如,振动是否真的使用足够的功率来证明 ...

  3. 我的Android进阶之旅------Android自定义View来实现解析lrc歌词并同步滚动、上下拖动、缩放歌词的功能...

    前言 一LRC歌词文件简介 1什么是LRC歌词文件 2LRC歌词文件的格式 LRC歌词文件的标签类型 1标识标签 2时间标签 二解析LRC歌词 1读取出歌词文件 2解析得到的歌词内容 1表示每行歌词内 ...

  4. LINUX系统以及ANDROID 平台log信息输出级别设置 [MTK]

    一.LK层: 首先,在LK中,有一个对log打印级别的控制文档,其路径一般为:vendor\mediatek\proprietary\bootable\bootloader\lk\include\de ...

  5. Android自定义View实践 空气质量检测 pm2.5

    直接先看效果图 自定义气体检测视图我们先整理下需要做的的事情 画五个圆弧 每个圆弧上再通过具体的数据绘制一定角度的圆弧 甲醛那个进度条比较特殊,一头平一头椭圆该怎么实现? 文字的绘制 明白了需求我们开 ...

  6. Android -- 自定义StepView实现个人信息验证进度条

    1,项目中要用到个人信息验证的在网上找了一下,好像有封装好了的StepView,首先感谢一下作者,这是作者的地址,效果图如下: 2,正准备撸起袖子就是一顿复制粘贴的时候,发现效果图成这个样子了(其实这 ...

  7. android 自定义MP4播放器

    昨天,在网上找了好多资料,终于做了一个自定义的播发器. 视频播放方式 在Android中播放视频的方式有两种: 1.使用MediaPlayer结合SurfaceView进行播放.其中通过Surface ...

  8. Android自定义view详解,使用实例,自定义属性,贝塞尔曲线

    //只会触发执行onDraw方法,只会改变绘制里面的内容,条目的绘制 invalidate(); //只会触发执行onDraw方法,但是可以在子线程中刷新 postInvalidate(); //vi ...

  9. Android自定义实现FlowLayout

    实现FlowLayout 何为FlowLayout,如果对Java的Swing比较熟悉的话一定不会陌生,就是控件根据ViewGroup的宽,自动的往右添加,如果当前行剩余空间不足,则自动添加到下一行. ...

最新文章

  1. 阿里员工的Java问题排查工具单
  2. 杨剑勇:物联网是一个未来概念?其实就在身边
  3. css设置鼠标指针光标样式
  4. [androd] android的在线源码网站,各个版本都有(目前已到俺android 4.2,但不包含kernel部分的代码)
  5. python tushare获取股票数据_Python 金融: TuShare API 获取股票数据 (1)
  6. keras从入门到放弃(十二)卷积神经网络
  7. 每天一道LeetCode-----将字符串的连续相同的字符合并成一个字符后加个数
  8. 蓝桥杯真题-连号区间数-枚举
  9. 如何通过命令终端访问本地/局域网/远程的MySQL数据库_访问数据库_连接数据库_登录数据库
  10. 深入理解JavaScript系列(32):设计模式之观察者模式
  11. 【C语言进阶深度学习记录】一 数据类型的本质与变量的本质
  12. 大数据学习(1)-大数据概述
  13. 什么样的企业适合做响应式网站
  14. Windows操作系统dos常见用法与常见问题
  15. 计算机重启 ie 被改,IE浏览器首页被篡改怎么办 如何重置IE还原到最初的安装状态...
  16. cocos 修改层级_管理节点层级和显示顺序
  17. 硕士论文latex参考文献格式经验
  18. 《诗经·邶风·击鼓》
  19. Linux 日志系统、auditd用户审计、kdump故障定位
  20. Java查询Mysql数据库时区问题(相差13/14)个小时

热门文章

  1. matlab怎么做var,如何使用vgxvarx在matlab中运行这个简单的VAR(VARX?)模型?
  2. 计算机操作基础知识2017,计算机基础知识试题及答案2017
  3. MAPGIS67卸载
  4. NOIP2018 tg游记
  5. 面试:25匹马,5个赛道,选出前三,最优解
  6. uni-app教程二(微信开发者工具运行项目,icon字体使用,组件)
  7. python笔记 之 手机号有效性简单判断
  8. 要想工作流程更简便,试试开源web表单设计器
  9. 智慧城市数字孪生系统深度融合大数据、云计算等技术应用
  10. 君子有所为,有所不为