Hangfire使用ApplicationInsigts监控
起因
我司目前使用清真的ApplicationInsights來做程序級監(jiān)控。(ApplicationInsights相關(guān)文檔:?https://azure.microsoft.com/zh-cn/services/application-insights/?)
其實(shí)一切都蠻好的,但是我們基于Hangfire的Job系統(tǒng)卻無法被Ai所監(jiān)控到,因?yàn)锳i它監(jiān)控的原理是基于HttpModule對請求進(jìn)行監(jiān)控,而Hangfire則是通過輪詢Storage(如Sql或者隊(duì)列)來實(shí)現(xiàn)對Job的處理。
也就是說Hangfire理論上是沒有任何對Hangfire站點(diǎn)本身的請求,它類似于自己一個(gè)while(true)死循環(huán)不斷地輪詢Storage拿到Job任務(wù)就執(zhí)行。
關(guān)于Hangfire的系列可以參考官方的說明?http://docs.hangfire.io/en/latest/
雖說Hangfire自己有個(gè)Dashboard可以對Hangfire執(zhí)行的任務(wù)進(jìn)行監(jiān)控,如下
但是一眾的其他站點(diǎn)我全部在Azure的Portal里一目了然,就你一個(gè)Hangfire的要我跑到你自己家的Dashboard來看終歸不爽,而且也容易忘,導(dǎo)致Hangfire站點(diǎn)常年處于被遺忘的角落。
最近發(fā)生了一個(gè)Hangfire站點(diǎn)因?yàn)槟承┩獠吭驔]起來(宕掉)的事件之后更加速了要將Hangfire的監(jiān)控統(tǒng)一到Ai里。
?
搜索
首先去github上找下有沒相關(guān)解決方案,老實(shí)說覺得基于ApplicationInsights的第三方擴(kuò)展還是蠻多的,在github搜ApplicationInsights相關(guān)的還是能搜索出好幾頁(https://github.com/topics/application-insights),但并沒有找到我需要的。
然后google一下找到有人在hangfire論壇里問跟我類似的問題,然而也沒有解決方案(https://discuss.hangfire.io/t/integrating-application-insights-appinsights-into-hangfire/3009)。
既然找不到,那干脆自己擼起袖子干。
?
開擼
首先我們回顧下ApplicationInsights默認(rèn)自己監(jiān)控的原理:
前文說了它有個(gè)HttpModule會在請求進(jìn)來的創(chuàng)建一個(gè)RequestTelemetry,
并且會在線程上下文內(nèi)創(chuàng)建個(gè)OperationId,然后在該Request的作用于內(nèi)所有其他數(shù)據(jù)(如異常/Http請求/Sql請求)都會跟這個(gè)Id關(guān)聯(lián),
這個(gè)Id甚至?xí)谀惆l(fā)送Http請求的時(shí)候附加在你的Http Header里,然后接收到該Http請求的站點(diǎn)假如也用了Ai的話會根據(jù)這個(gè)Header里的Id再進(jìn)行二次關(guān)聯(lián)(調(diào)用鏈路關(guān)聯(lián))。
?
先解決ApplicationInsights需要的相關(guān)基礎(chǔ)知識
我們要自己在Hangfire里弄AI監(jiān)控的話,其實(shí)重點(diǎn)就是怎么能讓Request里的Id能傳遞到Hangfire里,然后在Hangfire一個(gè)操作的作用域里保持該Id一致(串聯(lián)所有操作)。
那問題重點(diǎn)就清楚了,就是如何解決這個(gè)Id的問題。
?
那Ai自己是如何產(chǎn)生或者獲取這個(gè)Id的呢,在Ai的2.4版本后引入了對System.Diagnostics.DiagnosticSource這個(gè)包的依賴。
所有的Id關(guān)聯(lián)它都基于由此包提供的Activity這個(gè)類來事現(xiàn),詳情可以參考?http://apmtips.com/blog/2018/01/23/diagnosticssource-design-principles/?
如果需要在自己系統(tǒng)里設(shè)置一個(gè)Id關(guān)聯(lián)的系統(tǒng)的話也強(qiáng)烈推薦使用Activity這個(gè)類來進(jìn)行處理。
別人實(shí)現(xiàn)的比自己弄的科學(xué)多了,之前我也自己用AsyncLocal來做過,但是后續(xù)也都替換成了Activity,
通過Activity.Current可以獲取到當(dāng)前的Activity實(shí)例,通過new Activity然后調(diào)用其Start方法也能快速啟動一個(gè)Activity,
到此Ai相關(guān)所需要的知識就都準(zhǔn)備妥當(dāng)了。
?
然后解決Hangfire需要的相關(guān)基礎(chǔ)知識
從Hangfire的角度來說,它只要提供2個(gè)功能支持就可以了。
在任務(wù)入隊(duì)的時(shí)候,在數(shù)據(jù)里面要塞入在當(dāng)前Request操作的Id,因?yàn)槲乙獙angfire的操作能夠跟Request里相關(guān)聯(lián)起來。
在任務(wù)執(zhí)行的時(shí)候,拿到任務(wù)數(shù)據(jù)的時(shí)候,要能取出這個(gè)Id,然后將這個(gè)Id通過Activity進(jìn)行Start,然后再任務(wù)執(zhí)行完之后要Stop掉這個(gè)Activity并釋放掉。
(畫的圖”有點(diǎn)”丑,但大概就這個(gè)意思)
?
為了解決這個(gè)問題查找了下Hangfire全局過濾器相關(guān)的資料找到它有IServerFilter和IClientFilter這2個(gè)東西:
IServerFilter:服務(wù)端處理的過濾器,就是Hangfire Server在執(zhí)行一個(gè)Job的時(shí)候要進(jìn)行處理的過濾器,可在此位置給Hangfire的Job設(shè)置Ai的Id到上下文。
IClientFilter:客戶端處理的過濾器,就是Hangfire Client在一個(gè)Job入隊(duì)的時(shí)候要進(jìn)行處理的過濾器,可在此位置將Request里的Id賦值給Job Data。
?
那在Client的時(shí)候如何解決每次都能自動塞個(gè)Id進(jìn)去呢?
我的解決思路是定義個(gè)JobDtoBase,所有Hangfire任務(wù)的數(shù)據(jù)都要繼承自這個(gè)類,里面就一個(gè)Id,然后通過IClientFilter在每次入隊(duì)的時(shí)候都將當(dāng)前Activity.Current.Id扔進(jìn)去
(需要考慮Acitivity.Current為null的情況)
?
然后如何在Server端自動將這個(gè)Id來啟動一個(gè)Activity并完成監(jiān)控呢?
我是想著通過IServerFilter里通過PerformingContext里獲取Job的參數(shù)然后用is來判斷如果是JobDtoBase就取它的Id出來然后啟動Activity并創(chuàng)建RequestTelemetry。
重點(diǎn)是在Server這邊執(zhí)行結(jié)束之后需要將RequestTelemetry和Activity釋放掉,所以通過ThreadStatic的靜態(tài)變量來對其保持引用。
?
效果
效果如何這個(gè)問題暫時(shí)我只能呵呵噠,因?yàn)橐彩莿傉垓v出來還沒投入線上運(yùn)行。
不過從測試環(huán)境來看,確實(shí)能抓到我hangfire的請求并在Ai里作為Request進(jìn)行展示:
而且還能抓到依賴項(xiàng)跟”Request”的關(guān)聯(lián):
所以至少測試的情況來說應(yīng)該是達(dá)到目的了,等之后投入線上后在看下最終具體效果。
原文地址?https://www.cnblogs.com/leolaw/p/8734822.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com 
總結(jié)
以上是生活随笔為你收集整理的Hangfire使用ApplicationInsigts监控的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【招聘(北京)】.NETCORE开发工程
- 下一篇: NET主流ORM框架分析
