Android 日志記錄雜談-Logger,Timber,logback-android

10083523,2560,1600.jpg

首先艺蝴,希望大家不要噴我。如果哪里不對(duì)际起,希望大家能在下面評(píng)論說(shuō)明下,然后我進(jìn)行修改。

-----------------------我是不分割不舒服君-----------------------------------------

“Every time you log in production, a puppy dies.” – Jake Wharton

做安卓項(xiàng)目中,調(diào)試程序的時(shí)候一般會(huì)進(jìn)行打log來(lái)查看相關(guān)信息街望,而我原來(lái)是使用的系統(tǒng)自帶的Log來(lái)打印校翔。

歸結(jié)二個(gè)問(wèn)題:<信息顯示>,<信息存儲(chǔ)>灾前,就這二個(gè)問(wèn)題我們具體來(lái)看如何解決

-----------------------主體分割君---------------------------------------------------

1.信息顯示

可能代碼中你是這么寫的log:Log.v(tag,"XXXX");當(dāng)項(xiàng)目越來(lái)越多了防症。你查看log的時(shí)候發(fā)現(xiàn),這個(gè)log信息不知道是哪個(gè)文件甚至哪段代碼生成的豫柬,然后又要回頭去找寫這段log代碼告希。而且一大片log信息挑出來(lái)后你看的眼睛也要花了。這時(shí)候我們是不是沒(méi)辦法烧给,只能大海撈針一樣來(lái)看燕偶,或者關(guān)鍵字tag來(lái)搜索。答案當(dāng)然是不用础嫡。(這B裝的我好累)

所以根據(jù)這個(gè)情況我網(wǎng)上搜索后指么,發(fā)現(xiàn)挺多推薦Logger,于是我便使用Logger榴鼎。

看到Logger所能提供的功能:

1.Thread information

2.Class information

3.Method information

4.Pretty-print for json content

5.Pretty-print for new line "\n"

6.Clean output

7.Jump to source

先上Logger源碼地址:https://github.com/orhanobut/logger
首先在build.gradle中引入Logger:
compile 'com.orhanobut:logger:1.15'
然后直接在代碼中就可以使用Logger了伯诬。先看效果:

public class Act_Logger extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       //設(shè)置tagname,可以不寫,默認(rèn)為“PRETTYLOGGER”
      //  Logger.init("tagname");

        String name = "billy";
        Logger.d("你好啊巫财,某某人");
        Logger.d("你好啊盗似,%s",name);
        getString(name);

        ArrayList<UserBean> list = new ArrayList<UserBean>();
        list.add(new UserBean("user1",1));
        list.add(new UserBean("user2",2));
        list.add(new UserBean("user3",3));
        list.add(new UserBean("user4",4));

        Logger.d(list);

    }

    public void getString(String name){
        Logger.e("你好啊,%s",name);
    }
}
屏幕快照 2016-11-24 11.40.22 AM.png

我們從Log信息中可以查看到線程的name,具體到哪個(gè)類平项,哪個(gè)方法赫舒,都有顯示,而且Log信息也十分美觀闽瓢。
而且可以點(diǎn)擊跳到相應(yīng)的代碼處接癌。十分方便,同時(shí)打印的時(shí)候支持Array, Map, Set 和 List扣讼。

description.png

什么缺猛,你覺(jué)得這樣也沒(méi)怎么樣?那么如果你想查看一個(gè)json的信息椭符,原來(lái)的log中json的排版也不(keng)錯(cuò)(die)荔燎,現(xiàn)在來(lái)看看Logger中的json的信息顯示。

logger-log.png

瞬間感覺(jué)高大上销钝『ⅲ快給同事們看看。

這里提到一個(gè)小功能曙搬,為啥

   Logger.d("你好啊摔吏,某某人");
   Logger.d("你好啊鸽嫂,%s",name);

都可以支持。

是因?yàn)樽罱K都調(diào)用了

private String createMessage(String message, Object... args) {      
    return args == null || args.length == 0 ? message : String.format(message, args);
}

然后再用系統(tǒng)的Log來(lái)打印字符串征讲。

主要我覺(jué)得createMessage這個(gè)代碼片段可以拿來(lái)作為util工具的一個(gè)方法挺方便的据某。就拿來(lái)用在自己項(xiàng)目里面了。

2.信息存儲(chǔ)

Log如果我們用手機(jī)連著電腦調(diào)試诗箍,這時(shí)候是方便癣籽,可以一邊操作一邊查看信息,但是萬(wàn)一是安裝到了某個(gè)客戶手機(jī)上滤祖,或者某個(gè)安卓設(shè)備上筷狼,這時(shí)候你有某個(gè)需求需要去知道他的Log的信息,那時(shí)候難道你要連著電腦一邊操作一邊查看Log信息匠童?

這里網(wǎng)上我又查看了下埂材,還是老套路,發(fā)現(xiàn)大家推薦Timber汤求。然后我就使用了Timber俏险。這個(gè)其實(shí)是Log的封裝庫(kù),廢話不多說(shuō)扬绪。脫光衣服直接上竖独。

老套路,先附上Timber的源碼地址:
https://github.com/JakeWharton/timber

在build.grade中引入Timber:
compile 'com.jakewharton.timber:timber:4.3.1'

在繼承Application的自定義類中挤牛,設(shè)置Timber的樹莹痢,其實(shí)Timber是類似管理著一片森林,具體用哪棵樹是你自己這邊決定的墓赴。比如Timber自帶的是DebugTree這個(gè)類竞膳。

@Override
public void onCreate() {    
          super.onCreate();    
         //在這里先使用Timber.plant注冊(cè)一個(gè)Tree,然后調(diào)用靜態(tài)的.d .v 去使用     
          if (BuildConfig.DEBUG) {    
                Timber.plant(new Timber.DebugTree());    
          } else {        
                Timber.plant(new FileLoggingTree());    
          }
}

然后就可以使用了

Timber.tag("code_gg");        
Timber.d("test Timber %d",10);

然后上面的FileLoggingTree是我這邊自己寫的一棵樹竣蹦,就是當(dāng)我用Timber這個(gè)封裝庫(kù)拿到了Log的信息后,后面就可以我們自己處理了沧奴。比如寫到文件中等痘括。我這邊先寫了一個(gè)傻白甜的FileLoggingTree類,僅供參考滔吠。后面我們會(huì)用到另外一個(gè)第三方纲菌,就更強(qiáng)大了。

其中String CacheDiaPath = context.getCacheDir().toString();

private static class FileLoggingTree extends Timber.Tree {
        @Override
        protected void log(int priority, String tag, String message, Throwable t) {
            if (TextUtils.isEmpty(CacheDiaPath)) {
                return;
            }
            File file = new File(CacheDiaPath + "/log.txt");
            Log.v("dyp", "file.path:" + file.getAbsolutePath() + ",message:" + message);
            FileWriter writer = null;
            BufferedWriter bufferedWriter = null;
            try {
                writer = new FileWriter(file);
                bufferedWriter = new BufferedWriter(writer);
                bufferedWriter.write(message);
                bufferedWriter.flush();

            } catch (IOException e) {
                Log.v("dyp", "存儲(chǔ)文件失敗");
                e.printStackTrace();
            } finally {
                if (bufferedWriter != null) {
                    try {
                        bufferedWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
}

log方法參數(shù)一共有int priority, String tag, String message, Throwable t這四個(gè)參數(shù)疮绷,而我這邊就是簡(jiǎn)單的拿了message這個(gè)參數(shù)的內(nèi)容翰舌,然后保存到了我指定路徑下的log.txt文件中。當(dāng)然Timber可以自己封裝.

比如還有記錄崩潰信息的樹

 /**
     * A tree which logs important information for crash reporting.
     */
    private static class CrashReportingTree extends Timber.Tree {
        @Override
        protected void log(int priority, String tag, String message, Throwable t) {
            if (priority == Log.VERBOSE || priority == Log.DEBUG) {
                return;
            }
            FakeCrashLibrary.log(priority, tag, message);
            if (t != null) {
                if (priority == Log.ERROR) {
                    FakeCrashLibrary.logError(t);
                } else if (priority == Log.WARN) {
                    FakeCrashLibrary.logWarning(t);
                }
            }
        }
    }

當(dāng)然我覺(jué)得我寫的挺low的冬骚。后來(lái)我又去查看了一些能寫到文件中的log的第三方椅贱。發(fā)現(xiàn)了logback-android懂算。
logback-android很強(qiáng)大,可以存儲(chǔ)信息到
-files
-SQLite databases
-logcat
-sockets
-syslog
-email

所以我們可以用Timber配合logback-android來(lái)模擬存儲(chǔ)到文件中庇麦。

首先又是老樣子计技,附上logback-android源碼地址:
https://github.com/tony19/logback-android

第一步:引入logback-android

Gradle

// only needed for SNAPSHOT builds
repositories {
  maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}

dependencies {
  compile 'org.slf4j:slf4j-api:1.7.21'
  compile 'com.github.tony19:logback-android-core:1.1.1-6'
  compile 'com.github.tony19:logback-android-classic:1.1.1-6'
}

第二步:在以下位置創(chuàng)建一個(gè)logback.xml文件,默認(rèn)情況下這個(gè)路徑和文件名是固定的

Paste_Image.png

第三步:配置logback文件

<!--debug屬性用來(lái)決定是否打印logback的日志信息-->
<configuration debug='false'>

    <!--聲明一個(gè)屬性,用來(lái)指定log文件存放的路徑-->
    <property name="LOG_DIR" value="/sdcard/rlog"/>

    <!--聲明一個(gè)時(shí)間戳-->
    <timestamp datePattern="yyyyMMdd" key="today"/>

    <!--用于在控制臺(tái)輸出的Appender-->
    <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
        <encoder>
            <pattern>%-5relative [%thread][%file:%M:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <!--聲明一個(gè)FileAppender-->
    <appender name="BASE_FILE" class="ch.qos.logback.core.FileAppender">
        <!--初始化的時(shí)候不創(chuàng)建文件,在第一次使用的時(shí)候創(chuàng)建文件-->
        <lazy>true</lazy>
        <!--log追加到文件,否則覆蓋文件-->
        <append>true</append>
        <!--用來(lái)保存log的文件全路徑-->
        <file>${LOG_DIR}/base.log</file>
        <!--輸出log的格式-->
        <encoder>
            <!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n</pattern>-->
            <pattern>%date [%thread] %-5level %logger{36} [%file:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <!--聲明一個(gè)RollingFileAppender-->
    <appender name="BASE_ROLL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/base.roll.${today}.log</file>
        <append>true</append>
        <encoder>
            <pattern>%date %-5relative [%thread] %-5level %logger{36} [%file:%M:%line] - %msg%n
            </pattern>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/base.roll.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!--最大保存7天的日志-->
            <maxHistory>7</maxHistory>
        </rollingPolicy>

        <!--文件大于10mb,切換文件-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>10MB</maxFileSize>
        </triggeringPolicy>
    </appender>

    <!--指定logtest采用BASE_ROLL_FILE聲明的RollingFileAppender輸出日志-->
    <logger name="logtest">
        <appender-ref ref="BASE_ROLL_FILE"/>
    </logger>

    <!-- Write INFO (and higher-level) messages to the log file -->
    <root level="TRACE">
        <appender-ref ref="LOGCAT"/>
    </root>

    <!--支持的level-->
    <!--TRACE-->
    <!--DEBUG-->
    <!--INFO-->
    <!--WARN-->
    <!--ERROR-->

    <!--<pattern>
      %d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n
      Logger: %logger
      Class: %class
      File: %file
      Caller: %caller
      Line: %line
      Message: %m
      Method: %M
      Relative: %relative
      Thread: %thread
      Exception: %ex
      xException: %xEx
      nopException: %nopex
      rException: %rEx
      Marker: %marker
      %n
  </pattern>-->

    <!--引用其他位置的配置信息-->
    <!--<includes>-->
    <!--<include file="/sdcard/foo.xml"/>-->
    <!--<include resource="assets/config/test.xml"/>-->
    <!--<include resource="AndroidManifest.xml"/>-->

    <!--<include file="/sdcard/logback/logback-test.xml"/>-->
    <!--<include file="/sdcard/logback/logback.xml"/>-->
    <!--<include resource="AndroidManifest.xml"/>-->
    <!--<include resource="assets/logback-test.xml"/>-->
    <!--<include resource="assets/logback.xml"/>-->
    <!--</includes>-->
</configuration>

還有其他的appender提供,詳細(xì)說(shuō)明移步: http://logback.qos.ch/manual/appenders.html

第四步:
可以在代碼里面使用logback-android了

//以下日志只會(huì)在控制臺(tái)輸出
//        Logger logger = LoggerFactory.getLogger(MainActivity.class);
//        logger.trace("angcyo-->{}","trace");
//        logger.debug("angcyo-->{}","debug");
//        logger.info("angcyo-->{}","info");
//        logger.warn("angcyo-->{}","warn");
//        logger.error("angcyo-->{}","error");

//以下日志會(huì)在BASE_ROLL_FILE聲明的文件中輸出,并且也會(huì)在控制臺(tái)輸出
        Logger logger = LoggerFactory.getLogger("logtest");
        logger.trace("angcyo-->{}","trace");
        logger.debug("angcyo-->{}","debug");
        logger.info("angcyo-->{}","info");
        logger.warn("angcyo-->{}","warn");
        logger.error("angcyo-->{}","error");

保存在文件中的Log信息:

Paste_Image.png

現(xiàn)在可以用logback-android 來(lái)寫一顆樹供Timber來(lái)使用:

public class FileLoggingTree extends Timber.DebugTree {

    static Logger mLogger = LoggerFactory.getLogger(FileLoggingTree.class);

    @Override
    protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE) {
            return;
        }

        String logMessage = tag + ": " + message;
        switch (priority) {
            case Log.DEBUG:
                mLogger.debug(logMessage);
                break;
            case Log.INFO:
                mLogger.info(logMessage);
                break;
            case Log.WARN:
                mLogger.warn(logMessage);
                break;
            case Log.ERROR:
                mLogger.error(logMessage);
                break;
        }
    }
}

然后再調(diào)用Timber.plant(new FileLoggingTree());就可以了山橄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末垮媒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子航棱,更是在濱河造成了極大的恐慌睡雇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饮醇,死亡現(xiàn)場(chǎng)離奇詭異它抱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驳阎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門抗愁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人呵晚,你說(shuō)我怎么就攤上這事蜘腌。” “怎么了饵隙?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵撮珠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我金矛,道長(zhǎng)芯急,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任驶俊,我火速辦了婚禮娶耍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饼酿。我一直安慰自己榕酒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布故俐。 她就那樣靜靜地躺著想鹰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪药版。 梳的紋絲不亂的頭發(fā)上辑舷,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音槽片,去河邊找鬼何缓。 笑死肢础,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歌殃。 我是一名探鬼主播乔妈,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼氓皱!你這毒婦竟也來(lái)了路召?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤波材,失蹤者是張志新(化名)和其女友劉穎股淡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廷区,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唯灵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隙轻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埠帕。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖玖绿,靈堂內(nèi)的尸體忽然破棺而出敛瓷,到底是詐尸還是另有隱情,我是刑警寧澤斑匪,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布呐籽,位于F島的核電站,受9級(jí)特大地震影響蚀瘸,放射性物質(zhì)發(fā)生泄漏狡蝶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一贮勃、第九天 我趴在偏房一處隱蔽的房頂上張望贪惹。 院中可真熱鬧,春花似錦寂嘉、人聲如沸奏瞬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丝格。三九已至撑瞧,卻和暖如春棵譬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背预伺。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工订咸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留曼尊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓脏嚷,卻偏偏與公主長(zhǎng)得像骆撇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子父叙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容