Search code examples
asp.net-coreamazon-cloudwatchserilog-aspnetcore

aws-logging-dotnet retrieve the AWS Logger LogStreamName value at runtime


I am using the aws-logging-dotnet library to write the application logs to AWS Cloudwatch.

The logger is configured via a json file:

{
  "Serilog": {
    "Using": [ "AWS.Logger.SeriLog", "Serilog.Exceptions" ],

    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Hangfire": "Warning",
        "Microsoft.AspNetCore": "Warning",
        "Serilog.AspNetCore": "Warning",
        "System": "Warning"
      }
    },
    "Enrich": [ "WithMachineName", "WithProcessId", "WithProcessName", "FromLogContext", "WithExceptionDetails" ],
    "Properties": {
      "Application": "My Application Name"
    },
    "Region": "My AWS Region", 
    "LogGroup": "My AWS LogGroup", 
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{SourceContext}] [{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      }
    ],
    "WriteTo:Async": {
      "Name": "Async",
      "Args": {
        "configure": [
          {
            "Name": "AWSSeriLog",
            "Args": {
              "textFormatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
            }
          }
        ]
      }
    }
  }
}

As soon as the app starts logging in AWS CW, it creates a dedicated stream, like this:

enter image description here

I am interested in getting the runtime value of the LogStreamName. The application is running on many nodes, hence each instance logs into its own stream.

I can see that the LogStreamName name is managed internally by the logger. However it seems there is no way to get that value.

https://github.com/aws/aws-logging-dotnet/blob/d59d7c855d5bccc4fd60d3435893152dfbf11b17/src/AWS.Logger.Core/Core/AWSLoggerCore.cs#L605C26-L605C40

public PutLogEventsRequest _request = new PutLogEventsRequest();
            public LogEventBatch(string logGroupName, string streamName, int timeIntervalBetweenPushes, int maxBatchSize)
            {
                _request.LogGroupName = logGroupName;
                _request.LogStreamName = streamName;
                TimeIntervalBetweenPushes = TimeSpan.FromSeconds(timeIntervalBetweenPushes);
                MaxBatchSize = maxBatchSize;
                Reset(null);
            }

Before I invent hacky solutions, does anyone know if there is a clean way to read it?


Solution

  • The short answer is no. The log stream name is managed internally by the AWSLoggerCore class. The logger API doesn't provide any public accessor to read or override it.

    However there is an open request for it: https://github.com/aws/aws-logging-dotnet/issues/195

    You may consider opting for this alternative library: serilog-sinks-awscloudwatch https://github.com/Cimpress-MCP/serilog-sinks-awscloudwatch

    This gives you the possibility to set the Log Stream Name you prefer by implementing your own LogStreamNameProvider:

    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 MyLogStreamProvider(),
        RetryAttempts = 5
      };
    
    ...
    
        public class MyLogStreamProvider : ILogStreamNameProvider
        {
            private readonly string DATETIME_FORMAT = "yyyy-MM-dd-hh-mm-ss";
    
            // Customise your log stream name
            public string GetLogStreamName()
            {
                return $"{DateTime.UtcNow.ToString(DATETIME_FORMAT)}_{Dns.GetHostName()}_{Guid.NewGuid()}";
            }
        }