Serilog-使用AppSettings Config如何配置子记录器并仅包括某些命名空间?

时间:2018-08-08 19:27:09

标签: serilog


我正在尝试在CMS中设置Serilog,该CMS具有我们定义为CMS的一些默认日志记录配置设置,但是允许使用CMS的开发人员通过使用Serilog AppSettings Nuget软件包-https://github.com/serilog/serilog-settings-appsettings来扩展和配置自己的日志记录要求

我有一些这样的工作,并且能够在外部配置文件中配置我有并且需要帮助的其他接收器,请问如何让开发人员配置文件接收器以生成仅包含其名称空间的txt logile?

有了C#类,我知道我可以创建一个子记录器,然后像这样使用过滤器 .Filter.ByIncludingOnly(Matching.FromSource("DevelopersNamespace")),但使用Serilog Analyzer VS扩展-https://github.com/Suchiman/SerilogAnalyzer无法生成XML AppSettings配置示例。

这是我的C#记录器配置的副本

Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));

//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log-{Date}.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
    .Enrich.WithProcessId()
    .Enrich.WithProcessName()
    .Enrich.WithThreadId()
    .Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
    .Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
    .Enrich.With<Log4NetLevelMapperEnricher>()

    //Main .txt logfile - in similar format to older Log4Net output
    //Ends with ..txt as Date is inserted before file extension substring
    .WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
        rollingInterval: RollingInterval.Day,
        restrictedToMinimumLevel: LogEventLevel.Debug,
        retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel}  {SourceContext} - {Message:lj}{NewLine}{Exception}")

    //.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
    //Ends with ..txt as Date is inserted before file extension substring
    .WriteTo.File(new CompactJsonFormatter(), $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json", 
        rollingInterval: RollingInterval.Day, //Create a new JSON file every day
        retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
        restrictedToMinimumLevel: LogEventLevel.Debug)

    //Read any custom user configuration of logging from serilog config file
    .ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.config")
    .CreateLogger();

这是AppSettings配置文件的示例,用户可以使用其修改自己的接收器。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <!-- Controls log levels for all sinks (Set this higher than child sinks) -->
        <add key="serilog:minimum-level" value="Verbose" />

        <!-- Write to a user log file -->
        <add key="serilog:using:File" value="Serilog.Sinks.File" />
        <add key="serilog:write-to:File.path" value="%BASEDIR%\logs\warren-log.txt" /><!-- Can we do a relative path to website ? -->
        <add key="serilog:write-to:File.restrictedToMinimumLevel" value="Debug" /> 
        <add key="serilog:write-to:File.retainedFileCountLimit" value="32" /> <!-- Number of log files to keep (or remove value to keep all files) -->
        <add key="serilog:write-to:File.rollingInterval" value="Day" /> <!-- Create a new log file every Minute/Hour/Day/Month/Year/infinite -->

        <!-- TODO: How do I filter the file sink for customer to their own namespace ?? -->

    </appSettings>
</configuration>

我愿意就如何实现此目标提供想法和建议,以使开发人员可以配置自己的接收器,并根据需要过滤到自己的命名空间(因为我怀疑用户会想要编写自己的接收器接收器代码)

1 个答案:

答案 0 :(得分:2)

对于有兴趣或以后再看此帖子的人,这就是我解决的方法。

我使用了两个配置文件,一个用于配置主日志记录管道,另一个用于子记录器的用户配置,以便它们可以在需要时使用过滤,而不会影响主日志记录管道。

Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));

//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Verbose() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
    .Enrich.WithProcessId()
    .Enrich.WithProcessName()
    .Enrich.WithThreadId()
    .Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
    .Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
    .Enrich.With<Log4NetLevelMapperEnricher>()

    //Main .txt logfile - in similar format to older Log4Net output
    //Ends with ..txt as Date is inserted before file extension substring
    .WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
        rollingInterval: RollingInterval.Day,
        restrictedToMinimumLevel: LogEventLevel.Verbose,
        retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel}  {SourceContext} - {Message:lj}{NewLine}{Exception}")

    //.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
    //Ends with ..txt as Date is inserted before file extension substring
    .WriteTo.File(new CompactJsonFormatter(), $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json", 
        rollingInterval: RollingInterval.Day, //Create a new JSON file every day
        retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
        restrictedToMinimumLevel: LogEventLevel.Verbose)

    //Read from main serilog.config file
    .ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.config")

    //A nested logger - where any user configured sinks via config can not effect the main 'umbraco' logger above
    .WriteTo.Logger(cfg =>
        cfg.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.user.config"))
    .CreateLogger();

这是两个配置文件的示例:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>

        <!-- Used to toggle the loge levels for the main Umbraco log files -->
        <!-- Found at /app_data/logs/ -->
        <!-- NOTE: Changing this will also flow down into serilog.user.config -->
        <add key="serilog:minimum-level" value="Verbose" />

        <!-- To write to new log locations (aka Sinks) such as your own .txt files, ELMAH.io, Elastic, SEQ -->
        <!-- Please use the serilog.user.config file to configure your own logging needs -->

    </appSettings>
</configuration>

这是配置文件,用户可以在其中使用自己的名称空间进行过滤:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>

        <!-- Controls log levels for all user-definied child sub-logger sinks configured here (Set this higher than child sinks) -->
        <add key="serilog:minimum-level" value="Verbose" />

        <!-- For Different Namespaces - Set different logging levels -->
        <add key="serilog:minimum-level:override:Microsoft" value="Warning" />
        <add key="serilog:minimum-level:override:Microsoft.AspNetCore.Mvc" value="Error" />
        <add key="serilog:minimum-level:override:YourNameSpace" value="Information" />

        <!-- All logs definied via user.config will contain this property (won't be in main Umbraco logs) -->
        <add key="serilog:enrich:with-property:websiteName" value="Warrens Website" />

        <!-- Write to a user log file -->
        <add key="serilog:using:File" value="Serilog.Sinks.File" />
        <add key="serilog:write-to:File.path" value="%BASEDIR%\logs\warren-log.txt" />
        <add key="serilog:write-to:File.restrictedToMinimumLevel" value="Debug" /> <!-- I will be ignored as Debug as the user logging pipleine has it min set to Information, so only Info will flow through me -->
        <add key="serilog:write-to:File.retainedFileCountLimit" value="32" /> <!-- Number of log files to keep (or remove value to keep all files) -->
        <add key="serilog:write-to:File.rollingInterval" value="Day" /> <!-- Create a new log file every Minute/Hour/Day/Month/Year/infinite -->

        <!-- Filters all above sink's to use this expression -->
        <!-- Common use case is to include SourceType starting with your own namespace -->
        <add key="serilog:using:FilterExpressions" value="Serilog.Filters.Expressions" />
        <add key="serilog:filter:ByIncluding.expression" value="StartsWith(SourceContext, 'MyNamespace')" />

    </appSettings>
</configuration>