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); }
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); }
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)); }
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()); }
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(); }
/// <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(); }
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(); }
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(); }
//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(); }
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(); } }
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(); }
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(); }
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(); }
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(); }