Log 日志工具类 保存到文件 MD
| Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
|---|---|---|---|---|
| MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Log 日志工具类 保存到文件 MD
目录
日志工具类
几个比较流行的开源库
logger 8K
hugo 6K
timber 5.5K
XLog 1.5K
KLog 1.5K
简介
public final class android.util.Log extends Object
public final class android.util.Log extends Object
API for sending log output.
Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e() methods.
The order in terms of verbosity(冗长,赘言), from least to most is ERROR, WARN, INFO, DEBUG, VERBOSE.
Verbose should never be compiled into an application except during development.
Debug logs are compiled in but stripped at runtime. Error, warning and info logs are always kept.
Tip: A good convention约定 is to declare a TAG constant in your class:
private static final String TAG = "MyActivity";
and use that in subsequent随后的 calls to the log methods.
Tip: Don't forget that when you make a call like
Log.v(TAG, "index=" + i);
that when you're building the string to pass into Log.d, the compiler uses a StringBuilder and at least three allocations分配 occur: the StringBuilder itself, the buffer, and the String object. Realistically, there is also another buffer allocation and copy, and even more pressure on the gc. That means that if your log message is filtered out, you might be doing significant work and incurring significant overhead.
日志工具类
超强工具类
一个可打印并可跳转到"日志所在类、所在行"的工具类
效果如下:

public class L {
private static boolean OPEN_LOG = BuildConfig.DEBUG;
public static void isOpenLog(boolean isOpenLog) {
OPEN_LOG = isOpenLog;
}
public static void v(Object... message) {
if (OPEN_LOG) log(Log.VERBOSE, formatMessage(message));
}
public static void d(Object... message) {
if (OPEN_LOG) log(Log.DEBUG, formatMessage(message));
}
public static void i(Object... message) {
if (OPEN_LOG) log(Log.INFO, formatMessage(message));
}
public static void w(Object... message) {
log(Log.WARN, formatMessage(message));
}
public static void e(Object... message) {
log(Log.ERROR, formatMessage(message));
}
public static void json(String json) {
json = new GsonBuilder()
.setPrettyPrinting()
.create()
.toJson(new JsonParser().parse(json));
log(Log.DEBUG, formatMessage(json));
}
/**
* 根据type输出日志消息,包括方法名,方法行数,Message
*
* @param type 日志类型,如Log.INFO
* @param message 日志内容
*/
private static void log(int type, String message) {
StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[4]; //核心一,获取到执行log方法的代码位置
String className = stackTrace.getClassName();
String tag = className.substring(className.lastIndexOf('.') + 1); //不必须的tag
StringBuilder sb = new StringBuilder();
sb.append("日志")
.append("(") //核心二,通过(fileName:lineNumber)格式,即可在点击日志后跳转到执行log方法的代码位置
.append(stackTrace.getFileName())//文件名
.append(":")
.append(stackTrace.getLineNumber())//行号
.append(")")
.append("_") //后面的属于不必须的信息
.append(stackTrace.getMethodName())//方法名
.append("【")
.append(message)//消息
.append("】");
switch (type) {
case Log.DEBUG:
Log.d(tag, sb.toString());
break;
case Log.INFO:
Log.i(tag, sb.toString());
break;
case Log.WARN:
Log.w(tag, sb.toString());
break;
case Log.ERROR:
Log.e(tag, sb.toString());
break;
case Log.VERBOSE:
Log.v(tag, sb.toString());
break;
}
}
private static String formatMessage(Object... messages) {
StringBuilder sb = new StringBuilder();
for (Object mobj : messages) {
sb.append(objToString(mobj, -1)).append("\n");
}
return sb.substring(0, sb.length() - 1).trim();
}
//******************************************************************************************
private static String objToString(Object obj, int currentLvel) {
if (obj == null) return "null";
currentLvel++;
StringBuilder sb = new StringBuilder();
if (obj instanceof String) {//字符串
sb.append(getSpace(currentLvel)).append(obj);
} else if (obj instanceof Object[]) {//数组
sb.append("数组:").append("\n");
for (Object mobj : (Object[]) obj) {
sb.append(objToString(mobj, currentLvel)).append("\n");//递归
}
} else if (obj instanceof Collection) {//集合
sb.append("集合:").append("\n");
for (Object mobj : (Collection) obj) {
sb.append(objToString(mobj, currentLvel)).append("\n");//递归
}
} else {//其他对象
sb.append(getSpace(currentLvel)).append(obj.toString());
}
return sb.toString();
}
/***
* 格式化目录
*
* @param level 目录层次,也即"| _ _"的个数
*/
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < level; i++) {
sb.append("|__");
}
return sb.toString();
}
}
实验案例
L.i("包青天");
L.i(5);
L.i(true);
L.json("{\"name\":\"bqt\",\"age\":30,\"more\":[true,985,\"河南\"] }");
L.i(new Person("白乾涛"));
L.i("----------------------连续---------------------");
L.i("包青天", 5, true, new Person("白乾涛"));
L.i("----------------------数组---------------------");
Object[] array = {"包青天", 5, true, new Person("白乾涛")};
L.i(array);
L.i("-----------------------集合--------------------");
L.i(Arrays.asList(array));
L.i("---------------------嵌套----------------------");
List<Object> mList = new ArrayList<>();
mList.add("这是一级元素");
mList.add(10086);
mList.add(new Person("包青天"));
mList.add(array);
mList.add(Arrays.asList(array));
L.i(mList);
实验结果
日志(MainActivity.java:53)_test【包青天】
日志(MainActivity.java:54)_test【5】
日志(MainActivity.java:55)_test【true】
日志(MainActivity.java:56)_test【{
"name": "bqt",
"age": 30,
"more": [
true,
985,
"河南"
]
}】
日志(MainActivity.java:57)_test【Person{name='白乾涛'}】
日志(MainActivity.java:58)_test【----------------------连续---------------------】
日志(MainActivity.java:59)_test【包青天
5
true
Person{name='白乾涛'}】
日志(MainActivity.java:60)_test【----------------------数组---------------------】
日志(MainActivity.java:62)_test【包青天
5
true
Person{name='白乾涛'}】
日志(MainActivity.java:63)_test【-----------------------集合--------------------】
日志(MainActivity.java:64)_test【集合:
|__包青天
|__5
|__true
|__Person{name='白乾涛'}】
日志(MainActivity.java:65)_test【---------------------嵌套----------------------】
日志(MainActivity.java:72)_test【集合:
|__这是一级元素
|__10086
|__Person{name='包青天'}
数组:
|__|__包青天
|__|__5
|__|__true
|__|__Person{name='白乾涛'}
集合:
|__|__包青天
|__|__5
|__|__true
|__|__Person{name='白乾涛'}】
一个专门保存日志到文件的工具类
public class LaunchLog {
private static long tempTime;
private static FileOutputStream outputStream;
private static final String DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bqtlog";
public static void write(String text) {
try {
File dir = new File(DIR);
if (!dir.exists()) {
dir.mkdirs();
}
String date = new SimpleDateFormat("HH:mm:ss_SSS", Locale.getDefault()).format(new Date());
if (outputStream == null) {
outputStream = new FileOutputStream(new File(dir, "log.txt"), true);
outputStream.write(("\n------------------------- " + date + " ------------------------\n").getBytes());
tempTime = System.currentTimeMillis();
}
outputStream.write(("\n" + date + "\t" + text + "(耗时" + (System.currentTimeMillis() - tempTime) + "毫秒)").getBytes());
outputStream.flush();
tempTime = System.currentTimeMillis();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void close() {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
一个简单封装的日志工具类
public class L {
/**
* 是否需要打印bug,可以在application的onCreate函数里面初始化
*/
public static boolean isDebug = true;
private static final String TAG = "bqt";
private L() {
}
//**********************************************下面四个是默认tag的函数 ********************************************
public static void i(String msg) {
if (isDebug) Log.i(TAG, msg);
}
public static void d(String msg) {
if (isDebug) Log.d(TAG, msg);
}
public static void e(String msg) {
if (isDebug) Log.e(TAG, msg);
}
public static void v(String msg) {
if (isDebug) Log.v(TAG, msg);
}
//******************************************下面是传入自定义tag的函数 ************************************************
public static void i(String tag, String msg) {
if (isDebug) Log.i(tag, msg);
}
public static void d(String tag, String msg) {
if (isDebug) Log.i(tag, msg);
}
public static void e(String tag, String msg) {
if (isDebug) Log.i(tag, msg);
}
public static void v(String tag, String msg) {
if (isDebug) Log.i(tag, msg);
}
}
一个保存日志到文件的工具类
产生的文件内容

public class MyLog {
private static boolean MYLOG_SWITCH = true; // 是否打印日志及是否写入到文件的总开关
private static boolean MYLOG_WRITE_TO_FILE = true;// 是否将日志写入到文件的开关
private static char MYLOG_TYPE = 'v';// 输入日志类型,仅输出比自己级别高的日志,日志级别ERROR, WARN, INFO, DEBUG, VERBOSE
private static String MYLOG_PATH_SDCARD_DIR = Environment.getExternalStorageDirectory().getPath() + "/bqt";// 日志文件的路径
private static String MYLOGFILEName = "Log-";// 日志文件名称①
private static SimpleDateFormat logfile = new SimpleDateFormat("yyyy-MM-dd");// 日志文件名称②
//**************************************************************************************************************************
public static void w(String tag, String text) {
log(tag, text, 'w');
}
public static void e(String tag, String text) {
log(tag, text, 'e');
}
public static void d(String tag, String text) {
log(tag, text, 'd');
}
public static void i(String tag, String text) {
log(tag, text, 'i');
}
public static void v(String tag, String text) {
log(tag, text, 'v');
}
//**************************************************************************************************************************
//根据tag, msg和等级输出日志
private static void log(String tag, String msg, char level) {
if (MYLOG_SWITCH) {
if ('e' == level) Log.e(tag, msg);
else if ('w' == level && ('w' == MYLOG_TYPE || 'i' == MYLOG_TYPE || 'd' == MYLOG_TYPE || 'v' == MYLOG_TYPE)) Log.w(tag, msg);
else if ('i' == level && ('i' == MYLOG_TYPE || 'd' == MYLOG_TYPE || 'v' == MYLOG_TYPE)) Log.i(tag, msg);
else if ('d' == level && ('d' == MYLOG_TYPE || 'v' == MYLOG_TYPE)) Log.d(tag, msg);
else if ('v' == level && 'v' == MYLOG_TYPE) Log.v(tag, msg);
if (MYLOG_WRITE_TO_FILE) writeLogtoFile(String.valueOf(level), tag, msg);
}
}
//将日志写入文件,文件名格式为MYLOGFILEName + logfile.format(nowtime) + ".txt",如【Log-2015-12-25.txt】
private static void writeLogtoFile(String mylogtype, String tag, String text) {
Date nowtime = new Date();
SimpleDateFormat myLogSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String myLogs = myLogSdf.format(nowtime) + " " + mylogtype + " " + tag + " " + text;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) return;//判断sdcard是否插入
File fileDir = new File(MYLOG_PATH_SDCARD_DIR);
if (!fileDir.exists()) fileDir.mkdirs();//创建文件夹,这一步不能少
File file = new File(fileDir, MYLOGFILEName + logfile.format(nowtime) + ".txt");
try {
FileWriter filerWriter = new FileWriter(file, true);//true代表在文件中原来的数据后面添加,不进行覆盖
BufferedWriter bufWriter = new BufferedWriter(filerWriter);
bufWriter.write(myLogs);
bufWriter.newLine();
bufWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2017-7-11
Log 日志工具类 保存到文件 MD的更多相关文章
- C# Log日志工具类
using System; using System.Collections.Generic; using System.Text; using System.IO; public class Log ...
- Android开发调试日志工具类[支持保存到SD卡]
直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...
- Android utils 之 日志工具类
工具类 在开发的过程中,我们时常会对代码执行特定的处理,而这部分处理在代码中可能多次用到,为了代码的统一性.规范性等,通过建工具类的方式统一处理.接下来我会罗列各种工具类. 日志工具类 在utils文 ...
- 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类
快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...
- 002-基本业务搭建【日志,工具类dbutils,dbcp等使用】
一.需求分析 1.1.概述 1.用户进入“客户管理”,通过列表方式查看用户: 2.客户名称,模糊查询用户列表 3.客户名称,可查看客户详细信息 4.新增.编辑.删除功能等 二.系统设计 需要对原始需求 ...
- 【个人使用.Net类库】(2)Log日志记录类
开发接口程序时,要保证程序稳定运行就要时刻监控接口程序发送和接收的数据,这就需要一个日志记录的类将需要的信息记录在日志文件中,便于自己维护接口程序.(Web系统也是如此,只是对应的日志实现比这个要复杂 ...
- logger日志工具类
日志工厂类 package cn.itcast.utils; import java.util.logging.FileHandler; import java.util.logging.Handle ...
- Java 基于log4j的日志工具类
对log4j日志类进行了简单封装,使用该封装类的优势在于以下两点: 1.不必在每个类中去创建对象,直接类名 + 方法即可 2.可以很方便的打印出堆栈信息 package com.tradeplatfo ...
- JAVA日志工具类
package com.ming.util; import java.io.File; import java.io.FileWriter; import java.io.IOException; i ...
随机推荐
- 【记录】【持续更新】mybatis使用记录
1.> < 等符号在mybatis中的sql语句需要转义 > : > < : < 2.mybatis动态选择 <choose> <when te ...
- c#程序员机试题
一.题目: 有一数组: int[] arr = new int[] { 48,1,3,55,15,29,12,33,26,41,56,32}; 1.求出最大值 2.按每个数字的10位数分组(说明:0~ ...
- 深入理解ajax系列第二篇
前面的话 在上一篇中,概要地介绍了XHR对象的使用.本文将详细介绍使用XHR对象发送请求的两种方式——GET和POST.下面将以实例的形式来详细说明 GET GET是最常见的请求类型,最常用于向服务器 ...
- Opencv学习笔记5:Opencv处理彩虹图、铜色图、灰度反转图
一.概述: 人类能够观察到的光的波长范围是有限的,并且人类视觉有一个特点,只能分辨出二十几种灰度,也就是说即使采集到的灰度图像分辨率超级高,有上百个灰度级,但是很遗憾,人们只能看出二十几个,也就是说信 ...
- 线性表之单链表C++实现
线性表之单链表 一.头文件:LinkedList.h //单链表是用一组任意的存储单元存放线性表的元素,这组单元可以是连续的也可以是不连续的,甚至可以是零散分布在内存中的任意位置. //单链表头文件 ...
- hdu 2819 记录路径的二分匹配
题目大意就是给出一个矩阵,每个格子里面要么是0, 要么是1:是否能够经过交换(交换行或者列)使得主对角线上都是1. 其实就行和列的匹配,左边是行,右边是列,然后如果行列交点是1,那么就可以匹配,看是否 ...
- bzoj 2011
决策单调性,对于一个1D/1D(状态是一维,转移也是一维)的DP,如果DP的决策具有单调性,那么就可以做到O(nlogn)的复杂度完成DP. 感谢<1D/1D 动态规划优化初步>的作者. ...
- python开发_tkinter_图形随鼠标移动
做这个东西的时候,灵感源自于一个js效果: 两个眼睛随鼠标移动而移动 运行效果: =============================================== 代码部分: ===== ...
- python开发_getpass_获取登录名
我们有时候需要获取到计算机的登录名,这时候,就可以使用python中的getpass模块了 下面是我做的demo 运行效果: ===================================== ...
- [Android] 字体使用dp单位避免设置系统字体大小对排版的影响
[Android] 字体使用dp单位避免设置系统字体大小对排版的影响 以魄族mx3为例,在设置->显示->字体大小中能够选择字号大小例如以下图: 图1. 魄族mx3 会导致软件在有固定定高 ...