android 日誌檔案LogUtils例項
背景
這是好久之前在網上找的一個常用類,已經忘記原文連結了,但是覺得很好用一直都在用,可以將日誌寫到file裡面也可以定位你是在哪個類哪一行列印的日誌,儲存到檔案的路徑就是android/data/你的包名/files/目錄下,然後我們就可以愉快的找問題了
import android.text.TextUtils; import android.util.Log; import com.smartlink.suixing.App; import com.smartlink.suixing.BuildConfig; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Formatter; import java.util.Locale; public class LogUtils { public static String customTagPrefix = "log"; // 自定義Tag的字首,可以是作者名 private static final boolean isSaveLog = true; // 是否把儲存日誌到SD卡中 private static String cacheDirPath; private LogUtils() { } // 容許列印日誌的型別,預設是true,設定為false則不列印 public static boolean allowD = BuildConfig.DEBUG; public static boolean allowE = BuildConfig.DEBUG; public static boolean allowI = BuildConfig.DEBUG; public static boolean allowV = BuildConfig.DEBUG; public static boolean allowW = BuildConfig.DEBUG; public static boolean allowWtf = BuildConfig.DEBUG; // public static boolean allowD = true; // public static boolean allowE = true; // public static boolean allowI = true; // public static boolean allowV = true; // public static boolean allowW = true; // public static boolean allowWtf = true; private static String generateTag(StackTraceElement caller) { String tag = "%s.%s(Line:%d)"; // 佔位符 String callerClazzName = caller.getClassName(); // 獲取到類名 callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1); tag = String.format(tag,callerClazzName,caller.getMethodName(),caller.getLineNumber()); // 替換 tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":" + tag; return tag; } /*** * 列印控制檯顯示不了那麼長的日誌問題 * * @param msg */ public static void logE(String msg) { // 資訊太長,分段列印 if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); // 因為String的length是字元數量不是位元組數量所以為了防止中文字元過多, // 把4*1024的MAX位元組列印長度改為2001字元數 int max_str_length = 2001 - tag.length(); // 大於4000時 while (msg.length() > max_str_length) { // Log.e(tag,msg.substring(0,max_str_length)); LogUtils.e(msg.substring(0,max_str_length)); msg = msg.substring(max_str_length); } // 剩餘部分 // Log.e(tag,msg); LogUtils.e(msg); } /** * 自定義的logger */ public static CustomLogger customLogger; public interface CustomLogger { void d(String tag,String content); void d(String tag,String content,Throwable tr); void e(String tag,String content); void e(String tag,Throwable tr); void i(String tag,String content); void i(String tag,Throwable tr); void v(String tag,String content); void v(String tag,Throwable tr); void w(String tag,String content); void w(String tag,Throwable tr); void wtf(String tag,String content); void wtf(String tag,Throwable tr); } public static void d(String content) { if (!allowD) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.d(tag,content); } else { Log.d(tag,content); } } public static void d(String content,Throwable tr) { if (!allowD) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.d(tag,content,tr); } else { Log.d(tag,tr); } } public static void e(String content) { if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.e(tag,content); } else { Log.e(tag,content); } if (isSaveLog) { point(cacheDirPath,tag,content); } } public static void e(String content,Throwable tr) { if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.e(tag,tr); } else { Log.e(tag,tr); } if (isSaveLog) { point(cacheDirPath,tr.getMessage()); } } public static void e(Throwable tr) { if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.e(tag,"",tr.getMessage()); } } public static void i(String content) { if (!allowI) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.i(tag,content); } else { Log.i(tag,content); } } public static void i(String content,Throwable tr) { if (!allowI) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.i(tag,tr); } else { Log.i(tag,tr); } } public static void v(String content) { if (!allowV) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.v(tag,content); } else { Log.v(tag,content); } } public static void v(String content,Throwable tr) { if (!allowV) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.v(tag,tr); } else { Log.v(tag,tr); } } public static void w(String content) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,content); } else { Log.w(tag,content); } } public static void w(String content,Throwable tr) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,tr); } else { Log.w(tag,tr); } } public static void w(Throwable tr) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,tr); } } public static void wtf(String content) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,content); } else { Log.wtf(tag,content); } } public static void wtf(String content,Throwable tr) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,tr); } else { Log.wtf(tag,tr); } } public static void wtf(Throwable tr) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,tr); } } private static StackTraceElement getCallerStackTraceElement() { return Thread.currentThread().getStackTrace()[4]; } public static void point(String path,String tag,String msg) { if (isSDAva()) { path = cacheDirPath; Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("",Locale.SIMPLIFIED_CHINESE); dateFormat.applyPattern("yyyy"); path = path + dateFormat.format(date) + "/"; dateFormat.applyPattern("MM"); path += dateFormat.format(date) + "/"; dateFormat.applyPattern("dd"); path += dateFormat.format(date) + ".log"; dateFormat.applyPattern("[yyyy-MM-dd HH:mm:ss]"); String time = dateFormat.format(date); File file = new File(path); if (!file.exists()) createDipPath(path); BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true))); out.write(time + " " + tag + " " + msg + "\r\n"); } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } } /** * 根據檔案路徑 遞迴建立檔案 * * @param file */ public static void createDipPath(String file) { String parentFile = file.substring(0,file.lastIndexOf("/")); File file1 = new File(file); File parent = new File(parentFile); if (!file1.exists()) { parent.mkdirs(); try { file1.createNewFile(); LogUtils.e("日誌檔案的路徑是" + file1.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } } } /** * A little trick to reuse a formatter in the same thread */ private static class ReusableFormatter { private Formatter formatter; private StringBuilder builder; public ReusableFormatter() { builder = new StringBuilder(); formatter = new Formatter(builder); } public String format(String msg,Object... args) { formatter.format(msg,args); String s = builder.toString(); builder.setLength(0); return s; } } private static final ThreadLocal<ReusableFormatter> thread_local_formatter = new ThreadLocal<ReusableFormatter>() { protected ReusableFormatter initialValue() { return new ReusableFormatter(); } }; public static String format(String msg,Object... args) { ReusableFormatter formatter = thread_local_formatter.get(); return formatter.format(msg,args); } public static boolean isSDAva() { if (cacheDirPath == null) cacheDirPath = App.getAppContext().getExternalFilesDir("log").getAbsolutePath(); if (!TextUtils.isEmpty(cacheDirPath)) { return true; } else { return false; } } }
補充知識:Android日誌列印類LogUtils,能夠定位到類名,方法名以及出現錯誤的行數並儲存日誌檔案
在開發中,我們常常用列印log的方式來除錯我們的應用。在Java中我們常常使用方法System.out.println()來在控制檯列印日誌,以便我們的除錯。Android中有一個專門的類Log來實現在Android系統下日誌的列印,更加方便我們定位程式出現問題的地方。
但是Android官方提供的Log類在實際專案使用中,也不是非常方便。當程式出現錯誤時,我們最希望的就是這個Log類能幫我們定位到是哪個類的哪個方法,甚至於是那一行出現了錯誤。這樣就能給我們的除錯帶來很大的便利。
同時我們也應該想到為了應用程式的安全起見,在app正式上線之前,我們應該要把列印日誌的功能關閉掉,以防別人通過Log來破解你的應用。生產模式的下列印Log,正式模式就把列印日誌的功能關閉掉,要做到Log的靈活關閉與開啟,也需要在原生的Log類上進行一些封裝。
還有一種時候,當我們的程式出現問題崩潰了,我們希望能夠收集到出現異常的原因進行分析,所以可以把Log日誌儲存到一個檔案中,放在SD卡程式建立的目錄下。也可以在使用者聯網的情況下,在程式的後臺把出異常的Log日誌檔案上傳到服務端,方便程式設計師進行分析,解決bug。
今天就給大家分享一個做專案中很實用的一個Log類LogUtils,這個類是從xUtils中提取出來,稍作修改的,有註釋。
示例:
我們在MainActivity中呼叫一些LogUtils中的方法,注意看行數。 1
接著看看控制檯列印的日誌是不是像MainActivity呼叫的那樣,Log中有這個類的名字和oncreate方法名,已及當前行數; 2
看到上圖中的Log日誌是不是很方便定位程式中的問題了,出現異常也能快速的定位到。然後把下面的Log型別在程式的任何地方設定為false則不會列印日誌,使用起來相當的方便。
// 容許列印日誌的型別,預設是true,設定為false則不列印 public static boolean allowD = true; public static boolean allowE = true; public static boolean allowI = true; public static boolean allowV = true; public static boolean allowW = true; public static boolean allowWtf = true;
程式碼貼在下面:
package com.finddreams.log; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Formatter; import java.util.Locale; import android.os.Environment; import android.text.TextUtils; import android.util.Log; /** * Log工具,類似android.util.Log。 tag自動產生,格式: * customTagPrefix:className.methodName(Line:lineNumber),* customTagPrefix為空時只輸出:className.methodName(Line:lineNumber)。 */ public class LogUtils { public static String customTagPrefix = "finddreams"; // 自定義Tag的字首,可以是作者名 private static final boolean isSaveLog = false; // 是否把儲存日誌到SD卡中 public static final String ROOT = Environment.getExternalStorageDirectory() .getPath() + "/finddreams/"; // SD卡中的根目錄 private static final String PATH_LOG_INFO = ROOT + "info/"; private LogUtils() { } // 容許列印日誌的型別,預設是true,設定為false則不列印 public static boolean allowD = true; public static boolean allowE = true; public static boolean allowI = true; public static boolean allowV = true; public static boolean allowW = true; public static boolean allowWtf = true; private static String generateTag(StackTraceElement caller) { String tag = "%s.%s(Line:%d)"; // 佔位符 String callerClazzName = caller.getClassName(); // 獲取到類名 callerClazzName = callerClazzName.substring(callerClazzName .lastIndexOf(".") + 1); tag = String.format(tag,caller.getLineNumber()); // 替換 tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":" + tag; return tag; } /** * 自定義的logger */ public static CustomLogger customLogger; public interface CustomLogger { void d(String tag,String content); void d(String tag,Throwable tr); void e(String tag,String content); void e(String tag,Throwable tr); void i(String tag,String content); void i(String tag,Throwable tr); void v(String tag,String content); void v(String tag,Throwable tr); void w(String tag,String content); void w(String tag,Throwable tr); void wtf(String tag,String content); void wtf(String tag,Throwable tr); } public static void d(String content) { if (!allowD) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.d(tag,content); } else { Log.d(tag,content); } } public static void d(String content,Throwable tr) { if (!allowD) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.d(tag,tr); } else { Log.d(tag,tr); } } public static void e(String content) { if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.e(tag,content); } else { Log.e(tag,content); } if (isSaveLog) { point(PATH_LOG_INFO,content); } } public static void e(String content,Throwable tr) { if (!allowE) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.e(tag,tr); } else { Log.e(tag,tr); } if (isSaveLog) { point(PATH_LOG_INFO,tr.getMessage()); } } public static void i(String content) { if (!allowI) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.i(tag,content); } else { Log.i(tag,content); } } public static void i(String content,Throwable tr) { if (!allowI) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.i(tag,tr); } else { Log.i(tag,tr); } } public static void v(String content) { if (!allowV) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.v(tag,content); } else { Log.v(tag,content); } } public static void v(String content,Throwable tr) { if (!allowV) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.v(tag,tr); } else { Log.v(tag,tr); } } public static void w(String content) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,content); } else { Log.w(tag,content); } } public static void w(String content,Throwable tr) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,tr); } else { Log.w(tag,tr); } } public static void w(Throwable tr) { if (!allowW) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.w(tag,tr); } } public static void wtf(String content) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,content); } else { Log.wtf(tag,content); } } public static void wtf(String content,Throwable tr) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,tr); } else { Log.wtf(tag,tr); } } public static void wtf(Throwable tr) { if (!allowWtf) return; StackTraceElement caller = getCallerStackTraceElement(); String tag = generateTag(caller); if (customLogger != null) { customLogger.wtf(tag,tr); } } private static StackTraceElement getCallerStackTraceElement() { return Thread.currentThread().getStackTrace()[4]; } public static void point(String path,String msg) { if (isSDAva()) { Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("",Locale.SIMPLIFIED_CHINESE); dateFormat.applyPattern("yyyy"); path = path + dateFormat.format(date) + "/"; dateFormat.applyPattern("MM"); path += dateFormat.format(date) + "/"; dateFormat.applyPattern("dd"); path += dateFormat.format(date) + ".log"; dateFormat.applyPattern("[yyyy-MM-dd HH:mm:ss]"); String time = dateFormat.format(date); File file = new File(path); if (!file.exists()) createDipPath(path); BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file,true))); out.write(time + " " + tag + " " + msg + "\r\n"); } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } } /** * 根據檔案路徑 遞迴建立檔案 * * @param file */ public static void createDipPath(String file) { String parentFile = file.substring(0,file.lastIndexOf("/")); File file1 = new File(file); File parent = new File(parentFile); if (!file1.exists()) { parent.mkdirs(); try { file1.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } /** * A little trick to reuse a formatter in the same thread */ private static class ReusableFormatter { private Formatter formatter; private StringBuilder builder; public ReusableFormatter() { builder = new StringBuilder(); formatter = new Formatter(builder); } public String format(String msg,Object... args) { formatter.format(msg,args); String s = builder.toString(); builder.setLength(0); return s; } } private static final ThreadLocal<ReusableFormatter> thread_local_formatter = new ThreadLocal<ReusableFormatter>() { protected ReusableFormatter initialValue() { return new ReusableFormatter(); } }; public static String format(String msg,Object... args) { ReusableFormatter formatter = thread_local_formatter.get(); return formatter.format(msg,args); } public static boolean isSDAva() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED) || Environment.getExternalStorageDirectory().exists()) { return true; } else { return false; } } }
以上這篇android 日誌檔案LogUtils例項就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。