前情提要
我將 ASP.Net Core 的 API 服務加上 Log。
Logger 使用 NLog ,載體我使用 Elasticsearch ,
使用者操作介面使用 Kibana。
然後面對開發者,我希望用 AOP 方式,
讓 Logger 與主邏輯分離。
- 這裡會用到簡單基本的 docker 技術
- 透過 docker-compose 建立 Kibana 與 Elasticsearch
- 假設你已經會使用 Dotnet Core DI 注入 Logger
- 用最原生的方法實作 AOP
- 對你可能沒有幫助
Run ElasticSearch & Kibana with docker
在本機建立 ElasticSearch & Kibana
首先建立 docker-compose.yaml 檔如下,
簡單說明一下內容:
- 起一個 elasticsearch,port : 9200
- 起一個 kibana ,port : 5601,設定環境變數
ELASTICSEARCH_URL
為http://localhost:9200
- 網路名命為 elastic 使用 bridge 讓兩個 container 連起來
elasticsearch-data:
實務上我想需要指定一個 storage(硬碟或 File System 之類的)
1 | version: "3.1" |
執行
1 | docker-compose up -d |
完成後在本機瀏覽器瀏覽以下網址。
確定功能正常。
- Elasticsearch URL http://localhost:9200/
- Kibana URL http://localhost:5601/
雷包
第一次啟動 Kibana 要 5 分鐘左右,但是我不確定是 docker 或是 Kibana 的問題
Dotnet Core NLog with ElasticSearch
首先必需安裝相關套件
1 | Install-Package NLog.Web.AspNetCore |
設定 appsettings.json
(請見 20200518 的補充)
1 | { |
設定 nlog.config,注意以下路徑
nlog > extenstions > assembly
nlog > targets > target
nlog > rules > logger
這裡的重點是 ElasticSearchServerAddress
這組字串需設定成你的 ElasticSearchServerAddress
(請見 20200518 的補充)
1 |
|
我的 Logger 代碼可能會類似這樣:
我想調整 Logger 代碼,不要與商務邏輯混在一起。
- 一般的 Logger 我會用 AOP 的方式作成 Audit Log 記錄
- catch Exception 的 Logger 我會統一處理
1 | private readonly ILogger logger; |
20200518 補充
nlog.config
與 appsettings.json
內容調整。
使用Elasticsearch Cloud(以下簡稱 ESC)當作服務的儲存體。
踩到了一個雷包,當我把 ElasticSearchServerAddress
修改成 ESC 服務的 EndPoint
我發現 ESC 並未接收到 Log ,更奇怪的事情是,在我本機端 docker 所建置服務仍然收到了 Log。
查詢了一下最新的Nlog ElasticSearch Wiki後,
應該改用 uri
屬性設定 EndPoint ,而沒有設定的情況下預設為 localhost:9200
,
1 | uri - Uri of a Elasticsearch node. Multiple can be passed comma separated. |
而要使用 ESC 的 EndPoint,除了設定 uri
外,還需要啟用授權。requireAuth
設定為 true
(預設為false
),另外還要設定 username
與 password
。appsettings.json
的 ConnectionsString 就可以刪除了。nlog.config
修改大致如下
1 | <!--略--> |
Dotnet Core AOP
用 AOP 的方式作成 Audit Log 記錄,
想法是方法的 in / out 我將想知道資訊記錄下來。
比如輸入的參數或是回傳值。
題外話,因為 AOP 的特性,如果方法處理到一半想要記錄是作不到的,
這是不是意味著必須重構將方法一分為二 ?
參考這篇,我會使用最基本的 Filter 實作 AOP,
依據 Filter
的特性我在這裡會實作 IActionFilter
1 | public class AuditLogAttribute : Attribute, IActionFilter |
我的最終目標是透過掛載 Attribute 的方式來讓 Logger 與解耦,
參考下方的程式碼。
1 | private readonly ILogger logger; |
這裡就有一件討厭的事,因為我的 Logger 都是透過建構子注入產生,
而自已本身也比較傾向不要使用公開 Property Injection 的方式*。
但是使用建構子在這裡會產生另一個問題,
我將無法使用掛載 Attribute 的方式處理 Logger
解決的方式是透過另一個 Attribute ServiceFilterAttribute
作間接掛載
1 | private readonly ILogger logger; |
這樣作還是有一些缺點,最明顯就是掛載的 Attribute 變長,
然後視覺上又是末端文字才能表達意涵,
另一點是原本約定成俗可以省略的*Attribute
後綴不能省略了。
我想使用 Castle 與 AutoFac 重作一次。
應該可以變得更加簡潔。
參考
- https://www.humankode.com/asp-net-core/logging-with-elasticsearch-kibana-asp-net-core-and-docker
- https://kevintsengtw.blogspot.com/2018/07/aspnet-core-nlog-log-elasticsearch.html
- https://kevintsengtw.blogspot.com/2018/07/aspnet-core-nlog-log-elasticsearch_9.html
- https://www.cnblogs.com/jlion/p/12394949.html
- https://paper.dropbox.com/doc/202001-DIAOP--Az2Kl_lUwdJulCygth_VSyrcAg-41nJ40hCmLj7o7haWhual
- https://blog.johnwu.cc/article/ironman-day14-asp-net-core-filters.html
- https://edi.wang/post/2019/1/21/aspnet-core-dependency-injection-in-actionfilterattribute
- 請比較 Property Injection 與其它的注入方式的優缺點。
(fin)