/// <summary>
        /// Add custom SerilogLogger to services
        /// </summary>
        /// <param name="services">services</param>
        /// <param name="loggerConfigure">Action to configure serilog LoggerConfiguration</param>
        /// <returns>IServiceCollection</returns>
        /// <summary>
        public static IServiceCollection AddCustomSerilogLogger(this IServiceCollection services, Action <LoggerConfiguration> loggerConfigure = null)
        {
            services.NotNull(nameof(services));

            AppDomain.CurrentDomain.ProcessExit += (s, e) =>
            {
                Log.CloseAndFlush();
            };

            var config = new LoggerConfiguration();

            //Customize LoggerConfiguration
            loggerConfigure?.Invoke(config);

            var logger = config.CreateLogger();
            //var logger = config.CreateLogger();
            var diagnosticContext    = new DiagnosticContext(logger);
            var serilogLogger        = new SerilogLogger(logger, diagnosticContext);
            var serilogLoggerFactory = new SerilogLoggerFactory(logger, diagnosticContext);

            MethodTimeLogger.Logger = serilogLogger;

            services.TryAddSingleton <ILogger>(serilogLogger);
            services.TryAddSingleton <ILoggerFactory>(serilogLoggerFactory);

            return(services);
        }
        /// <summary>
        /// Add SerilogLogger to services
        /// </summary>
        /// <param name="services">services</param>
        /// <param name="configure">Action to configure SerilogOptions (Enrichers, Sinks and ...)</param>
        /// <returns>IServiceCollection</returns>
        public static IServiceCollection AddSerilogLogger(this IServiceCollection services, Action <SerilogOptions> configure = null)
        {
            services.NotNull(nameof(services));

            AppDomain.CurrentDomain.ProcessExit += (s, e) =>
            {
                Log.CloseAndFlush();
            };

            var options = new SerilogOptions();

            configure?.Invoke(options);

            var logger               = options.LoggingEnabled ? CreateLogger() : global::Serilog.Core.Logger.None;
            var diagnosticContext    = new DiagnosticContext(logger);
            var serilogLogger        = new SerilogLogger(logger, diagnosticContext);
            var serilogLoggerFactory = new SerilogLoggerFactory(logger, diagnosticContext);

            LogConstants.LogErrorEnabled  = options.LoggingEnabled;
            LogConstants.LogCacheEnabled  = options.LoggingEnabled && options.LogCacheEnabled;
            LogConstants.LogTimingEnabled = options.LoggingEnabled && options.LogTimingEnabled;
            MethodTimeLogger.Logger       = serilogLogger;

            services.TryAddSingleton <ILogger>(serilogLogger);
            services.TryAddSingleton <ILoggerFactory>(serilogLoggerFactory);

            return(services);

            global::Serilog.ILogger CreateLogger()
            {
                var config = new LoggerConfiguration();

                #region Enrichers
                config.Enrich.FromLogContext();

                //https://www.nuget.org/packages/Serilog.Exceptions/
                //config.Enrich.WithExceptionDetails();

                if (options.WithCorrelationId)
                {
                    services.AddHttpContextAccessor();
                    config.Enrich.WithCorrelationId();
                }

                if (options.WithMemoryUsage)
                {
                    config.Enrich.WithMemoryUsage();
                }

                if (options.WithExceptionStackTraceHash)
                {
                    config.Enrich.WithExceptionStackTraceHash();
                }

                if (options.WithThreadId)
                {
                    config.Enrich.WithThreadId();
                }
                #endregion

                #region Sinks
                if (options.IsEnvDevelopment)
                {
                    if (options.EnableConsole)
                    {
                        config.WriteTo.Console(options.ConsoleMinimumLevel, theme: AnsiConsoleTheme.Code);
                    }

                    if (options.EnableDebug)
                    {
                        config.WriteTo.Debug(options.DebugMinimumLevel);
                    }
                }

                if (options.EnableFile)
                {
                    var filePath = Path.Combine(options.FileDirectory, "SmartCacheManager_Log_{Date}.txt");
                    config.WriteTo.File(filePath, restrictedToMinimumLevel: options.FileMinimumLevel,
                                        fileSizeLimitBytes: options.FileSizeLimitBytes, rollingInterval: options.FileRollingInterval, rollOnFileSizeLimit: true);
                }

                if (options.EnableEventLog)
                {
                    config.WriteTo.EventLog(options.EventLogApplicationName,
                                            restrictedToMinimumLevel: options.EventLogMinimumLevel,
                                            manageEventSource: true);
                }

                if (options.EnableSqlLog)
                {
                    options.SqlConnectionString.NotNullOrWhiteSpace(nameof(options.SqlConnectionString));

                    SqlHelper.CreateDatabaseIfNotExists(options.SqlConnectionString);

                    config.LogErrorToSqlServer(options.SqlConnectionString, LogEventLevel.Error);

                    if (options.LogTimingEnabled)
                    {
                        config.LogTimingToSqlServer(options.SqlConnectionString, LogEventLevel.Information);
                    }

                    if (options.LogCacheEnabled)
                    {
                        config.LogCacheToSqlServer(options.SqlConnectionString, LogEventLevel.Information);
                    }
                }
                #endregion

                return(config.CreateLogger());
            }
        }