日志都毒,一個(gè)容易被邊緣化的事情

我們打印日志的時(shí)候都很隨意,用的時(shí)候會(huì)吐槽各種 碰缔!

日志是什么账劲?

日志,維基百科的定義是記錄服務(wù)器等電腦設(shè)備或軟件的運(yùn)作。

日志文件提供精確的系統(tǒng)記錄瀑焦,根據(jù)日志最終定位到錯(cuò)誤詳情和根源腌且。日志的特點(diǎn)是,它描述一些離散的(不連續(xù)的)事件榛瓮。

例如:應(yīng)用通過(guò)一個(gè)滾動(dòng)的文件輸出 INFO 或 ERROR 信息铺董,并通過(guò)日志收集系統(tǒng)禀晓,存儲(chǔ)到一些存儲(chǔ)引擎(Elasticsearch)中方便查詢精续。

日志有什么用?

在上文中我們解釋了日志的作用是提供精準(zhǔn)的系統(tǒng)記錄方便根因分析粹懒。那么具體在哪些具體方面它可以發(fā)揮作用重付?

①打印調(diào)試: 即可以用日志來(lái)記錄變量或者某一段邏輯。記錄程序運(yùn)行的流程凫乖,即程序運(yùn)行了哪些代碼确垫,方便排查邏輯問(wèn)題。

②問(wèn)題定位:程序出異趁毖浚或者出故障時(shí)快速的定位問(wèn)題删掀,方便后期解決問(wèn)題。因?yàn)榫€上生產(chǎn)環(huán)境無(wú)法 DEBUG导街,在測(cè)試環(huán)境去模擬一套生產(chǎn)環(huán)境披泪,費(fèi)時(shí)費(fèi)力。所以依靠日志記錄的信息定位問(wèn)題菊匿,這點(diǎn)非常重要付呕。還可以記錄流量,后期可以通過(guò) ELK(包括 EFK 進(jìn)行流量統(tǒng)計(jì))跌捆。

③用戶行為日志:記錄用戶的操作行為徽职,用于大數(shù)據(jù)分析,比如監(jiān)控佩厚、風(fēng)控姆钉、推薦等等。這種日志抄瓦,一般是給其他團(tuán)隊(duì)分析使用潮瓶,而且可能是多個(gè)團(tuán)隊(duì),因此一般會(huì)有一定的格式要求钙姊,開(kāi)發(fā)者應(yīng)該按照這個(gè)格式來(lái)記錄毯辅,便于其他團(tuán)隊(duì)的使用。當(dāng)然煞额,要記錄哪些行為思恐、操作沾谜,一般也是約定好的,因此胀莹,開(kāi)發(fā)者主要是執(zhí)行的角色基跑。

④根因分析(甩鍋必備):即在關(guān)鍵地方記錄日志。方便在和各個(gè)終端定位問(wèn)題時(shí)描焰,別人說(shuō)是你的程序問(wèn)題媳否,你可以理直氣壯的拿出你的日志說(shuō),看荆秦,我這里運(yùn)行了篱竭,狀態(tài)也是對(duì)的。這樣萄凤,對(duì)方就會(huì)乖乖去定位他的代碼室抽,而不是互相推脫。

什么時(shí)候記錄日志靡努?

上文說(shuō)了日志的重要性坪圾,那么什么時(shí)候需要記錄日志?

①系統(tǒng)初始化:系統(tǒng)或者服務(wù)的啟動(dòng)參數(shù)惑朦。核心模塊或者組件初始化過(guò)程中往往依賴一些關(guān)鍵配置兽泄,根據(jù)參數(shù)不同會(huì)提供不一樣的服務(wù)。務(wù)必在這里記錄 INFO 日志漾月,打印出參數(shù)以及啟動(dòng)完成態(tài)服務(wù)表述病梢。

②編程語(yǔ)言提示異常:如今各類(lèi)主流的編程語(yǔ)言都包括異常機(jī)制,業(yè)務(wù)相關(guān)的流行框架有完整的異常模塊梁肿。這類(lèi)捕獲的異常是系統(tǒng)告知開(kāi)發(fā)人員需要加以關(guān)注的蜓陌,是質(zhì)量非常高的報(bào)錯(cuò)。應(yīng)當(dāng)適當(dāng)記錄日志吩蔑,根據(jù)實(shí)際結(jié)合業(yè)務(wù)的情況使用 WARN 或者 ERROR 級(jí)別钮热。

③業(yè)務(wù)流程預(yù)期不符:除開(kāi)平臺(tái)以及編程語(yǔ)言異常之外,項(xiàng)目代碼中結(jié)果與期望不符時(shí)也是日志場(chǎng)景之一烛芬,簡(jiǎn)單來(lái)說(shuō)所有流程分支都可以加入考慮隧期。取決于開(kāi)發(fā)人員判斷能否容忍情形發(fā)生。常見(jiàn)的合適場(chǎng)景包括外部參數(shù)不正確赘娄,數(shù)據(jù)處理問(wèn)題導(dǎo)致返回碼不在合理范圍內(nèi)等等仆潮。

④系統(tǒng)核心角色,組件關(guān)鍵動(dòng)作:系統(tǒng)中核心角色觸發(fā)的業(yè)務(wù)動(dòng)作是需要多加關(guān)注的遣臼,是衡量系統(tǒng)正常運(yùn)行的重要指標(biāo)性置,建議記錄 INFO 級(jí)別日志。比如電商系統(tǒng)用戶從登錄到下單的整個(gè)流程揍堰;微服務(wù)各服務(wù)節(jié)點(diǎn)交互蚌讼;核心數(shù)據(jù)表增刪改辟灰;核心組件運(yùn)行等等,如果日志頻度高或者打印量特別大篡石,可以提煉關(guān)鍵點(diǎn) INFO 記錄,其余酌情考慮 DEBUG 級(jí)別西采。

⑤第三方服務(wù)遠(yuǎn)程調(diào)用:微服務(wù)架構(gòu)體系中有一個(gè)重要的點(diǎn)就是第三方永遠(yuǎn)不可信凰萨,對(duì)于第三方服務(wù)遠(yuǎn)程調(diào)用建議打印請(qǐng)求和響應(yīng)的參數(shù),方便在和各個(gè)終端定位問(wèn)題械馆,不會(huì)因?yàn)榈谌椒?wù)日志的缺失變得手足無(wú)措胖眷。

日志打印

Slf4j&Logback

Slf4j 英文全稱為 “ Simple Logging Facade for Java ”,為 Java 提供的簡(jiǎn)單日志門(mén)面霹崎。Facade 門(mén)面珊搀,更底層一點(diǎn)說(shuō)就是接口。它允許用戶以自己的喜好尾菇,在工程中通過(guò) Slf4j 接入不同的日志系統(tǒng)境析。Logback 是 Slf4j 的原生實(shí)現(xiàn)框架,同樣也是出自 Log4j 一個(gè)人之手派诬,但擁有比 Log4j 更多的優(yōu)點(diǎn)劳淆、特性和更做強(qiáng)的性能,Logback 相對(duì)于 Log4j 擁有更快的執(zhí)行速度默赂。
基于我們先前在 Log4j 上的工作沛鸵,Logback 重寫(xiě)了內(nèi)部的實(shí)現(xiàn),在某些特定的場(chǎng)景上面缆八,甚至可以比之前的速度快上 10 倍曲掰。在保證 Logback 的組件更加快速的同時(shí),同時(shí)所需的內(nèi)存更加少奈辰。

日志文件

日志文件放置于固定的目錄中栏妖,按照一定的模板進(jìn)行命名,推薦的日志文件名稱:

當(dāng)前正在寫(xiě)入的日志文件名:<應(yīng)用名>[-<功能名>].log
如:example-server-book-service-access.log

已經(jīng)滾入歷史的日志文件名:<應(yīng)用名>[-<功能名>].yyyy-MM-dd-hh.[滾動(dòng)號(hào)].log
如:example-server-book-service-access.2019-12-01-10.1.log

日志變量定義

推薦使用 lombok(代碼生成器) 注解 @lombok.extern.slf4j.Slf4j 來(lái)生成日志變量實(shí)例:

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
    <scope>provided</scope>
</dependency>
// 代碼示例
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogTest {
    public static void main(String[] args) {
        log.info("this is log test");
    }
}

日志配置

日志記錄采用分級(jí)記錄冯挎,級(jí)別與日志文件名相對(duì)應(yīng)底哥,不同級(jí)別的日志信息記錄到不同的日志文件中。如有特殊格式日志房官,如 access log趾徽,單獨(dú)使用一個(gè)文件,請(qǐng)注意避免重復(fù)打雍彩亍(可使用 additivity="false" 避免 )孵奶。

參數(shù)占位格式

使用參數(shù)化形式 {} 占位,[] 進(jìn)行參數(shù)隔離蜡峰,這樣的好處是可讀性更高了袁,而且只有真正準(zhǔn)備打印的時(shí)候才會(huì)處理參數(shù)朗恳。

// 正確示例,必須使用參數(shù)化信息的方式
log.debug("order is paying with userId:[{}] and orderId : [{}]",userId, orderId);
// 錯(cuò)誤示例载绿,不要進(jìn)行字符串拼接,那樣會(huì)產(chǎn)生很多 String 對(duì)象粥诫,占用空間,影響性能崭庸。及日志級(jí)別高于此級(jí)別也會(huì)進(jìn)行字符串拼接邏輯怀浆。
log.debug("order is paying with userId: " + userId + " and orderId: " + orderId);

日志的基本格式

①日志時(shí)間

作為日志產(chǎn)生的日期和時(shí)間,這個(gè)數(shù)據(jù)非常重要怕享,一般精確到毫秒执赡。

yyyy-MM-dd HH:mm:ss.SSS

②日志級(jí)別

日志的輸出都是分級(jí)別的,不同的設(shè)置不同的場(chǎng)合打印不同的日志函筋。主要使用如下的四個(gè)級(jí)別:

DEBUG:DEUBG 級(jí)別的主要輸出調(diào)試性質(zhì)的內(nèi)容沙合,該級(jí)別日志主要用于在開(kāi)發(fā)、測(cè)試階段輸出跌帐。

該級(jí)別的日志應(yīng)盡可能地詳盡首懈,開(kāi)發(fā)人員可以將各類(lèi)詳細(xì)信息記錄到 DEBUG 里,起到調(diào)試的作用含末,包括參數(shù)信息猜拾,調(diào)試細(xì)節(jié)信息,返回值信息等等佣盒,便于在開(kāi)發(fā)挎袜、測(cè)試階段出現(xiàn)問(wèn)題或者異常時(shí),對(duì)其進(jìn)行分析肥惭。

INFO:INFO 級(jí)別的主要記錄系統(tǒng)關(guān)鍵信息盯仪,旨在保留系統(tǒng)正常工作期間關(guān)鍵運(yùn)行指標(biāo),開(kāi)發(fā)人員可以將初始化系統(tǒng)配置蜜葱、業(yè)務(wù)狀態(tài)變化信息全景,或者用戶業(yè)務(wù)流程中的核心處理記錄到 INFO 日志中,方便日常運(yùn)維工作以及錯(cuò)誤回溯時(shí)上下文場(chǎng)景復(fù)現(xiàn)牵囤。

建議在項(xiàng)目完成后爸黄,在測(cè)試環(huán)境將日志級(jí)別調(diào)成 INFO,然后通過(guò) INFO 級(jí)別的信息看看是否能了解這個(gè)應(yīng)用的運(yùn)用情況揭鳞,如果出現(xiàn)問(wèn)題后是否這些日志能提供有用的排查問(wèn)題的信息炕贵。

WARN:WARN 級(jí)別的主要輸出警告性質(zhì)的內(nèi)容,這些內(nèi)容是可以預(yù)知且是有規(guī)劃的野崇,比如称开,某個(gè)方法入?yún)榭栈蛘咴搮?shù)的值不滿足運(yùn)行該方法的條件時(shí)。在 WARN 級(jí)別的時(shí)應(yīng)輸出較為詳盡的信息,以便于事后對(duì)日志進(jìn)行分析鳖轰。

ERROR:ERROR 級(jí)別主要針對(duì)于一些不可預(yù)知的信息清酥,諸如:錯(cuò)誤、異常等蕴侣,比如焰轻,在 catch 塊中抓獲的網(wǎng)絡(luò)通信、數(shù)據(jù)庫(kù)連接等異常昆雀,若異常對(duì)系統(tǒng)的整個(gè)流程影響不大鹦马,可以使用 WARN 級(jí)別日志輸出。

在輸出 ERROR 級(jí)別的日志時(shí)忆肾,盡量多地輸出方法入?yún)?shù)、方法執(zhí)行過(guò)程中產(chǎn)生的對(duì)象等數(shù)據(jù)菱肖,在帶有錯(cuò)誤客冈、異常對(duì)象的數(shù)據(jù)時(shí),需要將該對(duì)象一并輸出稳强。

③DEBUG/INFO 的選擇 DEBUG 級(jí)別比 INFO 低场仲,包含調(diào)試時(shí)更詳細(xì)的了解系統(tǒng)運(yùn)行狀態(tài)的東西,比如變量的值等等退疫,都可以輸出到 DEBUG 日志里渠缕。INFO 是在線日志默認(rèn)的輸出級(jí)別,反饋系統(tǒng)的當(dāng)前狀態(tài)給最終用戶看的褒繁。輸出的信息亦鳞,應(yīng)該對(duì)最終用戶具有實(shí)際意義的。從功能角度上說(shuō)棒坏,INFO 輸出的信息可以看作是軟件產(chǎn)品的一部分燕差,所以需要謹(jǐn)慎對(duì)待,不可隨便輸出坝冕。如果這條日志會(huì)被頻繁打印或者大部分時(shí)間對(duì)于糾錯(cuò)起不到作用徒探,就應(yīng)當(dāng)考慮下調(diào)為 DEBUG 級(jí)別:

  • 由于 DEBUG 日志打印量遠(yuǎn)大于 INFO,出于前文日志性能的考慮喂窟,如果代碼為核心代碼测暗,執(zhí)行頻率非常高,務(wù)必推敲日志設(shè)計(jì)是否合理磨澡,是否需要下調(diào)為 DEBUG 級(jí)別日志碗啄。

  • 注意日志的可讀性,不妨在寫(xiě)完代碼 review 這條日志是否通順钱贯,能否提供真正有意義的信息挫掏。

  • 日志輸出是多線程公用的,如果有另外一個(gè)線程正在輸出日志秩命,上面的記錄就會(huì)被打斷尉共,最終顯示輸出和預(yù)想的就會(huì)不一致褒傅。

④WARN/ERROR 的選擇 當(dāng)方法或者功能處理過(guò)程中產(chǎn)生不符合預(yù)期結(jié)果或者有框架報(bào)錯(cuò)時(shí)可以考慮使用。常見(jiàn)問(wèn)題處理方法包括:

  • 增加判斷處理邏輯袄友,嘗試本地解決:增加邏輯判斷吞掉報(bào)警永遠(yuǎn)是最優(yōu)選擇拋出異常殿托,交給上層邏輯解決

  • 拋出異常,交給上層邏輯解決

  • 記錄日志剧蚣,報(bào)警提醒

  • 使用返回碼包裝錯(cuò)誤做返回

一般來(lái)說(shuō)支竹,WARN 級(jí)別不會(huì)短信報(bào)警,ERROR 級(jí)別則會(huì)短信報(bào)警甚至電話報(bào)警鸠按,ERROR 級(jí)別的日志意味著系統(tǒng)中發(fā)生了非常嚴(yán)重的問(wèn)題礼搁,必須有人馬上處理,比如數(shù)據(jù)庫(kù)不可用目尖,系統(tǒng)的關(guān)鍵業(yè)務(wù)流程走不下去等等馒吴。錯(cuò)誤的使用反而帶來(lái)嚴(yán)重的后果,不區(qū)分問(wèn)題的重要程度瑟曲,只要有問(wèn)題就 ERROR 記錄下來(lái)饮戳。其實(shí)這樣是非常不負(fù)責(zé)任的,因?yàn)閷?duì)于成熟的系統(tǒng)洞拨,都會(huì)有一套完整的報(bào)錯(cuò)機(jī)制扯罐,那這個(gè)錯(cuò)誤信息什么時(shí)候需要發(fā)出來(lái),很多都是依據(jù)單位時(shí)間內(nèi) ERROR 日志的數(shù)量來(lái)確定的烦衣。

⑤強(qiáng)調(diào) ERROR 報(bào)警 ERROR 級(jí)別的日志打印通常伴隨報(bào)警通知歹河。ERROR 的報(bào)出應(yīng)該伴隨著業(yè)務(wù)功能受損,即上面提到的系統(tǒng)中發(fā)生了非常嚴(yán)重的問(wèn)題琉挖,必須有人馬上處理启泣。

ERROR 日志目標(biāo):給處理者直接準(zhǔn)確的信息,ERROR 信息形成自身閉環(huán)示辈。

問(wèn)題定位:

  • 發(fā)生了什么問(wèn)題寥茫,哪些功能受到影響

  • 獲取幫助信息:直接幫助信息或幫助信息的存儲(chǔ)位置

  • 通過(guò)報(bào)警知道解決方案或者找何人解決

⑥線程名稱

輸出該日志的線程名稱,一般在一個(gè)應(yīng)用中一個(gè)同步請(qǐng)求由同一線程完成矾麻,輸出線程名稱可以在各個(gè)請(qǐng)求產(chǎn)生的日志中進(jìn)行分類(lèi)纱耻,便于分清當(dāng)前請(qǐng)求上下文的日志。

⑦opentracing 標(biāo)識(shí)

在分布式應(yīng)用中险耀,用戶的一個(gè)請(qǐng)求會(huì)調(diào)用若干個(gè)服務(wù)完成弄喘,這些服務(wù)可能還是嵌套調(diào)用的,因此完成一個(gè)請(qǐng)求的日志并不在一個(gè)應(yīng)用的日志文件甩牺,而是分散在不同服務(wù)器上不同應(yīng)用節(jié)點(diǎn)的日志文件中蘑志。該標(biāo)識(shí)是為了串聯(lián)一個(gè)請(qǐng)求在整個(gè)系統(tǒng)中的調(diào)用日志:

  • 唯一字符串(trace id)

  • 調(diào)用層級(jí)(span id)

通過(guò)搜索 trace id 就可以查到這個(gè) trace id 標(biāo)識(shí)的請(qǐng)求在整個(gè)系統(tǒng)中流轉(zhuǎn)(處理)過(guò)程中產(chǎn)生的所有日志。

⑧biz 標(biāo)識(shí)

在業(yè)務(wù)開(kāi)發(fā)中,我們的日志都是和業(yè)務(wù)相關(guān)聯(lián)的急但,有時(shí)候是需要根據(jù)用戶或者業(yè)務(wù)做聚類(lèi)的澎媒,因此一次請(qǐng)求如果可以通過(guò)某項(xiàng)標(biāo)識(shí)做聚類(lèi)的時(shí)候,可以將聚類(lèi)標(biāo)識(shí)打印到日志中:

  • 用戶標(biāo)識(shí)(user id)

  • 業(yè)務(wù)標(biāo)識(shí)(biz id)

⑨日志記錄器名稱

日志記錄器名稱一般使用類(lèi)名波桩,日志文件中可以輸出簡(jiǎn)單的類(lèi)名即可戒努,看實(shí)際情況是否需要使用包名和行號(hào)等信息。主要用于看到日志后到哪個(gè)類(lèi)中去找這個(gè)日志輸出镐躲,便于定位問(wèn)題所在储玫。

⑩日志內(nèi)容

禁用 System.out.println 和 System.err.println。變參替換日志拼接萤皂,輸出日志的對(duì)象撒穷,應(yīng)在其類(lèi)中實(shí)現(xiàn)快速的 toString 方法,以便于在日志輸出時(shí)僅輸出這個(gè)對(duì)象類(lèi)名和 hashCode裆熙。預(yù)防空指針:不要在日志中調(diào)用對(duì)象的方法獲取值桥滨,除非確保該對(duì)象肯定不為 null,否則很有可能會(huì)因?yàn)槿罩镜膯?wèn)題而導(dǎo)致應(yīng)用產(chǎn)生空指針異常弛车。

?異常堆棧

異常堆棧一般會(huì)出現(xiàn)在 ERROR 或者 WARN 級(jí)別的日志中,異常堆棧含有方法調(diào)用鏈的系統(tǒng)蒲每,以及異常產(chǎn)生的根源纷跛。異常堆棧的日志屬于上一行日志的,在日志收集時(shí)需要將其劃至上一行中邀杏。

最佳實(shí)踐

①日志格式

2019-12-01 00:00:00.000|pid|log-level|[svc-name,trace-id,span-id,user-id,biz-id]|thread-name|package-name.class-name : log message

日志格式如下:

  • 時(shí)間

  • pid贫奠,pid

  • log-level,日志級(jí)別

  • svc-name望蜡,應(yīng)用名稱

  • trace-id唤崭,調(diào)用鏈標(biāo)識(shí)

  • span-id,調(diào)用層級(jí)標(biāo)識(shí)

  • user-id脖律,用戶標(biāo)識(shí)

  • biz-id谢肾,業(yè)務(wù)標(biāo)識(shí)

  • thread-name,線程名稱

  • package-name.class-name小泉,日志記錄器名稱

  • log message芦疏,日志消息體

②日志模塊擴(kuò)展

日志模塊是基于以下技術(shù)點(diǎn)做擴(kuò)展的:

  • Slf4j MDC 實(shí)現(xiàn)原理。

  • Opentracing Scope 原理微姊。

在每個(gè) tracing 鏈路中酸茴,將 Opentracing Scope 中的上下文信息放置 MDC 中,根據(jù) Spring Boot Logging 擴(kuò)展接口擴(kuò)展的取值邏輯 logging.pattern.level 的取值邏輯兢交。

相關(guān)源碼參考:

Spring Cloud Sleuth:
https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceEnvironmentPostProcessor.java

https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/log/Slf4jCurrentTraceContext.java

修改 logback 配置文件中每個(gè) appender 的 pattern 為以下默認(rèn)值即可實(shí)現(xiàn)標(biāo)準(zhǔn)化薪捍。

%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}|${PID:- }|%level|${LOG_LEVEL_PATTERN:-%5p}|%t|%-40.40logger{39}: %msg%n

logback.xml 節(jié)選:

<configuration><property name="LOG_PATH"
          value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}"/>


<springProperty scope="context" name="APP_NAME"
                source="spring.application.name" defaultValue="spring-boot-fusion"/>
<!-- 全局統(tǒng)一 pattern -->
<property name="LOG_PATTERN"
          value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}|${PID:- }|%level|${LOG_LEVEL_PATTERN:-%5p}|%t|%-40.40logger{39}: %msg%n"/>
<!-- 輸出模式 file,滾動(dòng)記錄文件,先將日志文件指定到文件,當(dāng)符合某個(gè)條件時(shí)酪穿,將日志記錄到其他文件 -->
<appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!--被寫(xiě)入的文件名凳干,可以是相對(duì)目錄,也可以是絕對(duì)目錄昆稿,如果上級(jí)目錄不存在會(huì)自動(dòng)創(chuàng)建纺座,沒(méi)有默認(rèn)值。-->
    <file>${LOG_PATH}/${APP_NAME}-info.log</file>
    <!--滾動(dòng)策略  基于時(shí)間的分包策略 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- yyyy-MM-dd 時(shí)間策略則為一天一個(gè)文件 -->
        <FileNamePattern>${LOG_PATH}/${APP_NAME}-info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>
        <!--日志文件保留小時(shí)數(shù)-->
        <MaxHistory>48</MaxHistory>
        <maxFileSize>1GB</maxFileSize>
        <totalSizeCap>20GB</totalSizeCap>
    </rollingPolicy>
    <!--  layout 負(fù)責(zé)把事件轉(zhuǎn)換成字符串溉潭,格式化的日志信息的輸出 -->
    <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>${LOG_PATTERN}</pattern>
    </layout>
    <!--級(jí)別過(guò)濾器净响,根據(jù)日志級(jí)別進(jìn)行過(guò)濾。如果日志級(jí)別等于配置級(jí)別喳瓣,過(guò)濾器會(huì)根據(jù)onMath 和 onMismatch接收或拒絕日志-->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <!--設(shè)置過(guò)濾級(jí)別-->
        <level>INFO</level>
        <!--用于配置符合過(guò)濾條件的操作-->
        <onMatch>ACCEPT</onMatch>
        <!--用于配置不符合過(guò)濾條件的操作-->
        <onMismatch>DENY</onMismatch>
    </filter>
</appender>
</configuration>

代碼使用示例:

@Override
public Result<PagingObject<SimpleResponse>> page(@RequestParam(value = "page-num", defaultValue = "1") int pageNum,
                                                 @RequestParam(value = "page-size", defaultValue = "10") int pageSize) {
    LogStandardUtils.putUserId("userId123");
    LogStandardUtils.putBizId("bizId321");
    producerService.sendMsg("xxx");
    simpleClient.page(pageNum, pageSize);
    return new Result<>(simpleService.page(pageNum, pageSize));
}

日志記錄:

2019-12-04 16:29:08.223|43546|INFO|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.n.u.concurrent.ShutdownEnabledTimer   : Shutdown hook installed for: NFLoadBalancer-PingTimer-example-server-order-service
2019-12-04 16:29:08.224|43546|INFO|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.netflix.loadbalancer.BaseLoadBalancer : Client: example-server-order-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=example-server-order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2019-12-04 16:29:08.234|43546|INFO|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.n.l.DynamicServerListLoadBalancer     : Using serverListUpdater PollingServerListUpdater
2019-12-04 16:29:08.247|43546|INFO|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.n.l.DynamicServerListLoadBalancer     : DynamicServerListLoadBalancer for client example-server-order-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=example-server-order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:ConsulServerList{serviceId='example-server-order-service', tag=null}
2019-12-04 16:29:08.329|43546|WARN|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.p.f.l.ctl.common.rule.StrategyRule    : No up servers available from load balancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=example-server-order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:ConsulServerList{serviceId='example-server-order-service', tag=null}
2019-12-04 16:29:08.334|43546|WARN|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.p.f.l.ctl.common.rule.StrategyRule    : No up servers available from load balancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=example-server-order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:ConsulServerList{serviceId='example-server-order-service', tag=null}
2019-12-04 16:29:08.342|43546|ERROR|[example-server-book-service,ac613cff04bac8b1,4a9adc10fdf0eb5,userId123,bizId321]|XNIO-1 task-4|c.p.f.w.c.advice.ExceptionHandlerAdvice : 當(dāng)前程序進(jìn)入到異常捕獲器馋贤,出錯(cuò)的 url 為:[ http://127.0.0.1:10011/simples ],出錯(cuò)的參數(shù)為:[ {"querystring":"{}","payload":""} ]
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: example-server-order-service

日志服務(wù)

SLS 阿里云日志服務(wù)

阿里云日志服務(wù)(簡(jiǎn)稱 SLS)是針對(duì)日志類(lèi)數(shù)據(jù)的一站式服務(wù)畏陕,在阿里巴巴集團(tuán)經(jīng)歷大量大數(shù)據(jù)場(chǎng)景錘煉而成配乓。您無(wú)需開(kāi)發(fā)就能快捷完成日志數(shù)據(jù)采集、消費(fèi)惠毁、投遞以及查詢分析等功能犹芹,提升運(yùn)維、運(yùn)營(yíng)效率鞠绰,建立 DT 時(shí)代海量日志處理能力腰埂。

project:項(xiàng)目、管理日志基礎(chǔ)單元蜈膨,服務(wù)日志建議一個(gè)環(huán)境建為一個(gè) Project屿笼,這樣日志記錄是整體一個(gè)閉環(huán),日志記錄隨整個(gè)環(huán)境內(nèi)的服務(wù)調(diào)用產(chǎn)生翁巍。

logstore:日志庫(kù)驴一,日志庫(kù)建議按照日志類(lèi)型分為不同的,如特定格式的 access 日志灶壶,以及 info / warn / error 日志肝断,特定格式可以配置更為方面的索引以及告警設(shè)置。

注意:請(qǐng)勿按照應(yīng)用服務(wù)區(qū)分為不同的 logstore驰凛,在微服務(wù)架構(gòu)中孝情,一次請(qǐng)求交叉了多個(gè)應(yīng)用服務(wù),日志是散落在各個(gè)應(yīng)用服務(wù)中的洒嗤,按照服務(wù)區(qū)分 logstore箫荡,需要開(kāi)發(fā)同學(xué)十分了解應(yīng)用運(yùn)行狀況和調(diào)用拓?fù)鋱D,這點(diǎn)往往是不具備的渔隶。

①實(shí)時(shí)采集與消費(fèi)

功能:

  • 通過(guò) ECS羔挡、容器洁奈、移動(dòng)端、開(kāi)源軟件绞灼、JS 等接入實(shí)時(shí)日志數(shù)據(jù)(例如 Metric利术、Event、BinLog低矮、TextLog印叁、Click 等)。

  • 提供實(shí)時(shí)消費(fèi)接口军掂,與實(shí)時(shí)計(jì)算及服務(wù)對(duì)接轮蜕。

用途:數(shù)據(jù)清洗(ETL)、流計(jì)算(Stream Compute)蝗锥、監(jiān)控與報(bào)警跃洛、 機(jī)器學(xué)習(xí)與迭代計(jì)算。

image

②查詢分析

實(shí)時(shí)索引终议、查詢分析數(shù)據(jù):

  • 查詢:關(guān)鍵詞汇竭、模糊、上下文穴张、范圍细燎。

  • 統(tǒng)計(jì):SQL聚合等豐富查詢手段。

  • 可視化:Dashboard+報(bào)表功能皂甘。

  • 對(duì)接:Grafana找颓、JDBC/SQL92。

用途:DevOps / 線上運(yùn)維叮贩,日志實(shí)時(shí)數(shù)據(jù)分析,安全診斷與分析佛析,運(yùn)營(yíng)與客服系統(tǒng)益老。

image

③消費(fèi)投遞

穩(wěn)定可靠的日志投遞。將日志中樞數(shù)據(jù)投遞至存儲(chǔ)類(lèi)服務(wù)進(jìn)行存儲(chǔ)寸莫。支持壓縮捺萌、自定義 Partition、以及行列等各種存儲(chǔ)方式膘茎。

用途:數(shù)據(jù)倉(cāng)庫(kù)+數(shù)據(jù)分析桃纯、審計(jì)、推薦系統(tǒng)與用戶畫(huà)像披坏。

image

④告警

日志服務(wù)的告警功能基于儀表盤(pán)中的查詢圖表實(shí)現(xiàn)态坦。在日志服務(wù)控制臺(tái)查詢頁(yè)面或儀表盤(pán)頁(yè)面設(shè)置告警規(guī)則,并指定告警規(guī)則的配置棒拂、檢查條件和通知方式伞梯。設(shè)置告警后玫氢,日志服務(wù)定期對(duì)儀表盤(pán)的查詢結(jié)果進(jìn)行檢查,檢查結(jié)果滿足預(yù)設(shè)條件時(shí)發(fā)送告警通知谜诫,實(shí)現(xiàn)實(shí)時(shí)的服務(wù)狀態(tài)監(jiān)控漾峡。

⑤最佳實(shí)踐

阿里云的日志服務(wù)功能相當(dāng)強(qiáng)大边琉,想用好日志服務(wù)可以參考:

https://help.aliyun.com/document_detail/29090.html?spm=a2c4g.11186623.6.1079.4edd3aabvs50OW

ELK 通用日志解決方案

ELK 是 Elasticsearch身坐、Logstash普碎、Kibana 三大開(kāi)源框架首字母大寫(xiě)簡(jiǎn)稱令蛉。市面上也被成為 Elastic Stack扩氢。其中 Elasticsearch 是一個(gè)基于 Lucene蜈项、分布式掌呜、通過(guò) Restful 方式進(jìn)行交互的近實(shí)時(shí)搜索平臺(tái)框架愈魏。像類(lèi)似百度辣之、谷歌這種大數(shù)據(jù)全文搜索引擎的場(chǎng)景都可以使用 Elasticsearch 作為底層支持框架掰伸,可見(jiàn) Elasticsearch 提供的搜索能力確實(shí)強(qiáng)大,市面上很多時(shí)候我們簡(jiǎn)稱 Elasticsearch 為 ES怀估。Logstash 是 ELK 的中央數(shù)據(jù)流引擎狮鸭,用于從不同目標(biāo)(文件/數(shù)據(jù)存儲(chǔ)/MQ)收集的不同格式數(shù)據(jù),經(jīng)過(guò)過(guò)濾后支持輸出到不同目的地(文件/MQ/Redis/Elasticsearch/Kafka 等)多搀。Kibana 可以將 Elasticsearch 的數(shù)據(jù)通過(guò)友好的頁(yè)面展示出來(lái)歧蕉,提供實(shí)時(shí)分析的功能。

實(shí)踐說(shuō)明

普通格式日志:

2019-11-26 15:01:03.332|1543|INFO|[example-server-book-service,28f019d57b8336ab,630697c7f34ca4fa,105,45982043|XNIO-1 task-42]|c.p.f.w.pay.PayServiceImpl     : order is paying with userId: 105 and orderId: 45982043

普通日志前綴是固定的康铭,可以固定分詞索引惯退,方便更快的查詢分析。

特定格式日志从藤,以 access 日志為例:

2019-11-26 15:01:03.332|1543|INFO|[example-server-book-service,28f019d57b8336ab,630697c7f34ca4fa,105,45982043|XNIO-1 task-42]|c.p.f.w.logging.AccessLoggingFilter     :
> url: http://liweichao.com:10011/actuator/health
> http-method: GET
> request-header: [Accept:"text/plain, text/*, */*", Connection:"close", User-Agent:"Consul Health Check", Host:"liweichao.com:10011", Accept-Encoding:"gzip"]
> request-time: 2019-11-26 15:01:03.309
> querystring: -
> payload: -
> extra-param: -


< response-time: 2019-11-26 15:01:03.332
< take-time: 23
< http-status: 200
< response-header: [content-type:"application/vnd.spring-boot.actuator.v2+json;charset=UTF-8", content-size:"15"]
< response-data: {"status":"UP"}

特定格式日志可按格式創(chuàng)建索引更方便聚焦查詢分析和告警催跪,如根據(jù) take-time,http-status夷野,biz-code 等值懊蒸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悯搔,隨后出現(xiàn)的幾起案子骑丸,更是在濱河造成了極大的恐慌,老刑警劉巖妒貌,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件通危,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灌曙,警方通過(guò)查閱死者的電腦和手機(jī)菊碟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)在刺,“玉大人框沟,你說(shuō)我怎么就攤上這事藏古。” “怎么了忍燥?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵拧晕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我梅垄,道長(zhǎng)厂捞,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任队丝,我火速辦了婚禮靡馁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘机久。我一直安慰自己臭墨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布膘盖。 她就那樣靜靜地躺著胧弛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侠畔。 梳的紋絲不亂的頭發(fā)上结缚,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音软棺,去河邊找鬼红竭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛喘落,可吹牛的內(nèi)容都是我干的茵宪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘦棋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稀火!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起兽狭,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鹿蜀,沒(méi)想到半個(gè)月后箕慧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茴恰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年颠焦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片往枣。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伐庭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出圾另,到底是詐尸還是另有隱情集乔,我是刑警寧澤宫莱,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布识椰,位于F島的核電站绝葡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腹鹉。R本人自食惡果不足惜藏畅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望功咒。 院中可真熱鬧愉阎,春花似錦、人聲如沸力奋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)景殷。三九已至溅呢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猿挚,已是汗流浹背咐旧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绩蜻,地道東北人铣墨。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像办绝,于是被迫代替她去往敵國(guó)和親伊约。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姚淆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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

  • 在應(yīng)用程序中添加日志記錄總的來(lái)說(shuō)基于三個(gè)目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時(shí)待吾閱讀 5,049評(píng)論 1 13
  • 在應(yīng)用程序中添加日志記錄總的來(lái)說(shuō)基于三個(gè)目的:監(jiān)視代碼中變量的變化情況屡律,周期性的記錄到文件中供其他應(yīng)用進(jìn)行統(tǒng)計(jì)分析...
    時(shí)待吾閱讀 4,985評(píng)論 0 6
  • 打印日志是一門(mén)藝術(shù)疹尾,但長(zhǎng)期被開(kāi)發(fā)同學(xué)所忽視上忍。日志就像車(chē)輛保險(xiǎn),沒(méi)人愿意為保險(xiǎn)付錢(qián)纳本,但是一旦出了問(wèn)題都又想有保險(xiǎn)可用...
    猿天地閱讀 1,288評(píng)論 0 24
  • idea 添加注釋/** 然后回車(chē) 選中代碼塊 Ctrl+Shift+/ 重點(diǎn)推薦閱讀:https://www....
    Helen_Cat閱讀 19,893評(píng)論 0 37
  • 打印日志是一門(mén)藝術(shù)繁成,但長(zhǎng)期被開(kāi)發(fā)同學(xué)所忽視吓笙。日志就像車(chē)輛保險(xiǎn),沒(méi)人愿意為保險(xiǎn)付錢(qián)巾腕,但是一旦出了問(wèn)題又都想有保險(xiǎn)可用...
    weifansym閱讀 310評(píng)論 0 1