写了个android简洁的日志打印工具类。

本文详细介绍了日志工具类的功能点、使用方法、权限需求以及如何配置和使用该工具类来管理和记录应用日志。包括日志级别控制、同步记录信息到本地文件等功能,帮助开发者更高效地进行日志管理。
package mma.demo.exception;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Pattern;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

/**
 * 打印工具类
 * @author meimuan
 * 功能点:<p>
 * <ul>
 * 	<li>可以控制打印输出</li>
 * 	<li>可以简便打印,经过包装得到精准特定格式的日志信息</li>
 * 	<li>可以直接打印异常</li>
 * 	<li>可以定位异常信息</li>
 * 	<li>可以便捷统一修改,优化</li>
 *  <li>^^^^^^^^^^^^^^^^^^^^^^^^^^^^</li>
 *  <li>同步输出日志到本地sdcard文件</li>
 * </ul>
 * <p>
 * 需要注册权限:
 * <table>
 *  <tr>
 * 		<td>* 读写SD卡权限    </td><td>android.permission.WRITE_EXTERNAL_STORAGE</td>
 *  </tr>
 * 	<tr>
 * 		<td>? 网络权限    </td><td>android.permission.INTERNET</td>
 *  </tr>
 * </table>
 * </p>
 * <p>
 * 说明:<br/>
 * 1. 日志是针对天数级别的,自动生成的日志名称yyyyMMdd.log形式。</br>
 * 2. 如果当天的日志需要新开一个(比如:日志很大了,需要从新生成一个)
 * </p>
 */
public class LogUtil {
	/** 控制打印级别 在level级别之上才可以被打印出来 */
	public static int LEVEL = 3;
	/** 打印级别为V,对应Log.v*/
	public final static int V = 1;
	/** 打印级别为W,对应Log.w*/
	public final static int W = 2;
	/** 打印级别为I,对应Log.i*/
	public final static int I = 3;
	/** 打印级别为D,对应Log.d*/
	public final static int D = 4;
	/** 打印级别为E,对应Log.e*/
	public final static int E = 5;
	/** 最高级别打印,强制性打印,LEVEL无法关闭。 */
	private final static int P = Integer.MAX_VALUE;
	/** 打印修饰符号*/
	private static final String _L = "[";
	private static final String _R = "]";
	/** 是否同步输出到本地日志文件 */
	private static boolean IS_SYNS = false;
	/** 打印日志保存路径*/
	private static String LOG_FILE_DIR = "";
	/** 生成一个日期文件名格式的日式格式对象*/
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd",Locale.getDefault());
	/** 是否新建一个日志文件。*/
	private static boolean IF_START_NEWLOG = true;
	/** 保存创建的文件路径 */
	private static String CURRENT_LOG_NAME = "";
	/** 针对天数级别的。如果当天已经存在一个LOG了,而使用者需要新开一个LOG,那么将计数 */
	private static int FILE_LOG_COUNT = 0;
	/** 单个日志的最大的容量,如果一个日志太大了,打开会影响效率*/
	private static int LOG_MAX_SIZE = 6 * 1024 * 1024;
	/** 检测文件目的地址是否正确 */
	private static Pattern pattern = Pattern.compile("(\\w+/)+");
	/** 设置是否同步记录信息或者异常到日志文件。*/
	public static final void setSyns(boolean flag) {
		synchronized (LogUtil.class){
			IS_SYNS = flag;
		}
	}
	/** 开启一个新的LOG */
	public static final void startNewLog() {
		IF_START_NEWLOG = true;
	}
	/**
	 * 打印信息
	 * @param message
	 */
	public static final void i(String message) {
		if (LEVEL <= I) {
			Log.i(getTag(message), message);
			if (IS_SYNS) {
				LogFile.writeLog(message);
			}
		}
	}
	
	public static final void i(Exception exp) {
		if (LEVEL <= I) {
			Log.i(getTag(exp),getMessage(exp));
			if (IS_SYNS) {
				LogFile.writeLog(exp);
			}
		}
	}
	
	public static final void e(String message) {
		if (LEVEL <= E) {
			Log.e(getTag(message), message);
			if (IS_SYNS) {
				LogFile.writeLog(message);
			}
		}
	}
	
	public static final void e(Exception exp) {
		if (LEVEL <= E) {
			Log.e(getTag(exp),getMessage(exp));
			if (IS_SYNS) {
				LogFile.writeLog(exp);
			}
		}
	}
	
	public static final void w(String message) {
		if (LEVEL <= W) {
			Log.w(getTag(message), message);
			if (IS_SYNS) {
				LogFile.writeLog(message);
			}
		}
	}
	
	public static final void w(Exception exp) {
		if (LEVEL <= W) {
			Log.w(getTag(exp),getMessage(exp));
			if (IS_SYNS) {
				LogFile.writeLog(exp);
			}
		}
	}
	
	public static final void v(String message) {
		if (LEVEL <= V) {
			Log.v(getTag(message), message);
			if (IS_SYNS) {
				LogFile.writeLog(message);
			}
		}
	}
	
	public static final void v(Exception exp) {
		if (LEVEL <= V) {
			Log.v(getTag(exp),getMessage(exp));
			if (IS_SYNS) {
				LogFile.writeLog(exp);
			}
		}
	}
	
	public static final void d(String message) {
		if (LEVEL <= D) {
			Log.d(getTag(message), message);
			if (IS_SYNS) {
				LogFile.writeLog(message);
			}
		}
	}
	
	public static final void d(Exception exp) {
		if (LEVEL <= D) {
			Log.d(getTag(exp),getMessage(exp));
			if (IS_SYNS) {
				LogFile.writeLog(exp);
			}
		}
	}
	/**
	 * 强制打印信息
	 * @param message
	 */
	public static final void print(String message) {
		if (LEVEL <= P) {
			Log.e(getTag(message), message);
			if (IS_SYNS)
				LogFile.writeLog(message);
		}
	}
	/**
	 * 强制打印异常
	 * @param exp
	 */
	public static final void print(Exception exp) {
		if (LEVEL <= P) {
			Log.e(getTag(exp), getMessage(exp));
			if (IS_SYNS)
				LogFile.writeLog(exp);
		}
	}
	/** 获取一个Tag打印标签
	 * @param msg
	 * @return
	 * @since JDK 1.5
	 */
	private static String getTag(String msg) {
		if (msg != null) {
			//since jdk 1.5
			if (Thread.currentThread().getStackTrace().length > 0) {
				String name = Thread.currentThread().getStackTrace()[0].getClassName();
				return _L + name.substring(name.lastIndexOf(".") + 1) + _R;
			}
		}
		return _L + "null" + _R;
	}
	/**
	 * 跟据变量获取一个打印的标签。
	 * @param exp
	 * @return
	 */
	private static String getTag(Exception exp) {
		if (exp != null) {
			if (exp.getStackTrace().length > 0) {
				String name = exp.getStackTrace()[0].getClassName();
				return _L + name.substring(name.lastIndexOf(".") + 1) + _R;
			}
			return _L + "exception" + _R;
		}
		return _L + "null" + _R;
	}
	/**
	 * 获取Exception的简便异常信息
	 * @param exp
	 * @return
	 */
	private static String getMessage(Exception exp) {
		StringBuilder sb = new StringBuilder();
		StackTraceElement[] element =  exp.getStackTrace();
		int n = 0;
		sb.append("\n");
		sb.append(exp.toString());
		sb.append("\n");
		for (StackTraceElement e : element) {
			sb.append(e.getClassName());
			sb.append(".");
			sb.append(e.getMethodName());
			sb.append("[");
			sb.append(e.getLineNumber());
			sb.append("]");
			sb.append("\n");
			n++;
			if (n >= 2) break;
		}
		if (exp.getCause() != null) {
			sb.append("Caused by: ");
			sb.append(exp.getMessage());
		}
		return sb.toString();
	}
	
	/** 自定义保存文件路径,如果是多重路径,请以xxx/xxx/xxx 形式的‘文件夹’ 
	 *  @parma  path : 文件夹名称 
	 *  * [将自动以当前时间为文件名拼接成完整路径。请慎用]
	 *  */
	public final static void setLogFilePath(String path) {
		String url = SDcardUtil.getPath() + File.separator + path;
		boolean flag = pattern.matcher(url).matches();
		if (flag) {
			LOG_FILE_DIR = url;
		} else {
			LogFile.print("the url is not match file`s dir");
		}
	}
	
	/** 设置默认路径,以包名为格式的文件夹*/
	public final static void setDefaultFilePath(Context context) {
		String pkName = context.getPackageName().replaceAll("\\.", "\\/");
		setLogFilePath(pkName);
	}
	/** 获取时间字符串 */
	private static String getCurrTimeDir() {
		return sdf.format(new Date());
	}
	
	/** LOG定制类。
	 *  输出LOG到日志。
	 */
	private static class LogFile {
		/** 内部强制性打印使用。区分print , 是为了解决无限循环打印exception*/
		private static void print(String msg) {
			if (LEVEL <= P) {
				Log.e(getTag(msg), msg);
			}
		}
		/**
		 * 打印信息
		 * @param message
		 */
		public static synchronized void writeLog(String message) {
			File f = getFile();
			if (f != null) {
				try {
					FileWriter fw = new FileWriter(f , true);
					BufferedWriter bw = new BufferedWriter(fw);
					bw.append("\n");
					bw.append(message);
					bw.append("\n");
					bw.flush();
					bw.close();
					fw.close();
				} catch (IOException e) {
					print("writeLog error, " + e.getMessage());
				}
			} else {
				print("writeLog error, due to the file dir is error");
			}
		}
		/**
		 * 打印异常
		 * @param exp
		 */
		public static synchronized void writeLog(Exception exp) {
			File f = getFile();
			if (f != null) {
				try {
					FileWriter fw = new FileWriter(f , true);
					PrintWriter pw = new PrintWriter(fw);
					pw.append("\n");
					exp.printStackTrace(pw);
					pw.flush();
					pw.close();
					fw.close();
				} catch (IOException e) {
					print("writeLog error, " + e.getMessage());
				}
			} else {
				print("writeLog error, due to the file dir is error");
			}
		}
		/**
		 * 获取文件
		 * @return
		 */
		private static final File getFile() {
			if ("".equals(LOG_FILE_DIR)) {
				return null;
			}
			synchronized (LogUtil.class) {
				if (!IF_START_NEWLOG) {
					File currFile = new File(CURRENT_LOG_NAME);
					if (currFile.length() >= LOG_MAX_SIZE) {
						IF_START_NEWLOG = true;
						return getFile();
					}
					return currFile;
				}
				File f = new File(LOG_FILE_DIR);
				if (!f.exists()) {
					f.mkdirs();
				}
				File file = new File(f.getAbsolutePath() + File.separator + getCurrTimeDir() + ".log");
				if (!file.exists()) {
					try {
						file.createNewFile();
						FILE_LOG_COUNT = 0;
						IF_START_NEWLOG = false;
						CURRENT_LOG_NAME = file.getAbsolutePath();
					} catch (IOException e) {
						print("createFile error , " + e.getMessage());
					}
				} else {
					//已经存在了
					if (IF_START_NEWLOG) {
						FILE_LOG_COUNT ++;
						return new File(f.getAbsolutePath() + File.separator + getCurrTimeDir() + "_" + FILE_LOG_COUNT+ ".log");
					}
				}
				return file;
			}
		}
	}
	
	/**
	 * SD卡管理器
	 */
	private static class SDcardUtil {
		
//		public static String getAbsPath() {
//			if (isMounted()) {
//				return Environment.getExternalStorageDirectory().getAbsolutePath();
//			}
//			return "";
//		}
		/** 获取Path*/
		public static String getPath() {
			if (isMounted()) {
				return Environment.getExternalStorageDirectory().getPath();
			}
			LogFile.print("please check if sd card is not mounted");
			return "";
		}
		/** 判断SD卡是否mounted*/
		public static boolean isMounted() {
			return Environment.isExternalStorageEmulated();
		}
		
	}
}
用法介绍:
设置日志打印级别  
LogUtil.LEVEL = LogUtil.W;  (默认为LogUtil.I)
设置应用打印日志路径名称
LogUtil.setDefaultFilePath(context);
设置应用自定义打印日志路径名称
LogUtil.setLogFilePath("com/demo/log");
设置同步打印记录到日志
LogUtil.setSyns(true);
设置启用一个新的LOG
LogUtil.startNewLog();
打印单行信息
LogUtil.i(msg)   LogUtil.v(msg)   LogUtil.w(msg)  LogUtil.d(msg)  LogUtil.e(msg);
打印异常信息
LogUtil.i(exp) .... ;
强制打印信息
LogUtil.print(msg);  LogUtil.print(exp);



==========================================================================================


一般应用发布前要除去项目中的打印信息,因此只需要设置LogUtil.LEVEL = 10 (比LogUtil.E大即可);
对于强制打印的信息,将无法去除。

欢迎大家补充,以及指点错误之处。

转载于:https://my.oschina.net/meimuan/blog/161878

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值