public static IServiceCollection AddLogger(this IServiceCollection collection, IConfiguration configuration)
        {
            var logConfig = new LoggerConfiguration();
            var sink      = configuration["Logging:Sink"];

            switch (sink)
            {
            case "AWSCloudWatch":
                var accessKeyId           = configuration["AWS:AccessKeyId"];
                var accessSecretAccessKey = configuration["AWS:AccessSecretAccessKey"];

                var client  = new AmazonCloudWatchLogsClient(accessKeyId, accessSecretAccessKey, RegionEndpoint.EUWest2);
                var options = new CloudWatchSinkOptions
                {
                    LogGroupName          = "shared-list-beanstalk-log/ShareListApi-env",
                    Period                = TimeSpan.FromSeconds(10),
                    BatchSizeLimit        = 100,
                    QueueSizeLimit        = 10000,
                    LogStreamNameProvider = new DefaultLogStreamProvider(),
                    RetryAttempts         = 5,
                    CreateLogGroup        = true,
                    TextFormatter         = new AWSTextFormatter(),
                };

                logConfig.WriteTo.AmazonCloudWatch(options, client);
                break;

            default:
                logConfig.WriteTo.RollingFile(Path.Combine(AppContext.BaseDirectory, "log-{Date}.log"));
                break;
            }

            collection.AddSingleton <ILogger>(logConfig.CreateLogger());
            return(collection);
        }
Beispiel #2
0
        private static void AwsCloudwatchSinkConfiger(LoggerConfiguration lscf)
        {
            // name of the log group
            var logGroupName = "myLogGroup/dev";

            // options for the sink defaults in https://github.com/Cimpress-MCP/serilog-sinks-awscloudwatch/blob/master/src/Serilog.Sinks.AwsCloudWatch/CloudWatchSinkOptions.cs
            var options = new CloudWatchSinkOptions
            {
                // you must provide a text formatter, otherwise exception throw
                TextFormatter = new Serilog.Formatting.Json.JsonFormatter(),
                // the name of the CloudWatch Log group for logging
                LogGroupName = logGroupName,

                // other defaults defaults
                MinimumLogEventLevel = Serilog.Events.LogEventLevel.Information,
                BatchSizeLimit       = 100,
                QueueSizeLimit       = 10000,
                Period                = TimeSpan.FromSeconds(10),
                CreateLogGroup        = true,
                LogStreamNameProvider = new DefaultLogStreamProvider(),
                RetryAttempts         = 5
            };

            // setup AWS CloudWatch client
            var client = new AmazonCloudWatchLogsClient("yourAwsAccessKey", "yourAwsSecretAccessKey", RegionEndpoint.USWest2);

            lscf.WriteTo
            .AmazonCloudWatch(options, client);
        }
Beispiel #3
0
        public static LoggerConfiguration AppendAwsCloudwatchLogger(this LoggerConfiguration logger,
                                                                    string logGroupName,
                                                                    string environmentName,
                                                                    LogEventLevel minimumLogEvent)
        {
            logGroupName = $"{logGroupName}/{environmentName}".ToLower();

            var formatter = new CompactJsonFormatter();
            var options   = new CloudWatchSinkOptions
            {
                LogGroupName         = logGroupName,
                TextFormatter        = formatter,
                MinimumLogEventLevel = minimumLogEvent,
                BatchSizeLimit       = 100,
                QueueSizeLimit       = 10000,
                Period                  = TimeSpan.FromSeconds(10),
                CreateLogGroup          = true,
                LogStreamNameProvider   = new DefaultLogStreamProvider(),
                RetryAttempts           = 5,
                LogGroupRetentionPolicy = LogGroupRetentionPolicy.OneDay
            };

            var client = new AmazonCloudWatchLogsClient(RegionEndpoint.SAEast1);

            return(logger
                   //.Filter.ByExcluding(c => c.Properties.Any(p => p.Value.ToString().Contains("swagger")))
                   .WriteTo.AmazonCloudWatch(options, client));
        }
Beispiel #4
0
        private static Logger CreateLogger()
        {
            var group       = "Context";
            var application = "API.Context";

#if (!DEBUG)
            var client = Configuration.GetAWSOptions().CreateServiceClient <IAmazonCloudWatchLogs>();

            var options = new CloudWatchSinkOptions
            {
                LogGroupName            = $"Applications/{group}/{application}",
                LogStreamNameProvider   = new DefaultLogStreamProvider(),
                BatchSizeLimit          = 100,
                QueueSizeLimit          = 10000,
                RetryAttempts           = 3,
                LogGroupRetentionPolicy = LogGroupRetentionPolicy.FiveDays,
                TextFormatter           = new JsonFormatter(),
                MinimumLogEventLevel    = LogEventLevel.Information
            };
#endif
            return(new LoggerConfiguration()
                   .Enrich.FromLogContext()
                   .Enrich.WithProperty("Application", application)
                   .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                   .MinimumLevel.Debug()
                   .WriteTo.Console(
                       outputTemplate: "{NewLine}[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Scope} {Message}{NewLine}{Exception}"
                       )
#if (!DEBUG)
                   .WriteTo.AmazonCloudWatch(options, client)
#endif
                   .CreateLogger());
        }
Beispiel #5
0
        public static void InitLogger(string awsAccessKey, string awsSecretKey, string logName, string streamPrefix = null)
        {
            var logGroupName   = logName;
            var AWS_ACCESS_KEY = awsAccessKey;
            var AWS_SECRET_KEY = awsSecretKey;

            Amazon.RegionEndpoint REGION = Amazon.RegionEndpoint.APSouth1;

            Serilog.Debugging.SelfLog.Enable(Console.WriteLine);
            CloudWatchSinkOptions options = new CloudWatchSinkOptions {
                LogGroupName = logGroupName, LogEventRenderer = new EventLogRenderer()
            };

            if (streamPrefix != null)
            {
                ILogStreamNameProvider streamNameProvider = new ConstantLogStreamNameProvider(streamPrefix);
                options = new CloudWatchSinkOptions {
                    LogGroupName = logGroupName, LogEventRenderer = new EventLogRenderer(), LogStreamNameProvider = streamNameProvider
                };
            }

            // setup AWS CloudWatch client
            AWSCredentials        credentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
            IAmazonCloudWatchLogs client      = new AmazonCloudWatchLogsClient(credentials, REGION);


            Log.Logger = new LoggerConfiguration().WriteTo.AmazonCloudWatch(options, client)
                         .MinimumLevel.Verbose()
                         .CreateLogger();
        }
Beispiel #6
0
        /// <summary> Create logger </summary>
        public static ILogger?TryCreateSerilogLogger()
        {
            try
            {
                var logStreamProvider = new DefaultLogStreamProvider();

                var serilogSinkConfig = new CloudWatchSinkOptions
                {
                    LogGroupName          = "Serilog",
                    MinimumLogEventLevel  = LogEventLevel.Information,
                    CreateLogGroup        = false,
                    TextFormatter         = new MessageTemplateTextFormatter("[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"),
                    LogStreamNameProvider = logStreamProvider,
                    RetryAttempts         = 5
                };
                var amazonCloudWatchLogger = new AmazonCloudWatchLogsClient();
                var logger = new LoggerConfiguration()
                             .MinimumLevel.Information()
                             .WriteTo.AmazonCloudWatch(serilogSinkConfig, amazonCloudWatchLogger)
                             .CreateLogger();

                logger.Information("Start");

                return(logger);
            }
            catch
            {
                return(null);
            }
        }
        public async Task SingleBatch()
        {
            // expect a single batch of events to be posted to CloudWatch Logs

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ReturnsAsync(new PutLogEventsResponse
            {
                HttpStatusCode    = System.Net.HttpStatusCode.OK,
                NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            Assert.Single(putLogEventsCalls);

            var request = putLogEventsCalls.First().Request;

            Assert.Equal(options.LogGroupName, request.LogGroupName);
            Assert.Null(request.SequenceToken);
            Assert.Equal(10, request.LogEvents.Count);
            for (var i = 0; i < events.Length; i++)
            {
                Assert.Equal(events[i].MessageTemplate.Text, request.LogEvents.ElementAt(i).Message);
            }

            client.VerifyAll();
        }
Beispiel #8
0
        public static void Init()
        {
            if (_enabled)
            {
                return;
            }

            var dir   = Env.GetEnvironmentString("COMPUTE_LOG_PATH", Path.Combine(Path.GetTempPath(), "Compute", "Logs"));
            var path  = Path.Combine(dir, "log-frontend-.txt"); // log-20180925.txt, etc.
            var limit = Env.GetEnvironmentInt("COMPUTE_LOG_RETAIN_DAYS", 10);

            var logger = new LoggerConfiguration()
//#if DEBUG
                         .MinimumLevel.Debug()
//#endif
                         .Enrich.FromLogContext()
                         .Enrich.WithProperty("Source", "frontend")
                         .WriteTo.Console(outputTemplate: "{Timestamp:o} {Level:w3}: {Source} {Message:lj} {Properties:j}{NewLine}{Exception}")
                         .WriteTo.File(new JsonFormatter(), path, rollingInterval: RollingInterval.Day, retainedFileCountLimit: limit);

            var cloudwatch_enabled = false;
            var aws_log_group      = Env.GetEnvironmentString("COMPUTE_LOG_CLOUDWATCH_GROUP", "/compute/dev");

            if (Env.GetEnvironmentBool("COMPUTE_LOG_CLOUDWATCH", false))
            {
                var options = new CloudWatchSinkOptions
                {
                    LogGroupName            = aws_log_group,
                    MinimumLogEventLevel    = LogEventLevel.Debug,
                    TextFormatter           = new JsonFormatter(),
                    LogGroupRetentionPolicy = LogGroupRetentionPolicy.SixMonths,
#if !DEBUG
                    Period = TimeSpan.FromSeconds(60)
#endif
                };

                var aws_region_string   = Env.GetEnvironmentString("AWS_REGION_ENDPOINT", "us-east-1");
                var aws_region_endpoint = Amazon.RegionEndpoint.GetBySystemName(aws_region_string);
                var aws_client          = new AmazonCloudWatchLogsClient(aws_region_endpoint);

                logger.WriteTo.AmazonCloudWatch(options, aws_client);

                cloudwatch_enabled = true;
            }

            Log.Logger = logger.CreateLogger();

            Log.Debug("Logging to {LogPath}", Path.GetDirectoryName(path));

            if (cloudwatch_enabled)
            {
                Log.ForContext("LogGroup", aws_log_group)
                .Debug("Amazon CloudWatch logging enabled");
            }

            _enabled = true;
        }
        public async Task LargeMessage()
        {
            // expect an event with a length beyond the MaxLogEventSize will be truncated to the MaxLogEventSize

            var client            = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options           = new CloudWatchSinkOptions();
            var sink              = new CloudWatchLogSink(client.Object, options);
            var largeEventMessage = CreateMessage(CloudWatchLogSink.MaxLogEventSize + 1);
            var events            = new LogEvent[]
            {
                new LogEvent(
                    DateTimeOffset.UtcNow,
                    LogEventLevel.Information,
                    null,
                    new MessageTemplateParser().Parse(largeEventMessage),
                    Enumerable.Empty <LogEventProperty>())
            };

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ReturnsAsync(new PutLogEventsResponse
            {
                HttpStatusCode    = System.Net.HttpStatusCode.OK,
                NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            Assert.Single(putLogEventsCalls);

            var request = putLogEventsCalls.First().Request;

            Assert.Equal(options.LogGroupName, request.LogGroupName);
            Assert.Null(request.SequenceToken);
            Assert.Single(request.LogEvents);
            Assert.Equal(largeEventMessage.Substring(0, CloudWatchLogSink.MaxLogEventSize), request.LogEvents.First().Message);

            client.VerifyAll();
        }
        public async Task ServiceUnavailable()
        {
            // expect retries until exhausted

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ThrowsAsync(new ServiceUnavailableException("unavailable"));

            await sink.EmitBatchAsync(events);

            Assert.Equal(options.RetryAttempts + 1, putLogEventsCalls.Count);

            TimeSpan lastInterval = TimeSpan.Zero;

            for (var i = 1; i < putLogEventsCalls.Count; i++)
            {
                // ensure retry attempts are throttled properly
                var interval = putLogEventsCalls[i].DateTime.Subtract(putLogEventsCalls[i - 1].DateTime);
                Assert.True(interval.TotalMilliseconds >= (CloudWatchLogSink.ErrorBackoffStartingInterval.Milliseconds * Math.Pow(2, i - 1)), $"{interval.TotalMilliseconds} >= {CloudWatchLogSink.ErrorBackoffStartingInterval.Milliseconds * Math.Pow(2, i - 1)}");
                lastInterval = interval;
            }

            client.VerifyAll();
        }
        public async Task DataAlreadyAccepted()
        {
            // expect update of sequence token and successful retry

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.DescribeLogStreamsAsync(It.IsAny <DescribeLogStreamsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogStreamsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK, NextToken = Guid.NewGuid().ToString()
            });

            List <CreateLogStreamRequest> createLogStreamRequests = new List <CreateLogStreamRequest>();

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .Callback <CreateLogStreamRequest, CancellationToken>((createLogStreamRequest, cancellationToken) => createLogStreamRequests.Add(createLogStreamRequest))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.SetupSequence(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new DataAlreadyAcceptedException("data already accepted"))
            .ReturnsAsync(new PutLogEventsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK, NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            client.Verify(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.DescribeLogStreamsAsync(It.Is <DescribeLogStreamsRequest>(req => req.LogGroupName == options.LogGroupName && req.LogStreamNamePrefix == createLogStreamRequests.First().LogStreamName), It.IsAny <CancellationToken>()), Times.Once);
            client.Verify(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()), Times.Once);

            client.VerifyAll();
        }
Beispiel #12
0
        private static ILogger GetLogger(IConfiguration configuration)
        {
            var options = new CloudWatchSinkOptions
            {
                TextFormatter = new CompactJsonFormatter()
            };

            return(new LoggerConfiguration()
                   .ReadFrom.Configuration(configuration)
                   .Enrich.FromLogContext()
                   .CreateLogger());
        }
        public async Task ResourceNotFound()
        {
            // expect failure, creation of log group/stream, and evenutal success

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            List <CreateLogStreamRequest> createLogStreamRequests = new List <CreateLogStreamRequest>();

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .Callback <CreateLogStreamRequest, CancellationToken>((createLogStreamRequest, cancellationToken) => createLogStreamRequests.Add(createLogStreamRequest))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.SetupSequence(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new ResourceNotFoundException("no resource"))
            .ReturnsAsync(new PutLogEventsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK, NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            client.Verify(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.CreateLogGroupAsync(It.Is <CreateLogGroupRequest>(req => req.LogGroupName == options.LogGroupName), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));

            Assert.Equal(createLogStreamRequests.ElementAt(0).LogStreamName, createLogStreamRequests.ElementAt(1).LogStreamName);

            client.VerifyAll();
        }
Beispiel #14
0
        //public Logger(TLoggerConfig cfg): this(cfg.Type,cfg.Name)
        //{
        //}
        public Logger(string type = "file", string name = "_")
        {
            if (type == "file")
            {
                _logger = new LoggerConfiguration()
                          .WriteTo.File(path: $"logs\\{name}")
                          .CreateLogger();
            }
            else if (type == "tcp")
            {
                _logger = new LoggerConfiguration()
                          .WriteTo.TcpSyslog("logs#.papertrailapp.com:####")
                          .CreateLogger();
            }
            else if (type == "aws")
            {
                var client = new AmazonCloudWatchLogsClient(Amazon.RegionEndpoint.EUCentral1);
                ICloudWatchSinkOptions awsConfig;

                {
                    // name of the log group
                    var logGroupName = $"/aws/{name}";


                    // options for the sink defaults in https://github.com/Cimpress-MCP/serilog-sinks-awscloudwatch/blob/master/src/Serilog.Sinks.AwsCloudWatch/CloudWatchSinkOptions.cs
                    awsConfig = new CloudWatchSinkOptions
                    {
                        // the name of the CloudWatch Log group for logging
                        LogGroupName = logGroupName,

                        //// the main formatter of the log event
                        TextFormatter = new CompactJsonFormatter(),

                        // other defaults defaults
                        MinimumLogEventLevel = LogEventLevel.Information,
                        BatchSizeLimit       = 100,
                        QueueSizeLimit       = 10000,
                        Period                = TimeSpan.FromSeconds(10),
                        CreateLogGroup        = true,
                        LogStreamNameProvider = new DefaultLogStreamProvider(),
                        RetryAttempts         = 5
                    };
                    //return options;
                }
                _logger = new LoggerConfiguration()
                          .WriteTo.AmazonCloudWatch(awsConfig, client)
                          .CreateLogger();
                //throw new NotImplementedException();
            }

            this.name = name;
        }
        /// <summary>
        /// The builder has configuration, logging and Amazon API Gateway already configured. The startup class
        /// needs to be configured in this method using the UseStartup() method.
        /// </summary>
        /// <param name="builder"></param>
        protected override void Init(IWebHostBuilder builder)
        {
            // name of the log group
            var logGroupName = $"FacwareBaseAPI/{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}";

            // customer formatter
            var formatter = new CustomTextFormatter();

            // options for the sink defaults in https://github.com/Cimpress-MCP/serilog-sinks-awscloudwatch/blob/master/src/Serilog.Sinks.AwsCloudWatch/CloudWatchSinkOptions.cs
            var options = new CloudWatchSinkOptions
            {
                // the name of the CloudWatch Log group for logging
                LogGroupName = logGroupName,

                // the main formatter of the log event
                TextFormatter = formatter,

                // other defaults defaults
                MinimumLogEventLevel = LogEventLevel.Information,
                BatchSizeLimit       = 100,
                QueueSizeLimit       = 10000,
                Period                = TimeSpan.FromSeconds(10),
                CreateLogGroup        = true,
                LogStreamNameProvider = new DefaultLogStreamProvider(),
                RetryAttempts         = 5
            };

            // setup AWS CloudWatch client
            var client = new AmazonCloudWatchLogsClient(RegionEndpoint.USEast1);

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Information()
                         .WriteTo.AmazonCloudWatch(options, client)
                         .CreateLogger();

            try
            {
                Log.Information("Staring up AWS Lambda");
                Log.Information($"Options: { JsonConvert.SerializeObject(options)}");
                builder
                .UseSerilog()
                .UseStartup <Startup>();
            }
            catch (System.Exception exception)
            {
                Log.Fatal(exception, "Application fails to start in AWS Lambda");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
        public async Task ResourceNotFound_CannotCreateResource()
        {
            // expect failure with failure to successfully create resources upon retries

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.SetupSequence(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            })
            .ThrowsAsync(new Exception("can't create a new log stream"));

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new ResourceNotFoundException("no resource"));

            await sink.EmitBatchAsync(events);

            client.Verify(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(1));
            client.Verify(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.CreateLogGroupAsync(It.Is <CreateLogGroupRequest>(req => req.LogGroupName == options.LogGroupName), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));

            client.VerifyAll();
        }
        public async Task InvalidParameter()
        {
            // expect batch dropped

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ThrowsAsync(new InvalidParameterException("invalid param"));

            await sink.EmitBatchAsync(events);

            Assert.Single(putLogEventsCalls);

            client.VerifyAll();
        }
Beispiel #18
0
        public static void Main(string[] args)
        {
            CloudWatchSinkOptions options = new CloudWatchSinkOptions {
                LogGroupName = "Kitsune-API2", MinimumLogEventLevel = LogEventLevel.Debug
            };                                                                                                                                         //, LogEventRenderer = MyCustomRenderer
            AWSCredentials        credentials = new BasicAWSCredentials("[[KIT_CLOUD_AWS_ACCESS_KEY]]", "[[KIT_CLOUD_AWS_SECRET_KEY]]");
            IAmazonCloudWatchLogs client      = new AmazonCloudWatchLogsClient(credentials, RegionEndpoint.APSouth1);

            string myIP = null;

            try
            {
                string hostName = Dns.GetHostName(); // Retrive the Name of HOST
                                                     // Get the IP
                myIP = Dns.GetHostEntry(hostName)?.AddressList?.Where(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.FirstOrDefault()?.ToString();
            }
            catch
            {
            }

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
                         .MinimumLevel.Override("System", LogEventLevel.Warning)
                         .Enrich.WithProperty("IP", myIP)
                         .WriteTo.AmazonCloudWatch(options, client)
                         .CreateLogger();

            try
            {
                Log.Information("Starting web host");
                BuildWebHost(args).Run();
                return;
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
                return;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
Beispiel #19
0
        public static CloudWatchSinkOptions GetCloudWatchSinkOptionsFromConfig(LoggingConfiguration loggingConfiguration)
        {
            var options = new CloudWatchSinkOptions
            {
                // the name of the CloudWatch Log group from config
                LogGroupName         = loggingConfiguration.LogGroup,
                TextFormatter        = loggingConfiguration.TextFormatter,
                MinimumLogEventLevel = loggingConfiguration.LogLevel,
                BatchSizeLimit       = loggingConfiguration.BatchSizeLimit,
                QueueSizeLimit       = loggingConfiguration.QueueSizeLimit,
                Period                  = loggingConfiguration.Period,
                CreateLogGroup          = loggingConfiguration.CreateLogGroup,
                LogStreamNameProvider   = loggingConfiguration.LogStreamNameProvider,
                RetryAttempts           = loggingConfiguration.RetryAttempts,
                LogGroupRetentionPolicy = loggingConfiguration.RetentionPolicy
            };

            return(options);
        }
        public async Task ServiceUnavailable_WithEventualSuccess()
        {
            // expect successful posting of batch after retry

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 10)
                          .Select(_ => // create 10 events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.SetupSequence(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new ServiceUnavailableException("unavailable"))
            .ReturnsAsync(new PutLogEventsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK, NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            client.Verify(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.VerifyAll();
        }
Beispiel #21
0
        private static void Main(string[] args)
        {
            var awsCredentials = new BasicAWSCredentials("AWS AccessKey", "AWD SecretKey");
            var region         = Amazon.RegionEndpoint.APSoutheast2;

            var outputTemplate = new AwsTextFormatter();
            var logStream      = new AwsLogStream();
            var logGroupName   = "AWSGroupName";

            // for debugging purposes, disable when it goes to production
            Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));

            var options = new CloudWatchSinkOptions()
            {
                LogGroupName         = logGroupName,
                TextFormatter        = outputTemplate,
                MinimumLogEventLevel = LogEventLevel.Verbose,
                BatchSizeLimit       = 1000,
                QueueSizeLimit       = 10000,
                Period                = TimeSpan.FromSeconds(5),
                CreateLogGroup        = true,
                LogStreamNameProvider = new DefaultLogStreamProvider(), // or you can use logStream variable defined if you need a custom name
                RetryAttempts         = 5
            };

            var client = new AmazonCloudWatchLogsClient(awsCredentials, region);

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .WriteTo.Console()
                         .WriteTo.AmazonCloudWatch(options, client)
                         .CreateLogger();

            Log.Information($"Hello, Info");
            Log.Warning($"Hello, Warn");
            Log.Debug($"Hello, Debug");
            Log.Error($"Hello, Error");
            Log.Fatal($"Hello, Fatal");

            Log.CloseAndFlush();

            Console.ReadKey();
        }
        public void Build()
        {
            string logGroupName = "GeoIPMicroserviceLogGroup/" +
                                  Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

            CloudWatchSinkOptions options = new CloudWatchSinkOptions
            {
                LogGroupName         = logGroupName,
                MinimumLogEventLevel = LogEventLevel.Information,
            };

            ConfigureCredentials();

            RegionEndpoint             awsRegion = RegionEndpoint.USEast2;
            AmazonCloudWatchLogsClient client    = new AmazonCloudWatchLogsClient(awsRegion);

            Log.Logger = new LoggerConfiguration()
                         .WriteTo.AmazonCloudWatch(options, client)
                         .CreateLogger();
        }
Beispiel #23
0
        protected void Application_Start(IHostingEnvironment env)
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);

            var logGroupName = "Logger/" + env.EnvironmentName;

            // customer renderer (optional, defaults to a simple rendered message of Serilog's LogEvent
            var renderer = new CustomRenderer();

            // options for the sink, specifying the log group name
            var options = new CloudWatchSinkOptions {
                LogGroupName = logGroupName, LogEventRenderer = renderer
            };

            // setup AWS CloudWatch client
            var credentials = new BasicAWSCredentials(myAwsAccessKey, myAwsSecretKey);
            var client      = new AmazonCloudWatchLogsClient(credentials, myAwsRegion);

            // Attach the sink to the logger configuration
            Log.Logger = new LoggerConfiguration().MinimumLevel.Information()
                         .WriteTo.AmazonCloudWatch(options, client)
                         .CreateLogger();
        }
Beispiel #24
0
        public static LoggerConfiguration AppendAwsCloudwatchLogger(this LoggerConfiguration logger, string logGroupName, LogEventLevel minimumLogEvent, string accessKey, string securityKey)
        {
            // customer formatter
            var formatter = new CompactJsonFormatter();

            // options for the sink defaults in https://github.com/Cimpress-MCP/serilog-sinks-awscloudwatch/blob/master/src/Serilog.Sinks.AwsCloudWatch/CloudWatchSinkOptions.cs
            var options = new CloudWatchSinkOptions
            {
                LogGroupName          = logGroupName,
                TextFormatter         = formatter,
                MinimumLogEventLevel  = minimumLogEvent,
                LogStreamNameProvider = new DefaultLogStreamProvider(),
                RetryAttempts         = 5
            };

            var credentials = new BasicAWSCredentials(accessKey, securityKey);

            // setup AWS CloudWatch client
            var client = new AmazonCloudWatchLogsClient(credentials, RegionEndpoint.EUWest1);

            return(logger
                   .WriteTo.AmazonCloudWatch(options, client));
        }
        public static void ConfigureLogs(this IServiceCollection services, IConfiguration config)
        {
            //loggerConfiguration
            //    .MinimumLevel.Information()
            //    .Enrich.FromLogContext()
            //    .WriteTo.Console();

            if (!string.IsNullOrWhiteSpace(config.GetSection("AWS")["CloudWatchDev"]))
            {
                var options = new CloudWatchSinkOptions
                {
                    LogGroupName         = config.GetSection("AWS")["CloudWatchDev"],
                    CreateLogGroup       = true,
                    MinimumLogEventLevel = LogEventLevel.Information,
                    TextFormatter        = new CompactJsonFormatter(),
                    BatchSizeLimit       = 100,
                    QueueSizeLimit       = 10000,
                    Period = TimeSpan.FromSeconds(10),
                    LogStreamNameProvider = new DefaultLogStreamProvider(),
                    RetryAttempts         = 5
                };
                //var awsOptions = config.GetAWSOptions();

                var accessKey        = config["AWS:AccessKey"];
                var secretKey        = config["AWS:SecretKey"];
                var cloudWatchClient = new AmazonCloudWatchLogsClient(accessKey, secretKey, RegionEndpoint.EUWest1);

                //var cloudWatchClient = awsOptions.CreateServiceClient<IAmazonCloudWatchLogs>();

                Log.Logger = new LoggerConfiguration()
                             .MinimumLevel.Error()
                             .Enrich.FromLogContext()
                             .WriteTo.Console()
                             .WriteTo.AmazonCloudWatch(options, cloudWatchClient)
                             .CreateLogger();
            }
        }
        public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env,
            ILoggerFactory loggerFactory,
            IApplicationLifetime appLifetime,
            IServiceProvider serviceProvider)
        {
            var loggerConfiguration = new LoggerConfiguration().Enrich.FromLogContext();

            if (env.IsDevelopment())
            {
                loggerConfiguration
                .MinimumLevel.Debug()
                .WriteTo.ColoredConsole();
            }
            else
            {
                loggerConfiguration.MinimumLevel.Is(LogEventLevel.Verbose);

                var logGroupName = Configuration["aws:cloudwatch:logGroupName"] + "/" + env.EnvironmentName;

                AWSCredentials credentials =
                    new BasicAWSCredentials(Configuration["aws:accessKey"], Configuration["aws:secret"]);
                IAmazonCloudWatchLogs client = new AmazonCloudWatchLogsClient(credentials, RegionEndpoint.EUCentral1);
                var options = new CloudWatchSinkOptions
                {
                    LogGroupName          = logGroupName,
                    LogEventRenderer      = new JsonLogEventRenderer(),
                    MinimumLogEventLevel  = (LogEventLevel)Convert.ToInt32(Configuration["logLevel"]),
                    LogStreamNameProvider = new ConstantLogStreamNameProvider(Environment.MachineName)
                };

                loggerConfiguration.WriteTo.AmazonCloudWatch(options, client);
            }

            var cgc = serviceProvider.GetService <CollectionGameConfiguration>();

            loggerConfiguration
            .WriteTo
            .Logger(lc =>
                    lc.Filter
                    .ByIncludingOnly(a =>
                                     a.Properties.ContainsKey("SourceContext") &&
                                     a.Properties["SourceContext"].ToString() == $@"""{typeof(CollectingGameService)}""")
                    .WriteTo.File(cgc.LogFile, (LogEventLevel)cgc.LogLevel)
                    );

            Log.Logger = loggerConfiguration.CreateLogger();
            loggerFactory
            .WithFilter(new FilterLoggerSettings
            {
                { "Microsoft", env.IsDevelopment() ? LogLevel.Information : LogLevel.Warning },
                { "System", env.IsDevelopment() ? LogLevel.Information : LogLevel.Warning }
            })
            .AddSerilog();

            _logger = loggerFactory.CreateLogger(GetType());
            _logger.LogInformation($"Logging commences");


            appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);

            app.UseCors("CorsPolicy");

            app.UseJwtBearerAuthentication(new JwtBearerOptions
            {
                TokenValidationParameters = new TokenValidationParameters
                {
                    IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.ASCII.GetBytes(Configuration["oAuth:secretKey"])),
                    ValidAudience    = Configuration["oAuth:Audience"],
                    ValidIssuer      = Configuration["oAuth:Issuer"],
                    ValidateLifetime = true,
                    ClockSkew        = TimeSpan.FromSeconds(0)
                },
                AutomaticAuthenticate = true,
                AutomaticChallenge    = true
            });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    "default",
                    "{controller=Test}/{action=Index}/{id?}");
            });

            app.UseSwagger();

            app.UseSwaggerUI(c =>
            {
                c.RoutePrefix = "swagger/v2/ui";
                c.DocExpansion("none");
                c.SwaggerEndpoint("/swagger/v2/swagger.json", "API v2");
            });

            if (env.IsProduction())
            {
                _logger.LogDebug("Starting JobManager to run jobs");
                JobManager.JobFactory = new ServiceProviderJobFactory(serviceProvider);
                JobManager.Initialize(new JobRegistry(Configuration.GetSection("jobs")));
            }

            _logger.LogInformation($"Startup complete ({env.EnvironmentName})");
        }
        // ReSharper disable once UnusedMember.Global
        public static LoggerConfiguration CloudWatch
        (
            this LoggerSinkConfiguration sinkConfiguration,
            string logGroupName,
            string regionEndpointSystemName,
            bool createLogGroup = true,
            LogEventLevel restrictedToMinimumLevel = LogEventLevel.Information,
            int batchSizeLimit = 100,
            int queueSizeLimit = 10000,
            byte retryAttempts = 5,
            TimeSpan?period    = null,
            string logStreamNameProviderFqn = null,
            string textFormatterFqn         = null
        )
        {
            ILogStreamNameProvider GetLogStreamNameProvider()
            {
                if (string.IsNullOrEmpty(logStreamNameProviderFqn))
                {
                    return(new DefaultLogStreamProvider());
                }

                var logStreamNameProviderType = Type.GetType(logStreamNameProviderFqn);

                return
                    ((ILogStreamNameProvider)
                     Activator
                     .CreateInstance(logStreamNameProviderType ?? throw new ArgumentNullException(nameof(logStreamNameProviderType))));
            }

            ITextFormatter GetTextFormatter()
            {
                if (string.IsNullOrEmpty(textFormatterFqn))
                {
                    return(new JsonFormatter());
                }

                var textFormatterType = Type.GetType(textFormatterFqn);

                return
                    ((ITextFormatter)
                     Activator
                     .CreateInstance(textFormatterType ?? throw new ArgumentNullException(nameof(textFormatterType))));
            }

            var options = new CloudWatchSinkOptions
            {
                LogGroupName         = logGroupName,
                TextFormatter        = GetTextFormatter(),
                MinimumLogEventLevel = restrictedToMinimumLevel,
                BatchSizeLimit       = batchSizeLimit,
                QueueSizeLimit       = queueSizeLimit,
                Period                = period ?? CloudWatchSinkOptions.DefaultPeriod,
                CreateLogGroup        = createLogGroup,
                LogStreamNameProvider = GetLogStreamNameProvider(),
                RetryAttempts         = retryAttempts
            };

            var endPoint = RegionEndpoint.GetBySystemName(regionEndpointSystemName);
            var client   = CloudWatchLogsClientExtensions.ClientFactory.Invoke(endPoint);

            return
                (sinkConfiguration
                 .Sink
                 (
                     new CloudWatchLogSink(client, options),
                     options.MinimumLogEventLevel
                 ));
        }
        public async Task InvalidSequenceToken_CannotUpdateSequenceToken()
        {
            // expect update of sequence token and success on a new log stream

            var logStreamNameProvider = new Mock <ILogStreamNameProvider>();

            logStreamNameProvider.SetupSequence(mock => mock.GetLogStreamName())
            .Returns("a")
            .Returns("b");

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions {
                LogStreamNameProvider = logStreamNameProvider.Object
            };
            var sink   = new CloudWatchLogSink(client.Object, options);
            var events = Enumerable.Range(0, 10)
                         .Select(_ => // create 10 events with message length of 12
                                 new LogEvent(
                                     DateTimeOffset.UtcNow,
                                     LogEventLevel.Information,
                                     null,
                                     new MessageTemplateParser().Parse(CreateMessage(12)),
                                     Enumerable.Empty <LogEventProperty>()))
                         .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.DescribeLogStreamsAsync(It.IsAny <DescribeLogStreamsRequest>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new Exception("no describe log stream"));

            List <CreateLogStreamRequest> createLogStreamRequests = new List <CreateLogStreamRequest>();

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .Callback <CreateLogStreamRequest, CancellationToken>((createLogStreamRequest, cancellationToken) => createLogStreamRequests.Add(createLogStreamRequest))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.PutLogEventsAsync(It.Is <PutLogEventsRequest>(req => req.LogStreamName == "a"), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new InvalidSequenceTokenException("invalid sequence"));

            client.Setup(mock => mock.PutLogEventsAsync(It.Is <PutLogEventsRequest>(req => req.LogStreamName == "b"), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new PutLogEventsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK, NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            client.Verify(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
            client.Verify(mock => mock.DescribeLogStreamsAsync(It.Is <DescribeLogStreamsRequest>(req => req.LogGroupName == options.LogGroupName && req.LogStreamNamePrefix == createLogStreamRequests.First().LogStreamName), It.IsAny <CancellationToken>()), Times.Once);
            client.Verify(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()), Times.Exactly(2));

            Assert.Equal(2, createLogStreamRequests.Count);
            Assert.NotEqual(createLogStreamRequests.ElementAt(0).LogStreamName, createLogStreamRequests.ElementAt(1).LogStreamName);

            client.VerifyAll();
        }
        public async Task MultipleDays()
        {
            // expect a batch to be posted for each 24-hour period

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 20)
                          .Select(i =>                                                                // create multipe events with message length of 12
                                  new LogEvent(
                                      DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays((i % 2) * 2)), // split the events into two days
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(12)),
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ReturnsAsync(new PutLogEventsResponse
            {
                HttpStatusCode    = System.Net.HttpStatusCode.OK,
                NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            Assert.Equal(2, putLogEventsCalls.Count);

            for (var i = 0; i < putLogEventsCalls.Count; i++)
            {
                var call    = putLogEventsCalls[i];
                var request = call.Request;

                Assert.Equal(options.LogGroupName, request.LogGroupName);
                Assert.Equal(events.Length / putLogEventsCalls.Count, request.LogEvents.Count);

                // make sure the events are ordered
                for (var index = 1; index < call.Request.LogEvents.Count; index++)
                {
                    Assert.True(call.Request.LogEvents.ElementAt(index).Timestamp >= call.Request.LogEvents.ElementAt(index - 1).Timestamp);
                }

                if (i == 0) // first call
                {
                    Assert.Null(request.SequenceToken);
                }
                else
                {
                    Assert.NotNull(request.SequenceToken);
                }
            }

            client.VerifyAll();
        }
        public async Task MoreThanMaxBatchSize()
        {
            // expect multiple batches, all having a batch size less than the maximum

            var client  = new Mock <IAmazonCloudWatchLogs>(MockBehavior.Strict);
            var options = new CloudWatchSinkOptions();
            var sink    = new CloudWatchLogSink(client.Object, options);
            var events  = Enumerable.Range(0, 256) // 256 4 KB messages matches our max batch size, but we want to test a "less nice" scenario, so we'll create 256 5 KB messages
                          .Select(i =>
                                  new LogEvent(
                                      DateTimeOffset.UtcNow,
                                      LogEventLevel.Information,
                                      null,
                                      new MessageTemplateParser().Parse(CreateMessage(1024 * 5)), // 5 KB messages
                                      Enumerable.Empty <LogEventProperty>()))
                          .ToArray();

            client.Setup(mock => mock.DescribeLogGroupsAsync(It.IsAny <DescribeLogGroupsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeLogGroupsResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogGroupAsync(It.IsAny <CreateLogGroupRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogGroupResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            client.Setup(mock => mock.CreateLogStreamAsync(It.IsAny <CreateLogStreamRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new CreateLogStreamResponse {
                HttpStatusCode = System.Net.HttpStatusCode.OK
            });

            var putLogEventsCalls = new List <RequestCall <PutLogEventsRequest> >();

            client.Setup(mock => mock.PutLogEventsAsync(It.IsAny <PutLogEventsRequest>(), It.IsAny <CancellationToken>()))
            .Callback <PutLogEventsRequest, CancellationToken>((putLogEventsRequest, cancellationToken) => putLogEventsCalls.Add(new RequestCall <PutLogEventsRequest>(putLogEventsRequest)))   // keep track of the requests made
            .ReturnsAsync(new PutLogEventsResponse
            {
                HttpStatusCode    = System.Net.HttpStatusCode.OK,
                NextSequenceToken = Guid.NewGuid().ToString()
            });

            await sink.EmitBatchAsync(events);

            Assert.Equal(2, putLogEventsCalls.Count);

            for (var i = 0; i < putLogEventsCalls.Count; i++)
            {
                var call    = putLogEventsCalls[i];
                var request = call.Request;

                Assert.Equal(options.LogGroupName, request.LogGroupName);

                if (i == 0) // first call
                {
                    Assert.Null(request.SequenceToken);
                    Assert.Equal(203, request.LogEvents.Count); // expect 203 of the 256 messages in the first batch
                }
                else
                {
                    Assert.NotNull(request.SequenceToken);
                    Assert.Equal(53, request.LogEvents.Count); // expect 53 of the 256 messages in the second batch
                }
            }

            client.VerifyAll();
        }