log4net Action Log 設定

我之前設定網站執行的 Action Log 的一個記錄,有些東西都是拼拼湊湊出來的,並不見得是最佳版本

log4net 設定檔

1
<?xml version="1.0" encoding="utf-8" ?>
2
<log4net>
3
    <root>
4
        <level value="DEBUG" />
5
        <appender-ref ref="stdout" />
6
        <appender-ref ref="ActionLogRollingFile" />
7
    </root>
8
    <appender name="ActionLogRollingFile" type="log4net.Appender.RollingFileAppender">
9
        <file type="log4net.Util.PatternString" value="action.log" />
10
        <appendToFile value="true" />
11
        <encoding value="utf-8" />
12
        <maxSizeRollBackups value="30" />
13
        <rollingStyle value="Date" />
14
        <datePattern value="'.'yyyy-MM-dd" />
15
        <layout type="log4net.Layout.PatternLayout">
16
            <conversionPattern value="(%date{HH:mm:ss,fff}) [%t] - %u %5property{Duration} %property{StatusCode} %6property{Method} %property{Uri} %m%n " />
17
        </layout>
18
        <filter type="log4net.Filter.LoggerMatchFilter">
19
            <acceptOnMatch value="true" />
20
            <LoggerToMatch value="Sample.Web.Filters.WebApiActionFilter" />
21
        </filter>
22
23
        <filter type="log4net.Filter.DenyAllFilter" />
24
    </appender>
25
</log4net>

其中要注意的是

  • log4net.Filter.LoggerMatchFilter: 用來設定特定的 class 記錄才使用這個 Appender
    • acceptOnMatch: 這個設定有點像是 blacklist/whitelist,true 表示有 match 才是,相當於 whitelist
    • LoggerToMatch: 設定要篩選的類別名稱
  • log4net.Filter.DenyAllFilter: 篩選掉其他的 Log,不會在這個 Appender 裡面記錄

C# Filter 程式參考

1
/// <summary>
2
/// 執行 Web Api 的呼叫記錄
3
/// </summary>
4
/// <remarks>
5
/// 紀錄資料:
6
///
7
///     呼叫時間
8
///     USER
9
///     URL
10
///     METHOD
11
///     BODY
12
///     StatusCode
13
///     Duration
14
///
15
/// Logger 的紀錄格式,參考 https://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
16
/// </remarks>
17
public class WebApiActionFilter : ActionFilterAttribute
18
{
19
    private ILog Logger { get; set; }
20
21
    public WebApiActionFilter()
22
    {
23
        Logger = LogManager.GetLog(GetType());
24
    }
25
26
    public WebApiActionFilter(ILog logger)
27
    {
28
        Logger = logger;
29
    }
30
31
    private ThreadLocal<Stopwatch> counter = new ThreadLocal<Stopwatch>(() => new Stopwatch());
32
    public static ThreadLocal<Task<string>> RequestBody = new ThreadLocal<Task<string>>();
33
34
    public override void OnActionExecuting(HttpActionContext actionContext)
35
    {
36
        RequestBody.Value = actionContext.Request.Content.ReadAsStringAsync();
37
        counter.Value.Start();
38
    }
39
40
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
41
    {
42
        counter.Value.Stop();
43
        LogActivity(actionExecutedContext.ActionContext, actionExecutedContext.Response);
44
    }
45
46
    private void LogActivity(HttpActionContext actionContext, HttpResponseMessage response)
47
    {
48
        try
49
        {
50
            var loggerProp = ThreadContext.Properties;
51
            loggerProp["Uri"] = actionContext.Request.RequestUri.PathAndQuery;
52
            loggerProp["Method"] = actionContext.Request.Method.Method;
53
            loggerProp["Duration"] = counter.Value.ElapsedMilliseconds;
54
            loggerProp["StatusCode"] = (int) response.StatusCode;
55
56
            Logger.Info(RequestBody.Value.Result);
57
        }
58
        catch (Exception e)
59
        {
60
            Console.WriteLine(e);
61
        }
62
    }
63
}
64
65
/// <summary>
66
/// 用來擷取傳入的 Request Content Body, 因為沒辦法在 Filter 中取得 Body
67
/// </summary>
68
/// <remark>
69
/// 如果需要抓傳遞資料才需要
70
/// </remark>
71
public class LogBodyDelegateHandler : DelegatingHandler
72
{
73
74
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
75
    {
76
        if (request.Content != null)
77
        {
78
            var requestText = request.Content.ReadAsStringAsync();
79
80
            WebApiActionFilter.RequestBody.Value = requestText;
81
        }
82
        // Execute the request, this does not block
83
        var response = base.SendAsync(request, cancellationToken);
84
85
        return response.Result;
86
    }
87
}

另外從網路上有查到一篇不錯的文章,http://it.tomtang.idv.tw/2013/12/log4net-best-practice.html
這篇是在說明 log4net 的一些設定建議

以下是他一個常用設定值的參考

1
<?xml version="1.0" encoding="UTF-8"?>
2
<log4net>
3
  <appender name="ErrorFile" type="log4net.Appender.RollingFileAppender">
4
    <file type="log4net.Util.PatternString" value="C:\applications\logs\%property{appname}\Error-%property{appname}.log" />
5
    <encoding value="utf-8" />
6
    <appendToFile value="true" />
7
    <maximumFileSize value="10000KB" />
8
    <maxSizeRollBackups value="50" />
9
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
10
    <layout type="log4net.Layout.PatternLayout">
11
      <conversionPattern value="%date&#x9;[%thread]&#x9;%level&#x9;%logger&#x9;%property{appname}&#x9;- %message%newline" />
12
    </layout>
13
    <filter type="log4net.Filter.LevelRangeFilter">
14
      <levelMin value="ERROR" />
15
      <levelMax value="FATAL" />
16
    </filter>
17
    <filter type="log4net.Filter.DenyAllFilter" />
18
  </appender>
19
  <appender name="WarnFile" type="log4net.Appender.RollingFileAppender">
20
    <file type="log4net.Util.PatternString" value="C:\applications\logs\%property{appname}\Warn-%property{appname}.log" />
21
    <encoding value="utf-8" />
22
    <appendToFile value="true" />
23
    <maximumFileSize value="10000KB" />
24
    <maxSizeRollBackups value="50" />
25
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
26
    <layout type="log4net.Layout.PatternLayout">
27
      <conversionPattern value="%date&#x9;[%thread]&#x9;%level&#x9;%logger&#x9;%property{appname}&#x9;- %message%newline" />
28
    </layout>
29
    <filter type="log4net.Filter.LevelMatchFilter">
30
      <param name="LevelToMatch" value="WARN" />
31
    </filter>
32
    <filter type="log4net.Filter.DenyAllFilter" />
33
  </appender>
34
  <appender name="InfoFile" type="log4net.Appender.RollingFileAppender">
35
    <file type="log4net.Util.PatternString" value="C:\applications\logs\%property{appname}\Info-%property{appname}.log" />
36
    <encoding value="utf-8" />
37
    <appendToFile value="true" />
38
    <maximumFileSize value="10000KB" />
39
    <maxSizeRollBackups value="50" />
40
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
41
    <layout type="log4net.Layout.PatternLayout">
42
      <conversionPattern value="%date&#x9;[%thread]&#x9;%level&#x9;%logger&#x9;%property{appname}&#x9;- %message%newline" />
43
    </layout>
44
    <filter type="log4net.Filter.LevelMatchFilter">
45
      <LevelToMatch value="INFO" />
46
    </filter>
47
    <filter type="log4net.Filter.DenyAllFilter" />
48
  </appender>
49
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
50
    <file type="log4net.Util.PatternString" value="C:\applications\logs\%property{appname}\ALL-%property{appname}.log" />
51
    <encoding value="utf-8" />
52
    <appendToFile value="true" />
53
    <maximumFileSize value="10000KB" />
54
    <maxSizeRollBackups value="50" />
55
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
56
    <layout type="log4net.Layout.PatternLayout">
57
      <conversionPattern value="%date&#x9;[%thread]&#x9;%level&#x9;%logger&#x9;%property{appname}&#x9;- %message%newline" />
58
    </layout>
59
  </appender>
60
  <appender name="debugger" type="log4net.Appender.OutputDebugStringAppender">
61
    <layout type="log4net.Layout.PatternLayout">
62
      <conversionPattern value="%date&#x9;[%thread]&#x9;%level&#x9;%logger&#x9;%property{appname}&#x9;- %message%newline" />
63
    </layout>
64
  </appender>
65
  <root additivity="true">
66
    <level value="ALL" />
67
    <appender-ref ref="debugger" />
68
    <appender-ref ref="RollingFile" />
69
    <appender-ref ref="InfoFile" />
70
    <appender-ref ref="WarnFile" />
71
    <appender-ref ref="ErrorFile" />
72
  </root>
73
  <logger name=「doway.sample.helloworld」>
74
    <level value="WARN" />
75
  </logger>
76
</log4net>

參考