[.Net]快速設定寫log檔方法(log4net)

  • 16646
  • 0
  • 2022-11-25

[.Net]快速設定寫log檔方法(log4net)

以.net Winform為例(console, web也差不多):
1.加入log4net.dll參考(下載log4net, 選擇log4net-2.0.8-bin-newkey.zip下載, 解壓縮後資料夾選擇bin\net, 請勿選到bin\net-cp, 因為cp表示client profile, 是簡易版)
ps. 2022/11/17補充:
現在直接於visual studio裡面的nuget裡面直接安裝log4net會是最快、最簡單的方式
2..exe的路徑加入log4net.config文字檔案,文字內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<log4net>
  <root>
    <level value="DEBUG"/>
    <appender-ref ref="LogFileAppender"/>    
  </root>
  <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
    <file type="log4net.Util.PatternString" value="D:\temp\.log"/>
    <!--<file type="log4net.Util.PatternString" value="LogFiles\.log"/>-->
    <preserveLogFileNameExtension value="true"/>
    <staticLogFileName value="false"/>
    <param name="AppendToFile" value="true"/>
    <rollingStyle value="Composite"/>
    <datePattern value="yyyyMMdd"/>
    <encoding value="UTF-8"/>
    <!--只要設定MaxDateRollBackups屬性的話就會出現錯誤,目前已知的log4net bug-->
    <!--<MaxDateRollBackups value="14" />-->
    <maxSizeRollBackups value="-1" />
    <maximumFileSize value="100MB"/>
    <countDirection value="1"/>
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%date [%thread] %-5level %logger (%line) - %message%newline"/>
    </layout>
  </appender>
</log4net>

ps.2019/09/25補充
也可直接下載作者準備好的log4net的dll以及log4net.config
官網的dll是一大包,有80多MB得下載
ps. 2022/11/17補充:
現在直接於visual studio裡面的nuget裡面直接安裝log4net會是最快、最簡單的方式
ps. 2022/11/17
由於官方的MaxDateRollBackups設定已經被認為bug且不會自動刪除舊的.log檔案,
這邊作者自行補充刪除舊的.log檔案的方式,直接複製下列程式碼即可,可 N 天內的.log檔案會保留,更舊的.log檔就會刪除    

//手動刪除 N天內的 舊的.log檔案   
//最多刪除365天內的log         
List<string> filePatterns = new List<string>();
//Log4netDeleteOldFileDays變數請自行設定為要刪除幾天內的.log檔資料
//一般是設定在設定檔,例如:app.config(Console, Winform), web.config(asp.net), appSettings.json(asp.net core)
for (int i = 365; i >= Convert.ToInt16(Log4netDeleteOldFileDays); i--)
{
    string pattern = @"*.log";
    pattern = DateTime.Now.AddDays(-i).ToString("yyyyMMdd") + pattern;
    filePatterns.Add(pattern);
}

foreach (var filePattern in filePatterns)
{
    string[] oldLogFiles = Directory.GetFiles(Log4netPath, filePattern);
    foreach (var oldFile in oldLogFiles)
    {
        try
        {
            File.Delete(oldFile);
            //log.Debug("檔案:" + oldFile + " 已刪除。");
            WriteLog("檔案:" + oldFile + " 已刪除。");
        }
        catch (Exception ex)
        {
            //log.Debug("檔案:" + oldFile + " 刪除過程發生錯誤:" + ex.ToString());
            WriteLog("檔案:" + oldFile + " 刪除過程發生錯誤:" + ex.ToString());
        }

    }
}

//此範例是寫在Console程式碼裡,其他類型的程式碼請自行改寫
static void WriteLog(string msg)
{
    //TestFlag通常是設定在設定檔,測試階段多出cmd的輸出,方便debug
    if (TestFlag.ToLower() == "true")
    {
        Console.WriteLine(msg);
    }
    log.Debug(msg);
}



3.Form_load加入程式碼:這裡是winform, console例子

XmlConfigurator.Configure(new System.IO.FileInfo("./log4net.config"));

以上,就設定完成
ps.2022 Nov 23th補充:
如果利用排程管理員執行.exe且寫入log4net的.log失敗的話,請把上面的寫法改為:

XmlConfigurator.Configure(new System.IO.FileInfo(System.AppContext.BaseDirectory + "\\log4net.config"));



然後在程式碼裡先宣告logger為全域變數:

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

之後只要在程式碼任意處加入debug等級以上的寫log,就會寫入檔案囉!
等級由低到高依序為:Debug, Info, Warn, Error, and Fatal.

log.Debug("程式已開始寫log!");

執行結果:文字檔寫入log
檔案名稱:當天日期.log(在D:\temp路徑, 若是修改此路徑, 執行之前請重建專案喔,相對路徑設定的話,例如:LogFiles\.log)
log內容:日期時間 執行序代號 log等級 寫log的function(行號) log的訊息
 


大概是這樣

ps. 2022 Nov 25th 補充
1. log4net不會自行建立路徑,因此需自行在程式碼中自動建立寫入.log檔的路徑,範例如下:

if (Directory.Exists(Log4netPath) == false)
{
	Directory.CreateDirectory(Log4netPath);

}

              
2. log4net的log4net.config檔不會自動複製到執行檔的路徑,可利用以下範例程式的CopyEmailTemplateAndLog4NetConfig()自動複製,只要偵測到是在localhost的debug模式之下,就會開始自動複製。(此範例是Console程式)

//在debug模式之下,自動複製最新的email template html以及log4net.config到debug資料夾
static void CopyEmailTemplateAndLog4NetConfig()
{
	if(Directory.GetCurrentDirectory().ToLower().IndexOf("debug") > -1)
	{
		string parentParentDir = System.IO.Directory.GetParent(
			Directory.GetCurrentDirectory()).Parent.FullName;
		//複製其他商業邏輯相關的檔案,這邊是TempFiles資料夾裡面會有一些發信的範本的.html檔
		Copy(parentParentDir + "\\TempFiles", Directory.GetCurrentDirectory() + "\\TempFiles");
		//複製log4net.config檔案
		System.IO.File.Copy(parentParentDir + "\\log4net.config",
			Directory.GetCurrentDirectory() + "\\log4net.config",true);
		WriteLog("偵測到在Debug模式,成功複製EmailTemplate以及log4net.config");
	}
	else
	{
		WriteLog("偵測到不是在Debug模式,因此不複製EmailTemplate以及log4net.config");
	}
}

static void Copy(string sourceDirectory, string targetDirectory)
{
	DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
	DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);

	CopyAll(diSource, diTarget);
}

static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
	Directory.CreateDirectory(target.FullName);

	// Copy each file into the new directory.
	foreach (FileInfo fi in source.GetFiles())
	{
		//Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
		fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
	}

	// Copy each subdirectory using recursion.
	foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
	{
		DirectoryInfo nextTargetSubDir =
			target.CreateSubdirectory(diSourceSubDir.Name);
		CopyAll(diSourceSubDir, nextTargetSubDir);
	}
}

static void WriteLog(string msg, string logType = "Info")
{
	if (TestFlag.ToLower() == "true")
	{
		Console.WriteLine(msg);
	}
	log.Debug(msg);

	WriteDbLog(logType, msg);

}



補充一下asp.net mvc的作法:
global.asax裡面加入:

string log4netPath = Server.MapPath("~/log4net.config");
log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(log4netPath));


log4net.config檔案放在bin資料夾裡面,並且順便加入專案裡面,以防以後bin資料夾裡面的檔案被刪除

然後要寫log的網頁在最上面加入這個宣告:

static ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


然後下面這樣就寫log檔案囉:

logger.Debug("進入了LDAP區塊:");


log檔案就會寫入一行:
2019-04-26 13:03:48,960 [15] DEBUG MyMVCWeb.Controllers.AccountController (69) - 進入了登入區塊:
 

參考資訊:
簡單記錄 log4net 的用法
https://dotblogs.com.tw/yuanlin/2012/05/30/72479