/// <summary> /// Create a new Log instance with default context with a failure sink. /// </summary> /// <param name="environment">The environment must be provided. This determines the ELK index, e.g. alog-local or alog-production.</param> /// <param name="config">Configuration for minimum log level and Elasticsearch connection details.</param> /// <param name="failureSink">Serilog failure sink. Pass null if not used.</param> /// <param name="failureCallback">Serilog failure callback. Pass null if not used.</param> /// <param name="enrichers">Serilog enrichers. If null, the default LogEnricher is used.</param> public Log(ElasticConfig config, LogLevel level, Func <string> createIndexName, ILogEventSink failureSink, Action <LogEvent> failureCallback, ILogEventEnricher[] enrichers) { _index = null == createIndexName ? "default" : createIndexName(); _config = config; _level = level; _enrichers = enrichers; _failureSink = failureSink; _failureCallback = failureCallback; var elasticOptions = new ElasticsearchSinkOptions(new Uri(config.Url)) { CustomFormatter = new LogExceptionFormatter(), MinimumLogEventLevel = LogEventLevel.Verbose, AutoRegisterTemplate = false, IndexDecider = (logEventProxy, dateTimeOffset) => _index, OverwriteTemplate = false, FailureCallback = null != _failureCallback ? _failureCallback : (e) => { Console.WriteLine("Unable to submit event " + e.MessageTemplate); }, EmitEventFailure = null != _failureSink ? EmitEventFailureHandling.WriteToSelfLog | EmitEventFailureHandling.WriteToFailureSink | EmitEventFailureHandling.RaiseCallback : EmitEventFailureHandling.WriteToSelfLog | EmitEventFailureHandling.RaiseCallback, FailureSink = _failureSink }; if (!string.IsNullOrWhiteSpace(_config.ElasticUser)) { elasticOptions.ModifyConnectionSettings = (connConfig) => connConfig.BasicAuthentication(config.ElasticUser, config.ElasticPassword); } Serilog.Debugging.SelfLog.Enable(msg => { Console.WriteLine(msg); }); var logConfig = new LoggerConfiguration() .WriteTo.Console() .WriteTo.Elasticsearch(elasticOptions); if (null == enrichers || enrichers.Length == 0) { enrichers = new[] { new LogEnricher() }; } logConfig.Enrich.With(enrichers); switch (_level) { case LogLevel.Trace: logConfig.MinimumLevel.Verbose(); break; case LogLevel.Debug: logConfig.MinimumLevel.Debug(); break; case LogLevel.Info: logConfig.MinimumLevel.Information(); break; case LogLevel.Warn: logConfig.MinimumLevel.Warning(); break; case LogLevel.Error: logConfig.MinimumLevel.Error(); break; default: logConfig.MinimumLevel.Fatal(); break; } _logger = logConfig.CreateLogger(); var ctx = new LogContext(); }
/// <summary> /// Create a new Log instance with default context. /// </summary> /// <param name="environment">The environment must be provided. This determines the ELK index, e.g. alog-local or alog-production.</param> /// <param name="config">Configuration for minimum log level and Elasticsearch connection details.</param> public Log(ElasticConfig config, LogLevel level, Func <string> createIndexName) : this(config, level, createIndexName, null, null, null) { }
/// <summary> /// Create a new Log instance with default context. /// </summary> /// <param name="environment">The environment must be provided. This determines the ELK index, e.g. alog-local or alog-production.</param> /// <param name="config">Configuration for minimum log level and Elasticsearch connection details.</param> /// <param name="enrichers">Serilog enrichers. If null, the default LogEnricher is used.</param> public Log(ElasticConfig config, LogLevel level, Func <string> createIndexName, ILogEventEnricher[] enrichers) : this(config, level, createIndexName, null, null, enrichers) { }
/// <summary> /// Add custom Serilog logging to Elasticsearch endpoint. /// </summary> /// <param name="services"></param> /// <param name="config">Connection configuration.</param> /// <param name="level">Log level</param> /// <param name="createIndexName">Function to create index name per request.</param> /// <param name="enrichers">Leave null to accept default enricher.</param> /// <returns></returns> public static IServiceCollection AddIokaLogging(this IServiceCollection services, ElasticConfig config, LogLevel level, Func <string> createIndexName, ILogEventEnricher[] enrichers = null, ILogEventSink failureSink = null, Action <LogEvent> failureCallback = null) { services.AddHttpContextAccessor(); services.AddSingleton <ContextProvider>(); services.AddSingleton <LogEnricher>((serviceProvider) => new LogEnricher(new LogContext(), LogContextFactory.CreateFactory(serviceProvider.GetService <ContextProvider>()))); services.AddScoped <ILog>((serviceProvider) => new Log(config, level, createIndexName, failureSink, failureCallback, (null == enrichers ? new[] { serviceProvider.GetService <LogEnricher>() } : enrichers))); var svcProvider = services.BuildServiceProvider(); var log = svcProvider.GetService <ILog>(); services.AddLogging(loggingBuilder => { // This is a variation of the .AddSerilog extension which filters out noisy framework messages. loggingBuilder.AddProvider((ILoggerProvider) new SerilogLoggerProvider(log.Logger, false)); FilterLoggingBuilderExtensions.AddFilter <SerilogLoggerProvider>(loggingBuilder, (category, logLevel) => { // Log all application level events from ALog.AspNet.Core.DefaultLogSource if (category == "Ioka.Services.Foundation.Logging.DefaultLogSource") { return(true); } // Log only Error level or above for other sources otherwise the logs will get jammed with // every ASP.NET Core event logged to ILogger this could be modified to allow configurable // logging of all framework events most of which are at Information level. if (logLevel > Microsoft.Extensions.Logging.LogLevel.Warning) { return(true); } return(false); }); }); // Configure ASP.NET Core extensions ILogger for default out of the box behavior. services.AddSingleton <Microsoft.Extensions.Logging.ILogger>((x) => x.GetRequiredService <ILogger <DefaultLogSource> >()); // As we have already called BuildServiceProvider and resolved ILog, we register it again to // assure that it is provided as a singleton after the ConfigureServices completes. services.AddSingleton <ILog>((x) => log); return(services); }