/// <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)
 {
 }
Exemple #4
0
        /// <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);
        }