Пример #1
0
        /// <summary>
        /// Adds a durable sink that sends log events using HTTP POST over the network. A durable
        /// sink will persist log events on disk before sending them over the network, thus
        /// protecting against data loss after a system or process restart.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="bufferPathFormat">
        /// The path format for a set of files that will be used to buffer events until they can be
        /// successfully sent over the network. Default value is "Buffer-{Date}.json". To use file
        /// rotation that is on an 30 or 60 minute interval pass "Buffer-{Hour}.json" or
        /// "Buffer-{HalfHour}.json".
        /// </param>
        /// <param name="bufferFileSizeLimitBytes">
        /// The maximum size, in bytes, to which the buffer log file for a specific date will be
        /// allowed to grow. By default no limit will be applied.
        /// </param>
        /// <param name="retainedBufferFileCountLimit">
        /// The maximum number of buffer files that will be retained, including the current buffer
        /// file. Under normal operation only 2 files will be kept, however if the log server is
        /// unreachable, the number of files specified by <paramref name="retainedBufferFileCountLimit"/>
        /// will be kept on the file system. For unlimited retention, pass null. Default value is 31.
        /// </param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration DurableHttp(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            string bufferPathFormat          = "Buffer-{Date}.json",
            long?bufferFileSizeLimitBytes    = null,
            int?retainedBufferFileCountLimit = 31,
            int batchPostingLimit            = 1000,
            TimeSpan?period = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            var sink = new DurableHttpSink(
                requestUri,
                bufferPathFormat,
                bufferFileSizeLimitBytes,
                retainedBufferFileCountLimit,
                batchPostingLimit,
                period ?? TimeSpan.FromSeconds(2),
                textFormatter ?? new NormalRenderedTextFormatter(),
                batchFormatter ?? new DefaultBatchFormatter(),
                httpClient ?? new HttpClientWrapper());

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TimeRolledDurableHttpSink"/> class.
        /// </summary>
        public TimeRolledDurableHttpSink(
            string requestUri,
            string bufferPathFormat,
            long?bufferFileSizeLimitBytes,
            bool bufferFileShared,
            int?retainedBufferFileCountLimit,
            int batchPostingLimit,
            long batchSizeLimitBytes,
            TimeSpan period,
            ITextFormatter textFormatter,
            IBatchFormatter batchFormatter,
            IHttpClient httpClient)
        {
            if (bufferFileSizeLimitBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferFileSizeLimitBytes), "Negative value provided; file size limit must be non-negative.");
            }

            shipper = new HttpLogShipper(
                httpClient,
                requestUri,
                new TimeRolledBufferFiles(new DirectoryService(), bufferPathFormat),
                batchPostingLimit,
                batchSizeLimitBytes,
                period,
                batchFormatter);

            sink = new RollingFileSink(
                bufferPathFormat,
                textFormatter,
                bufferFileSizeLimitBytes,
                retainedBufferFileCountLimit,
                Encoding.UTF8,
                shared: bufferFileShared);
        }
Пример #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DurableHttpSink"/> class.
        /// </summary>
        public DurableHttpSink(
            string requestUri,
            string bufferPathFormat,
            long?bufferFileSizeLimitBytes,
            int?retainedBufferFileCountLimit,
            int batchPostingLimit,
            TimeSpan period,
            ITextFormatter textFormatter,
            IBatchFormatter batchFormatter,
            IHttpClient client)
        {
            if (bufferFileSizeLimitBytes.HasValue && bufferFileSizeLimitBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferFileSizeLimitBytes), "Negative value provided; file size limit must be non-negative.");
            }

            shipper = new HttpLogShipper(
                client,
                requestUri,
                bufferPathFormat,
                batchPostingLimit,
                period,
                batchFormatter);

            sink = new RollingFileSink(
                bufferPathFormat,
                textFormatter,
                bufferFileSizeLimitBytes,
                retainedBufferFileCountLimit,
                Encoding.UTF8);
        }
Пример #4
0
        public FileSizeRolledDurableHttpSink(
            string requestUri,
            string bufferBaseFileName,
            long?bufferFileSizeLimitBytes,
            bool bufferFileShared,
            int?retainedBufferFileCountLimit,
            long?logEventLimitBytes,
            int?logEventsInBatchLimit,
            long?batchSizeLimitBytes,
            TimeSpan period,
            ITextFormatter textFormatter,
            IBatchFormatter batchFormatter,
            IHttpClient httpClient)
        {
            shipper = new HttpLogShipper(
                httpClient,
                requestUri,
                new FileSizeRolledBufferFiles(new DirectoryService(), bufferBaseFileName),
                logEventLimitBytes,
                logEventsInBatchLimit,
                batchSizeLimitBytes,
                period,
                batchFormatter);

            sink = CreateFileSink(
                bufferBaseFileName,
                bufferFileSizeLimitBytes,
                bufferFileShared,
                retainedBufferFileCountLimit,
                textFormatter);
        }
        /// <summary>
        /// Adds a non durable sink that sends log events using HTTP POST over the network. A
        /// non-durable sink will lose data after a system or process restart.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration Http(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            int batchPostingLimit                  = 1000,
            TimeSpan?period                        = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient                 = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            var sink = new HttpSink(
                requestUri,
                batchPostingLimit,
                period ?? TimeSpan.FromSeconds(2),
                textFormatter ?? new NormalRenderedTextFormatter(),
                batchFormatter ?? new DefaultBatchFormatter(),
                httpClient ?? new HttpClientWrapper());

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="FileSizeRolledDurableHttpSink"/> class.
        /// </summary>
        public FileSizeRolledDurableHttpSink(
            string requestUri,
            string bufferBaseFileName,
            long?bufferFileSizeLimitBytes,
            int?retainedBufferFileCountLimit,
            int batchPostingLimit,
            TimeSpan period,
            ITextFormatter textFormatter,
            IBatchFormatter batchFormatter,
            IHttpClient client)
        {
            if (bufferFileSizeLimitBytes.HasValue && bufferFileSizeLimitBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferFileSizeLimitBytes), "Negative value provided; file size limit must be non-negative.");
            }

            shipper = new HttpLogShipper(
                client,
                requestUri,
                new FileSizeRolledBufferFiles(new DirectoryService(), bufferBaseFileName),
                batchPostingLimit,
                period,
                batchFormatter);

            sink = new LoggerConfiguration()
                   .WriteTo.File(
                textFormatter,
                $"{bufferBaseFileName}-.json",
                fileSizeLimitBytes: bufferFileSizeLimitBytes,
                rollOnFileSizeLimit: true,
                retainedFileCountLimit: retainedBufferFileCountLimit,
                rollingInterval: RollingInterval.Day,
                encoding: Encoding.UTF8)
                   .CreateLogger();
        }
Пример #7
0
 public static LoggerConfiguration DurableHttp(
     this LoggerSinkConfiguration sinkConfiguration,
     string requestUri,
     string bufferPathFormat          = "Buffer-{Date}.json",
     long?bufferFileSizeLimitBytes    = null,
     int?retainedBufferFileCountLimit = 31,
     int batchPostingLimit            = 1000,
     TimeSpan?period = null,
     ITextFormatter textFormatter           = null,
     IBatchFormatter batchFormatter         = null,
     LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
     IHttpClient httpClient = null)
 {
     return(DurableHttpUsingTimeRolledBuffers(
                sinkConfiguration,
                requestUri,
                bufferPathFormat,
                bufferFileSizeLimitBytes,
                retainedBufferFileCountLimit,
                batchPostingLimit,
                period,
                textFormatter,
                batchFormatter,
                restrictedToMinimumLevel,
                httpClient));
 }
        /// <summary>
        /// Adds a non-durable sink that sends log events using HTTP POST over the network. A
        /// non-durable sink will lose data after a system or process restart.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="queueLimit">
        /// The maximum number of events stored in the queue in memory, waiting to be posted over
        /// the network. Default value is infinitely.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration Http(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            int batchPostingLimit                  = 1000,
            int?queueLimit                         = null,
            TimeSpan?period                        = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient                 = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            // Default values
            period         = period ?? TimeSpan.FromSeconds(2);
            textFormatter  = textFormatter ?? new NormalRenderedTextFormatter();
            batchFormatter = batchFormatter ?? new DefaultBatchFormatter();
            httpClient     = httpClient ?? new DefaultHttpClient();

            var sink = queueLimit != null
                ? new HttpSink(requestUri, batchPostingLimit, queueLimit.Value, period.Value, textFormatter, batchFormatter, httpClient)
                : new HttpSink(requestUri, batchPostingLimit, period.Value, textFormatter, batchFormatter, httpClient);

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
Пример #9
0
        public HttpLogShipper(
            IHttpClient client,
            string requestUri,
            string bufferBaseFilename,
            int batchPostingLimit,
            TimeSpan period,
            IBatchFormatter batchFormatter)
        {
            if (bufferBaseFilename == null)
            {
                throw new ArgumentNullException(nameof(bufferBaseFilename));
            }
            if (batchPostingLimit <= 0)
            {
                throw new ArgumentException("batchPostingLimit must be 1 or greater", nameof(batchPostingLimit));
            }

            this.client            = client ?? throw new ArgumentNullException(nameof(client));
            this.requestUri        = requestUri ?? throw new ArgumentNullException(nameof(requestUri));
            this.batchPostingLimit = batchPostingLimit;
            this.batchFormatter    = batchFormatter ?? throw new ArgumentNullException(nameof(batchFormatter));

            bookmarkFilename    = Path.GetFullPath(bufferBaseFilename + ".bookmark");
            logFolder           = Path.GetDirectoryName(bookmarkFilename);
            candidateSearchPath = Path.GetFileName(bufferBaseFilename) + "*.json";
            connectionSchedule  = new ExponentialBackoffConnectionSchedule(period);
            timer = new PortableTimer(OnTick);

            SetTimer();
        }
 public TencentCloudSink(string requestUri, int batchSizeLimit, TimeSpan period, int queueLimit, IHttpClient client, IBatchFormatter clsFormatter)
     : base(batchSizeLimit, period, queueLimit)
 {
     this.requestUri   = requestUri ?? throw new ArgumentNullException(nameof(requestUri));
     this.clsFormatter = clsFormatter ?? throw new ArgumentNullException(nameof(clsFormatter));
     this.client       = client ?? throw new ArgumentNullException(nameof(client));
 }
Пример #11
0
 public HttpSink(
     string requestUri,
     int batchPostingLimit,
     TimeSpan period,
     ITextFormatter textFormatter,
     IBatchFormatter batchFormatter,
     IHttpClient client)
     : base(batchPostingLimit, period)
 {
     this.requestUri     = requestUri ?? throw new ArgumentNullException(nameof(requestUri));
     this.textFormatter  = textFormatter ?? throw new ArgumentNullException(nameof(textFormatter));
     this.batchFormatter = batchFormatter ?? throw new ArgumentNullException(nameof(batchFormatter));
     this.client         = client ?? throw new ArgumentNullException(nameof(client));
 }
Пример #12
0
        public HttpLogShipper(
            IHttpClient client,
            string requestUri,
            string bufferPathFormat,
            int batchPostingLimit,
            TimeSpan period,
            IBatchFormatter batchFormatter)
        {
            if (bufferPathFormat == null)
            {
                throw new ArgumentNullException(nameof(bufferPathFormat));
            }
            if (bufferPathFormat != bufferPathFormat.Trim())
            {
                throw new ArgumentException("bufferPathFormat must not contain any leading or trailing whitespaces", nameof(bufferPathFormat));
            }
            if (batchPostingLimit <= 0)
            {
                throw new ArgumentException("batchPostingLimit must be 1 or greater", nameof(batchPostingLimit));
            }

            this.client            = client ?? throw new ArgumentNullException(nameof(client));
            this.requestUri        = requestUri ?? throw new ArgumentNullException(nameof(requestUri));
            this.batchPostingLimit = batchPostingLimit;
            this.batchFormatter    = batchFormatter ?? throw new ArgumentNullException(nameof(batchFormatter));

            var bufferPathFormatMatch = BufferPathFormatRegex.Match(bufferPathFormat);

            if (!bufferPathFormatMatch.Success)
            {
                throw new ArgumentException($"bufferPathFormat must include one of the date formats [{string.Join(", ", Enum.GetNames(typeof(DateFormats)))}]");
            }

            var prefix  = bufferPathFormatMatch.Groups["prefix"];
            var postfix = bufferPathFormatMatch.Groups["postfix"];

            bookmarkFilename    = Path.GetFullPath(prefix.Value.TrimEnd(new char[] { '-' }) + ".bookmark");
            logFolder           = Path.GetDirectoryName(bookmarkFilename);
            candidateSearchPath = $"{Path.GetFileName(prefix.Value)}*{postfix.Value}";
            connectionSchedule  = new ExponentialBackoffConnectionSchedule(period);
            timer = new PortableTimer(OnTick);

            SetTimer();
        }
        /// <summary>
        /// Adds a durable sink that sends log events using HTTP POST over the network. A durable
        /// sink will persist log events on disk in buffer files before sending them over the
        /// network, thus protecting against data loss after a system or process restart. The
        /// buffer files will use a rolling behavior defined by the file size specified in
        /// <paramref name="bufferFileSizeLimitBytes"/>, i.e. a new buffer file is created when
        /// current has passed its limit. The maximum number of retained files is defined by
        /// <paramref name="retainedBufferFileCountLimit"/>, and when that limit is reached the
        /// oldest file is dropped to make room for a new.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="bufferBaseFileName">
        /// The relative or absolute path for a set of files that will be used to buffer events
        /// until they can be successfully transmitted across the network. Individual files will be
        /// created using the pattern "<paramref name="bufferBaseFileName"/>*.json", which should
        /// not clash with any other file names in the same directory. Default value is "Buffer".
        /// </param>
        /// <param name="bufferFileSizeLimitBytes">
        /// The approximate maximum size, in bytes, to which a buffer file will be allowed to grow.
        /// For unrestricted growth, pass null. The default is 1 GB. To avoid writing partial
        /// events, the last event within the limit will be written in full even if it exceeds the
        /// limit.
        /// </param>
        /// <param name="bufferFileShared">
        /// Allow the buffer file to be shared by multiple processes. Default value is false.
        /// </param>
        /// <param name="retainedBufferFileCountLimit">
        /// The maximum number of buffer files that will be retained, including the current buffer
        /// file. Under normal operation only 2 files will be kept, however if the log server is
        /// unreachable, the number of files specified by
        /// <paramref name="retainedBufferFileCountLimit"/> will be kept on the file system. For
        /// unlimited retention, pass null. Default value is 31.
        /// </param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="batchSizeLimitBytes">
        /// The approximate maximum size, in bytes, for a single batch. The value is an
        /// approximation because only the size of the log events are considered. The extra
        /// characters added by the batch formatter, where the sequence of serialized log events
        /// are transformed into a payload, are not considered. Please make sure to accommodate for
        /// those. Default value is long.MaxValue.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <param name="configuration">
        /// Configuration passed to <paramref name="httpClient"/>. Parameter is either manually
        /// specified when configuring the sink in source code or automatically passed in when
        /// configuring the sink using
        /// <see href="https://www.nuget.org/packages/Serilog.Settings.Configuration">Serilog.Settings.Configuration</see>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration DurableHttpUsingFileSizeRolledBuffers(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            string bufferBaseFileName        = "Buffer",
            long?bufferFileSizeLimitBytes    = ByteSize.GB,
            bool bufferFileShared            = false,
            int?retainedBufferFileCountLimit = 31,
            int batchPostingLimit            = 1000,
            long batchSizeLimitBytes         = long.MaxValue,
            TimeSpan?period = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient       = null,
            IConfiguration configuration = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            // Default values
            period ??= TimeSpan.FromSeconds(2);
            textFormatter ??= new NormalRenderedTextFormatter();
            batchFormatter ??= new DefaultBatchFormatter();
            httpClient ??= new DefaultHttpClient();
            httpClient.Configure(configuration);

            var sink = new FileSizeRolledDurableHttpSink(
                requestUri: requestUri,
                bufferBaseFileName: bufferBaseFileName,
                bufferFileSizeLimitBytes: bufferFileSizeLimitBytes,
                bufferFileShared: bufferFileShared,
                retainedBufferFileCountLimit: retainedBufferFileCountLimit,
                batchPostingLimit: batchPostingLimit,
                batchSizeLimitBytes: batchSizeLimitBytes,
                period: period.Value,
                textFormatter: textFormatter,
                batchFormatter: batchFormatter,
                httpClient: httpClient);

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
        public TimeRolledDurableHttpSink(
            string requestUri,
            string bufferBaseFileName,
            BufferRollingInterval bufferRollingInterval,
            long?bufferFileSizeLimitBytes,
            bool bufferFileShared,
            int?retainedBufferFileCountLimit,
            int batchPostingLimit,
            long batchSizeLimitBytes,
            TimeSpan period,
            ITextFormatter textFormatter,
            IBatchFormatter batchFormatter,
            IHttpClient httpClient)
        {
            if (bufferFileSizeLimitBytes < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferFileSizeLimitBytes), "Negative value provided; file size limit must be non-negative.");
            }

            shipper = new HttpLogShipper(
                httpClient,
                requestUri,
                new TimeRolledBufferFiles(new DirectoryService(), bufferBaseFileName),
                batchPostingLimit,
                batchSizeLimitBytes,
                period,
                batchFormatter);

            sink = new LoggerConfiguration()
                   .WriteTo.File(
                formatter: textFormatter,
                path: $"{bufferBaseFileName}-.json",
                fileSizeLimitBytes: bufferFileSizeLimitBytes,
                shared: bufferFileShared,
                rollingInterval: bufferRollingInterval.ToRollingInterval(),
                rollOnFileSizeLimit: false,
                retainedFileCountLimit: retainedBufferFileCountLimit)
                   .CreateLogger();
        }
        /// <summary>
        /// Adds a durable sink that sends log events using HTTP POST over the network. A durable
        /// sink will persist log events on disk in buffer files before sending them over the
        /// network, thus protecting against data loss after a system or process restart. The
        /// buffer files will use a rolling behavior defined by the file size specified in
        /// <paramref name="bufferFileSizeLimitBytes"/>, i.e. a new buffer file is created when
        /// current has passed its limit. The maximum number of retained files is defined by
        /// <paramref name="retainedBufferFileCountLimit"/>, and when that limit is reached the
        /// oldest file is dropped to make room for a new.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="bufferBaseFileName">
        /// The relative or absolute path for a set of files that will be used to buffer events
        /// until they can be successfully transmitted across the network. Individual files will be
        /// created using the pattern "<paramref name="bufferBaseFileName"/>*.json", which should
        /// not clash with any other file names in the same directory. Default value is "Buffer".
        /// </param>
        /// <param name="bufferFileSizeLimitBytes">
        /// The approximate maximum size, in bytes, to which a buffer file will be allowed to grow.
        /// For unrestricted growth, pass null. The default is 1 GB. To avoid writing partial
        /// events, the last event within the limit will be written in full even if it exceeds the
        /// limit.
        /// </param>
        /// <param name="retainedBufferFileCountLimit">
        /// The maximum number of buffer files that will be retained, including the current buffer
        /// file. Under normal operation only 2 files will be kept, however if the log server is
        /// unreachable, the number of files specified by <paramref name="retainedBufferFileCountLimit"/>
        /// will be kept on the file system. For unlimited retention, pass null. Default value is 31.
        /// </param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration DurableElasticEcsLogstashUsingFileSizeRolledBuffers(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            string bufferBaseFileName        = "Buffer",
            long?bufferFileSizeLimitBytes    = 1024 * 1024 * 1024,
            int?retainedBufferFileCountLimit = 31,
            int batchPostingLimit            = 1000,
            TimeSpan?period = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            // Default values
            period         = period ?? TimeSpan.FromSeconds(2);
            textFormatter  = textFormatter ?? new NormalRenderedTextFormatter();
            batchFormatter = batchFormatter ?? new DefaultBatchFormatter();
            httpClient     = httpClient ?? new DefaultHttpClient();

            var sink = new FileSizeRolledDurableElasticEcsLogstashSink(
                requestUri,
                bufferBaseFileName,
                bufferFileSizeLimitBytes,
                retainedBufferFileCountLimit,
                batchPostingLimit,
                period.Value,
                textFormatter,
                batchFormatter,
                httpClient);

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
        /// <summary>
        /// Adds a non-durable sink that sends log events using HTTP POST over the network. A
        /// non-durable sink will lose data after a system or process restart.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="batchSizeLimitBytes">
        /// The approximate maximum size, in bytes, for a single batch. The value is an
        /// approximation because only the size of the log events are considered. The extra
        /// characters added by the batch formatter, where the sequence of serialized log events
        /// are transformed into a payload, are not considered. Please make sure to accommodate for
        /// those. Default value is long.MaxValue.
        /// </param>
        /// <param name="queueLimit">
        /// The maximum number of events stored in the queue in memory, waiting to be posted over
        /// the network. Default value is infinitely.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <param name="configuration">
        /// Configuration passed to <paramref name="httpClient"/>. Parameter is either manually
        /// specified when configuring the sink in source code or automatically passed in when
        /// configuring the sink using
        /// <see href="https://www.nuget.org/packages/Serilog.Settings.Configuration">Serilog.Settings.Configuration</see>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration Http(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            int batchPostingLimit                  = 1000,
            long batchSizeLimitBytes               = long.MaxValue,
            int?queueLimit                         = null,
            TimeSpan?period                        = null,
            ITextFormatter textFormatter           = null,
            IBatchFormatter batchFormatter         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IHttpClient httpClient                 = null,
            IConfiguration configuration           = null)
        {
            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            // Default values
            period ??= TimeSpan.FromSeconds(2);
            textFormatter ??= new NormalRenderedTextFormatter();
            batchFormatter ??= new DefaultBatchFormatter();
            httpClient ??= new DefaultHttpClient();
            httpClient.Configure(configuration);

            var sink = new HttpSink(
                requestUri: requestUri,
                batchPostingLimit: batchPostingLimit,
                batchSizeLimitBytes: batchSizeLimitBytes,
                queueLimit: queueLimit,
                period: period.Value,
                textFormatter: textFormatter,
                batchFormatter: batchFormatter,
                httpClient: httpClient);

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }
        public HttpLogShipper(
            IHttpClient client,
            string requestUri,
            IBufferFiles bufferFiles,
            int batchPostingLimit,
            TimeSpan period,
            IBatchFormatter batchFormatter)
        {
            if (batchPostingLimit <= 0)
            {
                throw new ArgumentException("batchPostingLimit must be 1 or greater", nameof(batchPostingLimit));
            }

            this.client            = client ?? throw new ArgumentNullException(nameof(client));
            this.requestUri        = requestUri ?? throw new ArgumentNullException(nameof(requestUri));
            this.bufferFiles       = bufferFiles ?? throw new ArgumentNullException(nameof(bufferFiles));
            this.batchPostingLimit = batchPostingLimit;
            this.batchFormatter    = batchFormatter ?? throw new ArgumentNullException(nameof(batchFormatter));

            connectionSchedule = new ExponentialBackoffConnectionSchedule(period);
            timer = new PortableTimer(OnTick);

            SetTimer();
        }
        /// <summary>
        /// Adds a durable sink that sends log events using HTTP POST over the network. A durable
        /// sink will persist log events on disk in buffer files before sending them over the
        /// network, thus protecting against data loss after a system or process restart. The
        /// buffer files will use a rolling behavior defined by the file size specified in
        /// <paramref name="bufferFileSizeLimitBytes"/>, i.e. a new buffer file is created when
        /// current has passed its limit. The maximum number of retained files is defined by
        /// <paramref name="retainedBufferFileCountLimit"/>, and when that limit is reached the
        /// oldest file is dropped to make room for a new.
        /// </summary>
        /// <param name="sinkConfiguration">The logger configuration.</param>
        /// <param name="requestUri">The URI the request is sent to.</param>
        /// <param name="bufferBaseFileName">
        /// The relative or absolute path for a set of files that will be used to buffer events
        /// until they can be successfully transmitted across the network. Individual files will be
        /// created using the pattern "<paramref name="bufferBaseFileName"/>*.json", which should
        /// not clash with any other file names in the same directory. Default value is "Buffer".
        /// </param>
        /// <param name="bufferFileSizeLimitBytes">
        /// The approximate maximum size, in bytes, to which a buffer file will be allowed to grow.
        /// For unrestricted growth, pass null. The default is 1 GB. To avoid writing partial
        /// events, the last event within the limit will be written in full even if it exceeds the
        /// limit.
        /// </param>
        /// <param name="bufferFileShared">
        /// Allow the buffer file to be shared by multiple processes. Default value is false.
        /// </param>
        /// <param name="retainedBufferFileCountLimit">
        /// The maximum number of buffer files that will be retained, including the current buffer
        /// file. Under normal operation only 2 files will be kept, however if the log server is
        /// unreachable, the number of files specified by <paramref name="retainedBufferFileCountLimit"/>
        /// will be kept on the file system. For unlimited retention, pass null. Default value is 31.
        /// </param>
        /// <param name="batchPostingLimit">
        /// The maximum number of events to post in a single batch. Default value is 1000.
        /// </param>
        /// <param name="period">
        /// The time to wait between checking for event batches. Default value is 2 seconds.
        /// </param>
        /// <param name="textFormatter">
        /// The formatter rendering individual log events into text, for example JSON. Default
        /// value is <see cref="NormalRenderedTextFormatter"/>.
        /// </param>
        /// <param name="batchFormatter">
        /// The formatter batching multiple log events into a payload that can be sent over the
        /// network. Default value is <see cref="DefaultBatchFormatter"/>.
        /// </param>
        /// <param name="restrictedToMinimumLevel">
        /// The minimum level for events passed through the sink. Default value is
        /// <see cref="LevelAlias.Minimum"/>.
        /// </param>
        /// <param name="httpClient">
        /// A custom <see cref="IHttpClient"/> implementation. Default value is
        /// <see cref="HttpClient"/>.
        /// </param>
        /// <returns>Logger configuration, allowing configuration to continue.</returns>
        public static LoggerConfiguration Site24x7UsingFileSizeRolledBuffers(
            this LoggerSinkConfiguration sinkConfiguration,
            string requestUri,
            string minimumLogLevel           = null,
            string bufferBaseFileName        = "Buffer",
            long?bufferFileSizeLimitBytes    = 1024 * 1024 * 1024,
            bool bufferFileShared            = false,
            int?retainedBufferFileCountLimit = 31,
            int batchPostingLimit            = 1000,
            TimeSpan?period = null,
            ITextFormatter textFormatter   = null,
            IBatchFormatter batchFormatter = null,

            IHttpClient httpClient = null)
        {
            LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose;

            if (minimumLogLevel == null)
            {
                restrictedToMinimumLevel = LogEventLevel.Verbose;
            }
            else if (minimumLogLevel == "Debug")
            {
                restrictedToMinimumLevel = LogEventLevel.Debug;
            }
            else if (minimumLogLevel == "Information")
            {
                restrictedToMinimumLevel = LogEventLevel.Information;
            }
            else if (minimumLogLevel == "Warning")
            {
                restrictedToMinimumLevel = LogEventLevel.Warning;
            }
            else if (minimumLogLevel == "Error")
            {
                restrictedToMinimumLevel = LogEventLevel.Error;
            }
            else if (minimumLogLevel == "Fatal")
            {
                restrictedToMinimumLevel = LogEventLevel.Fatal;
            }
            else
            {
                restrictedToMinimumLevel = LogEventLevel.Verbose;
            }

            if (sinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(sinkConfiguration));
            }

            // Default values
            period         = period ?? TimeSpan.FromMilliseconds(1);
            textFormatter  = textFormatter ?? new NormalRenderedTextFormatter();
            batchFormatter = batchFormatter ?? new DefaultBatchFormatter();
            httpClient     = httpClient ?? new DefaultHttpClient();

            var sink = new FileSizeRolledDurableHttpSink(
                requestUri: requestUri,
                bufferBaseFileName: bufferBaseFileName,
                bufferFileSizeLimitBytes: bufferFileSizeLimitBytes,
                bufferFileShared: bufferFileShared,
                retainedBufferFileCountLimit: retainedBufferFileCountLimit,
                batchPostingLimit: batchPostingLimit,
                period: period.Value,
                textFormatter: textFormatter,
                batchFormatter: batchFormatter,
                httpClient: httpClient);

            return(sinkConfiguration.Sink(sink, restrictedToMinimumLevel));
        }