使用 log4net 有好些年了,但是這個開源專案目前處於休眠的狀態,慢慢凋零了,所以決定將手上的專案轉使用 NLog,過去開發的幾個在 log4net 上的 Appender 現在必須要轉成 NLog 的 Target,我就以 Slack 的 Incoming WebHooks 為例,將它做成一個 NLog 的 Target。
繼承 TargetWithLayout 或 AsyncTaskTarget
我將我要做的 Target 命名為 SlackTarget
,在這邊我們可以選擇繼承 TargetWithLayout
或是非同步版本的 AsyncTaskTarget
,那我選擇繼承的是 AsyncTaskTarget,並且透過 TargetAttribute
設定 Target 的名稱。
[Target("Slack")]
public class SlackTarget : AsyncTaskTarget
{
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken)
{
}
}
參數設定
建立 Incoming WebHooks 的過程我就不說明了,請大家自行上網搜尋,建好 Incoming WebHooks 會得到一串 WebhookUrl,我們不可能在 Target 裡面將這個 WebhookUrl 寫死,一定是透過 NLog 的設定檔傳遞進來,Target 要接收從設定檔傳進來的參數,只需要建立一個相同名稱的公開屬性
即可,不分大小寫,如果參數是必填的,則加上 RequiredParameterAttribute
。
[Target("Slack")]
public class SlackTarget : AsyncTaskTarget
{
[RequiredParameter]
public string WebhookUrl { get; set; }
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken)
{
}
}
補完傳送訊息的程式碼
Slack 的訊息是可以很豐富的,還能有互動,這個就留待大家針對自己的需求去實作了,我這邊的範例很陽春,單純只是傳送文字訊息到 Slack 上,頂多加上紅綠燈的顏色用來區分 LogLevel。
[Target("Slack")]
public class SlackTarget : AsyncTaskTarget
{
[RequiredParameter]
public string WebhookUrl { get; set; }
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken cancellationToken)
{
var hostName = Environment.MachineName;
var appDomain = AppDomain.CurrentDomain;
var renderedLog = this.RenderLogEvent(this.Layout, logEvent);
var title = $"[{logEvent.Level.ToString().ToUpper()}] on {hostName}";
var payload = JsonSerializer.Serialize(
new
{
Username = appDomain.FriendlyName,
Fallback = title,
Color = GetColor(logEvent.Level),
Fields = new[] { new { Title = title, Value = renderedLog, Short = false } }
},
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
var webhook = new Uri(this.WebhookUrl);
var request = new HttpRequestMessage(HttpMethod.Post, webhook)
{
Content = new StringContent(
string.Concat("payload=", payload),
Encoding.UTF8,
"application/x-www-form-urlencoded")
};
var httpClient = HttpClientFactory.Instance.CreateClient(new Uri($"{webhook.Scheme}{Uri.SchemeDelimiter}{webhook.Host}"));
await httpClient.SendAsync(request, cancellationToken);
}
}
調整設定檔
最後在設定檔的 <extensions>
加入 Target 所屬性的組件名稱,以及加入一個 xsi:type
為 Target Name 的 <target>
。
顯示在 Slack 上就長這樣:
< Source Code >