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