Android Logger 日志框架實(shí)現(xiàn)

寫在前面

這篇文章也是我以前寫在CSDN上的文章...


可以這樣說,Log日志是除了debug外我們調(diào)試程序的全部了,但是在實(shí)際的開發(fā)中,系統(tǒng)原生的Log功能并不強(qiáng)大,它只能打印簡單的字符串,如果碰到JSON,MAP一類的特殊字符串它的打印效果將極其糟糕。

機(jī)緣巧合下,我有幸見在github上見到了一個功能很強(qiáng)大的LOG日志庫Logger,它功能強(qiáng)大,當(dāng)你使用它打印LOG日志時,它不僅能把普通的字符串打印出來,甚至能定位你打印的位置。并且它能直接將JSON字符串格式化并打印出來,省下了我們手動格式化JSON字符串的時間。

下面是它的打印效果圖


效果圖

簡單Logger日志實(shí)現(xiàn)

好了,看完Logger的功能介紹和效果圖,想必你也很心動,也想要搞這樣一個Logger庫。
現(xiàn)在如果你想擁有這樣一個日志系統(tǒng),那么有兩個簡單的方法來供你選擇:
一、Clone 點(diǎn)擊我,然后關(guān)閉此窗口...
二、繼續(xù)往下看。


非常感謝你留下來繼續(xù)看我的廢話,現(xiàn)在讓我們一起研究Logger的主要功能吧!

JSON格式化部實(shí)現(xiàn)

當(dāng)我第一次使用Logger JSON格式化的功能時,我心情是悲傷的,因?yàn)樗屛覓仐壛伺惆槲叶嗄甑腏SON格式化網(wǎng)頁。本著無比悲痛的心情,有生以來我第一次極其認(rèn)真的查看了開源項(xiàng)目的代碼。
后來,看完代碼后的我,心情是崩潰的,原本以為JOSN格式化這么高達(dá)上的功能一定是很復(fù)雜的代碼實(shí)現(xiàn),后來發(fā)現(xiàn)尼瑪就一行代碼就能搞定,這是什么鬼啊,說好的復(fù)雜代碼呢??

    /**
     * 打印JSON
     *
     * @param jsonStr
     */
    public static void j(String jsonStr) {
        if (isDebug) {
            String message;
            try {
                if (jsonStr.startsWith("{")) {
                    JSONObject jsonObject = new JSONObject(jsonStr);
                    message = jsonObject.toString(JSON_INDENT); //這個是核心方法
                } else if (jsonStr.startsWith("[")) {
                    JSONArray jsonArray = new JSONArray(jsonStr);
                    message = jsonArray.toString(JSON_INDENT);
                } else {
                    message = jsonStr;
                }
            } catch (JSONException e) {
                message = jsonStr;
            }

            message = LINE_SEPARATOR + message;
            String[] lines = message.split(LINE_SEPARATOR);
            StringBuilder sb = new StringBuilder();
            printLog(D, lines);//請不要關(guān)注這行,這是控制臺輸出的Log方法
        }
    }

以上就是JSON格式化的方法,想必你和我當(dāng)初一樣充滿了錯愕,我們每天都在用toString()、toString()...然后竟然不知道還有個toString(int xxxx)的重載方法!?。?!

是的,高大上的JSON格式化功能不需要你998行代碼,也不需要你99行代碼,沒錯,你沒看錯,它就只需要你一行toString(int xxxx),并且附帶贈送你xxxx個縮進(jìn)空格?。?/p>

代碼定位的實(shí)現(xiàn)

當(dāng)年,我還是個孩子的時候我就知道我很無知,后來當(dāng)我看了Logger的Json格式化代碼的實(shí)現(xiàn)后,我已經(jīng)對它不屑一顧。后來當(dāng)我看了代碼定位的功能后,我覺得我還是太年輕了...

    /**
     * 代碼定位
     *
     * @param type
     */
    private static void printLocation(char type, String... msg) {
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        int i = 0;
        //獲取代碼所運(yùn)行的位置
        for (StackTraceElement e : stack) {
            String name = e.getClassName();
            if (!name.equals(L.class.getName())) {
                i++;
            } else {
                break;
            }
        }
        //進(jìn)行方法位置偏移
        i += 3;
        //當(dāng)我能準(zhǔn)確獲取到I時,本部分已經(jīng)完結(jié),以下代碼都是廢話,請不要關(guān)注
        String className = stack[i].getFileName();
        String methodName = stack[i].getMethodName();
        int lineNumber = stack[i].getLineNumber();
        StringBuilder sb = new StringBuilder();
        printHunk(type, HORIZONTAL_DOUBLE_LINE + "   Location:");
        sb.append(HORIZONTAL_DOUBLE_LINE)
                .append("   (").append(className).append(":").append(lineNumber).append(")# ").append(methodName);
        printHunk(type, sb.toString());
        printHunk(type, msg == null || msg.length == 0 ? BOTTOM_BORDER : MIDDLE_BORDER);
    }

注:上面并不是純粹的Logger源碼,那是我根據(jù)Logger的思路自己寫的代碼定位功能,事實(shí)上Logger源代碼那部分寫得很優(yōu)秀,但是你也懂的,優(yōu)秀也就意味著代碼不好看懂...

好吧,我承認(rèn),我當(dāng)初就是因?yàn)榭催@部分看得心煩,感覺很不爽,然后一怒之下,根據(jù)它的思路重新來寫的。。。

好吧,現(xiàn)在來所說代碼定位的原理。
如下圖所示:


元素攔截

我想,上面的圖你一定很熟悉,沒錯,那就是我們經(jīng)常用的debug 然后watch某個元素時候的界面。
在上面的圖片中,我們看到了一堆數(shù)組,其中圈紅色的部分是不是感覺有點(diǎn)特殊,因?yàn)榘⒉皇窍到y(tǒng)的包名,那些都是我們自己的類,自己的方法的元素。

現(xiàn)在,我想聰明的你已經(jīng)懂了,代碼定位的原理是通過Thread.currentThread().getStackTrace()方法獲取到所有的運(yùn)行元素,并根據(jù)獲取到的數(shù)組,進(jìn)行一定的偏移來準(zhǔn)確捕獲Looger( )被調(diào)用的真正位置。

根據(jù)JVM的運(yùn)行原理,每當(dāng)JVM執(zhí)行一個方法時,它都會把該方法壓到一個方法棧里面,根據(jù)棧的后入先出原則,我們可以知道,Logger( )被調(diào)用的位置一定是方法棧里面最先被壓入的函數(shù)的位置。也就是紅圈里面的最后一個元素。也就是我為什么要 i += 3的原因;

附上我自己寫的類L(Logger)的調(diào)用流程:


L流程

我們終于獲取到了代碼所在行的確切位置了,要在控制臺上實(shí)現(xiàn)代碼定位也就簡單多了。

根據(jù)獲取到的StackTraceElement元素,我們能通過api接口獲取到運(yùn)行類的類名及其該方法所被調(diào)用的位置,然后按照下面的格式進(jìn)行封裝,便能實(shí)現(xiàn)控制臺代碼的定位。
代碼定位格式:
(類名:代碼行)
只要按照上面的規(guī)則進(jìn)行組合類名和行,再通過系統(tǒng)提供的Log進(jìn)行輸出,便能通過控制臺直接跳轉(zhuǎn)到所在的代碼行。

打印Map

這個沒啥好說的...

     /**
     * 打印MAp
     */
    public static void m(Map map) {
        Set set = map.entrySet();
        if (set.size() < 1) {
            printLog(D, "[]");
            return;
        }

        int i = 0;
        String[] s = new String[set.size()];
        for (Object aSet : set) {
            Map.Entry entry = (Map.Entry) aSet;
            s[i] = entry.getKey() + " = " + entry.getValue() + ",\n";
            i++;
        }
        printLog(V, s);
    }

最終效果

最終效果
最終效果

最重要的還是放在最后面

我是偉大的DEMO

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,654評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,211評論 25 708
  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時待吾閱讀 5,161評論 0 6
  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時待吾閱讀 5,232評論 1 13
  • 本文參加#感悟三下鄉(xiāng),青春筑夢行?;顒樱恼聝?nèi)容為原創(chuàng),且未在其他平臺發(fā)表過。 作者:張子旭 我是生科院15級生態(tài)...
    奕工閱讀 628評論 0 0

友情鏈接更多精彩內(nèi)容