Base solution for your next web application
Open Closed

How to implement Serilog in ANZ platform #11018


User avatar
0
SRTMDEV created

Prerequisites

Please answer the following questions before submitting an issue. YOU MAY DELETE THE PREREQUISITES SECTION.

  • What is your product version? 11.0.0
  • What is your product type (Angular or MVC)? Angular
  • What is product framework type (.net framework or .net core)? .net core

Hello Team,

We would like to implement Serilog with Azure Log Analytics in ANZ. Can you guide us which Serilog library compatible with ANZ and where we can implment the changes to applicable in all ANZ project.

Thanks, SRTMDEV


8 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    You can use this package https://www.nuget.org/packages/Castle.Core-Serilog and configure it in the Startup.cs file as shown below;

    options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                        f => f.LogUsing(new SerilogFactory(config))
                    );
    

    instead of

    options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                        f => f.UseAbpLog4Net().WithConfig(_hostingEnvironment.IsDevelopment()
                            ? "log4net.config"
                            : "log4net.Production.config")
                    );
    

    A sample config would be something like this;

     var config = new LoggerConfiguration()
                    .Enrich.WithProperty("ApplicationName", Assembly.GetExecutingAssembly().GetName().Name)
                    .WriteTo.MSSqlServer("Serilog", "Logs", columnOptions:columnOptions)
                    .ReadFrom.AppSettings()
                    .CreateLogger();
    
  • User Avatar
    0
    SRTMDEV created

    Hello Team,

    Thanks you so much for really valued ans. This really help us to get started to implement Serilog. Now we have one requirment where on each log we want to write current TenantId and UserId in seperate columns which help us to analyze log for each tenant.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @SRTMDEV

    We are not much experienced with Serilog. Maybe you can find how to do this on Serilog's documentation by using its LoggerConfiguration.

  • User Avatar
    1
    marble68 created

    By the way, this package doesn't work with 11.0.

    Just adding the package to the project causes it throw an error in startup.

    To recreate:

    Add the aforementioned package: Castle.Core-Serilog Add to Public, MVC, Host, and Migrator, just like log4net. Run - You'll get the following error:

    System.TypeInitializationException HResult=0x80131534 Message=The type initializer for 'Abp.Dependency.IocManager' threw an exception. Source=Abp StackTrace: at Abp.AbpBootstrapperOptions..ctor() at Abp.AbpBootstrapper..ctor(Type startupModule, Action1 optionsAction) at Abp.AbpBootstrapper.Create[TStartupModule](Action1 optionsAction) at Abp.AspNetCore.AbpServiceCollectionExtensions.AddAbpBootstrapper[TStartupModule](IServiceCollection services, Action1 optionsAction) at Abp.AspNetCore.AbpServiceCollectionExtensions.AddAbp[TStartupModule](IServiceCollection services, Action1 optionsAction, Boolean removeConventionalInterceptors) at inzibackend.Web.Startup.Startup.ConfigureServices(IServiceCollection services) in R:\Surpathv2\src\inzibackend.Web.Mvc\Startup\Startup.cs:line 201 at System.RuntimeMethodHandle.InvokeMethod(Object target, Span1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection) at Microsoft.AspNetCore.Hosting.StartupLoader.ConfigureServicesDelegateBuilder1.<>c__DisplayClass15_0.<BuildStartupServicesFilterPipeline>g__RunPipeline|0(IServiceCollection services) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services) at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services) at Microsoft.AspNetCore.Hosting.StartupLoader.ConfigureServicesDelegateBuilder`1.<>c__DisplayClass14_0.

    This exception was originally thrown at this call stack: [External Code]

    Inner Exception 1: TypeLoadException: Could not load type 'Castle.Core.Pair`2' from assembly 'Castle.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc'.

  • User Avatar
    0
    Astech created

    @marble68 - Did you get to the bottom of this error? We are getting the exact same thing after upgrading: Could not load type 'Castle.Core.Pair`2' from assembly 'Castle.Core, Version=5.0.0.0,

  • User Avatar
    0
    Astech created

    For anyone else getting the same: https://support.aspnetzero.com/QA/Questions/11223/Castle-core-pair-2-load-error-version

  • User Avatar
    0
    marble68 created

    Hi @Astech - Yeah, sort of.

    Until ismcagdas get some of these libraries updates - you have to use the version 4 Serilog stuff.

    So basically - I added Serilog: Settings.Configuration, sinks.file, expressions, and extensions hosting -

    For Castle, it wants a factory. Serilog factory wants a serilog configuration - so, what you need in startup is:

                    var _loggerConfig = new LoggerConfiguration()
                        .ReadFrom.Configuration(_appConfiguration)
                        .CreateLogger();
    
                    options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                         f => f.LogUsing<SerilogFactory>(new SerilogFactory(_loggerConfig))
                    );
    

    In your appsettings - put your Serilog configuration in there. Something like this very basic configuration:

      "Serilog": {
        "Using": [
          "Serilog.Sinks.File",
          "Serilog.Expressions"
    
        ],
        "MinimumLevel": "Debug",
        "WriteTo": [
          {
            "Name": "Logger",
            "Args": {
              "configureLogger": {
                "Filter": [
                ],
                "WriteTo": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "./App_Data/Logs/SeriLog-.txt",
                      "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} -- [{SourceContext}]{NewLine}{Exception}",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 20,
                      "rollOnFileSizeLimit": true,
                      "fileSizeLimitBytes": 500000000
                    }
                  }
                ]
              }
            }
          },
        ],
        "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
      }
    

    My goal, which is probably like yours, is to get the sourcecontext flowing into serilog so we can break out the ANZ logs by domain etc. more easily.

    While Log4Net is adequate for logging, Serilog is on a whole different level IMHO.

    I think I'm not getting all the power of Serilog's context routing using this older version, but regardless, I have it almost there.

    Now, we wait for Castle Windsor to make it to Castle Core 5.

  • User Avatar
    0
    marble68 created

    For those who aren't familiar with Serilog and want to break their logs into logical domains, here's a configuration to get you started.

    I've not broken out healthchecks and web requests, but this basically puts anything logged from an app service in one log, anything from entityframework in another, and anything from backgroundworkers in yet another.

    Lastly - anything not logged into its own file lands in the general 'logs' file.

    Obviously, there's a gigantic advantage to having the log files setup this way.

    Of note, I have my serilog configuration in my appsettings (see above).

     "Serilog": {
        "Using": [
          "Serilog.Sinks.File",
          "Serilog.Expressions"
    
        ],
        "MinimumLevel": "Debug",
        "WriteTo": [
          {
            "Name": "Logger",
            "Args": {
              "configureLogger": {
                "Filter": [
                  {
                    "Name": "ByIncludingOnly",
                    "Args": {
                      "expression": "EndsWith(SourceContext, 'BackgroundWorker')"
                    }
                  }
                ],
                "WriteTo": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "./App_Data/Logs/BackgroundWorkersLog-.txt",
                      "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} -- [{SourceContext}]{NewLine}{Exception}",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 20,
                      "rollOnFileSizeLimit": true,
                      "fileSizeLimitBytes": 500000000
                    }
                  }
                ]
              }
            }
          },
          {
            "Name": "Logger",
            "Args": {
              "configureLogger": {
                "Filter": [
                  {
                    "Name": "ByIncludingOnly",
                    "Args": {
                      "expression": "StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore') or StartsWith(SourceContext, 'Microsoft.AspNetCore')"
                    }
                  }
                ],
                "WriteTo": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "./App_Data/Logs/EntityFrameworkLog-.txt",
                      "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} -- [{SourceContext}]{NewLine}{Exception}",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 20,
                      "rollOnFileSizeLimit": true,
                      "fileSizeLimitBytes": 500000000
                    }
                  }
                ]
              }
            }
          },
          {
            "Name": "Logger",
            "Args": {
              "configureLogger": {
                "Filter": [
                  {
                    "Name": "ByIncludingOnly",
                    "Args": {
                      "expression": "EndsWith(SourceContext, 'AppService')"
                    }
                  }
                ],
                "WriteTo": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "./App_Data/Logs/AppServicesLog-.txt",
                      "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} -- [{SourceContext}]{NewLine}{Exception}",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 20,
                      "rollOnFileSizeLimit": true,
                      "fileSizeLimitBytes": 500000000
                    }
                  }
                ]
              }
            }
          },
          {
            "Name": "Logger",
            "Args": {
              "configureLogger": {
                "Filter": [
                  {
                    "Name": "ByExcluding",
                    "Args": {
                      "expression": "EndsWith(SourceContext, 'AppService') or EndsWith(SourceContext, 'BackgroundWorker') or StartsWith(SourceContext, 'Microsoft.EntityFrameworkCore') or StartsWith(SourceContext, 'Microsoft.AspNetCore')"
                    }
                  }
                ],
                "WriteTo": [
                  {
                    "Name": "File",
                    "Args": {
                      "path": "./App_Data/Logs/Log-.txt",
                      "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} -- [{SourceContext}]{NewLine}{Exception}",
                      "rollingInterval": "Day",
                      "retainedFileCountLimit": 20,
                      "rollOnFileSizeLimit": true,
                      "fileSizeLimitBytes": 500000000
                    }
                  }
                ]
              }
            }
          }
        ],
        "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
      }