緣起:
我現在自己獨立弄一個專案,上個禮拜有成功把所需的服務都用
docker container
跑起來,彼此間的溝通與協作也正常,所以接下來要開始正式開發後台的程式了,但在這之前,我想先弄好專案
app 的記錄 log 功能。之前還在哈瑪星工作時,有看到我們產品內有用到
NLog 套件來記錄各種程式執行時的 log,用檔案系統紀錄。當程式發生問題時,有 log
檔能看,會比較有頭緒,不然之後正式上線,程式怎麼爆的都不知道,會很可怕。
這篇文章主要記錄 Nlog 的設定與使用,還有在 Container
上執行時有碰到些雷。
NLog 的安裝與設定:
文章主要是參考這篇,我開個 Asp Net Web 專案來測試,專案有啟用 Docker 支援。
![]() |
先安裝這兩個 Nlog 套件 |
using NLog;
using NLog.Extensions.Logging;
namespace NLogTest
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Configuration
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", true, true)
.AddEnvironmentVariables();
builder.Services.AddRazorPages();
builder.Services.AddLogging(logging =>
{
logging.ClearProviders();
logging.AddNLog();
});
LogManager.GlobalThreshold = builder.Configuration.GetValue<NLog.LogLevel>("Logging:LogLevel:Default");
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
}
}
}
13~17 行 : 加入
appsettings.json 檔,還有環境變數 (有點忘了是在哪抄來的)。
20~24 行 : service 加入
Nlog,記得 using NLog.Extensions.Logging。
26 行 :
這邊看到的,讀取 appsetting 來設定 Nlog 的全域 LogLevel。
接著在專案目錄新增一個 Nlog.config 檔,之後去研究 log
檔的檔案路徑跟參數那些怎麼做調整,主要是參考這篇文章,我想要的 log
檔階層格式為,{專案當前執行目錄}/logs/{日期}/{LogLevel}/{完整 Class
名稱}.log,至於 log 紀錄的格式,我只有改 \n
的部份,我自己在測試的時候發現,如果想換行的話,要寫 ${newline} 才對,整個
Nlog.config 檔寫下來會長這樣。然後 Fatal 的 log ,單獨放在一個 fatal.log 檔中。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--設定 log 輸出目標-->
<targets>
<target name="FatalFile"
xsi:type="File"
fileName="${basedir}/logs/${processinfo:StartTime:format=yyyy-MM-dd:cached=true}/fatal.log"
layout="[${longdate}] ${processname:fullName=false} ${callsite:includeNamespace=true}: ${callsite-linenumber}${newline}${message}${newline}" />
<target name="TraceFile"
xsi:type="File"
fileName="${basedir}/logs/${processinfo:StartTime:format=yyyy-MM-dd:cached=true}/${level:uppercase=true}/${callsite:includeNamespace=true}.log"
layout="[${longdate}] ${processname:fullName=false} ${callsite:includeNamespace=true}: ${callsite-linenumber}${newline}${message}${newline}" />
<target name="Console" xsi:type="Console" />
</targets>
<!--設定不同 log level 的 routing 路徑-->
<rules>
<logger name="*" minlevel ="Trace" maxlevel="Error" writeTo="TraceFile"/>
<logger name="*" level="Fatal" writeTo="FatalFile" />
<logger name="*" minlevel="Info" maxlevel="Error" writeTo="Console"/>
</rules>
</nlog>
15 跟 22 行,原本沒加這兩行,跑程式時發現
Console 沒輸出,後來翻完文章後,就把 Console 部份加上去了。
接著執行程式,沒問題的話,你可以在
/bin/Debug/{dotnet版本}下看到 logs 的資料夾
有寫一個 docker-compose 來設定
services:
web:
build:
context: .
dockerfile: ./NlogTest/Dockerfile
image: nlog-test
ports:
- "8080:8080"
container_name: nlog-test
volumes:
- nlog-test:/app/logs
volumes:
nlog-test:
driver: local
container 跑起來後,我到 Desktop 的 volumes,查看 nlog-test
的內容,空空的
NLog.Common.InternalLogger.LogToConsole = true;
NLog.Common.InternalLogger.LogFile = "internal-nlog.log";
NLog.Common.InternalLogger.LogLevel = NLog.LogLevel.Trace;
加完後,我再跑 container,發現確實目錄下會多個
internal-nlog.log,打開檔案,發現
重點是第 7 跟第 8,它說找不到 "NLog.config"、"nlog.config",我這才意識到,把檔名取成 "Nlog.config",大寫 N,小寫 l,它檔名看起來是要跟預設清單完全匹配才能找到 config 檔,所以我就修改 config 檔的名字,全部都小寫,然後再 build 跟 run container,跑起來後,我還是沒看到 logs 資料夾裡有東西,所以再去看那個 nlog.config,這次發現它內容多了不少,注意到有 Warn
哦 ~~,原來在 docker-compose 中 mount volume 時,如果資料夾不存在,雖然它會自動幫你建立,但預設是用 root 權限建立的,所以我就想到要去改 dotnet 預設建立的 Dockerfile,在最後的 ENTRYPOINT 前加一行
RUN mkdir /app/logs
再次 build 後 run container,可以看到,那個資料夾的所屬使用者跟群組都是 app
沒有留言:
張貼留言