I'm using AWS Cloudwatch for my application logging. I recently learned that I could use structured logging to make my logs more searchable. I did a little research and decided to go with Serilog for my logging tool.
One difficulty I'm having is, although I'm seeing the structured logging message in Cloudwatch, it's not showing a fully formatted log message.
For example, when I send this to the logs:
_logger.LogError("Hello {person}, {question} are you {time}?", "Dave", "how", "today");
I see this message in the Cloudwatch logs output
Hello {person}, {question} are you {time}?
But I don't see the fully substituted version of the string anywhere i.e.
Hello Dave how are you today?
I followed this walkthrough on setting up Serilog for structured logging in AWS https://martinjt.me/2020/02/16/serilog-and-cloudwatch-with-inbuilt-credentials/ and ended up with this code.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.UseSerilog(SetupAWSLogging);
});
public class LoggingSettings
{
public string LogGroup { get; set; }
}
public static void SetupAWSLogging(WebHostBuilderContext hostingContext, LoggerConfiguration loggerConfiguration)
{
var config = hostingContext.Configuration;
var settings = config.GetSection("Logging").Get<LoggingSettings>();
loggerConfiguration
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
if (!string.IsNullOrEmpty(settings.LogGroup))
{
var options = new CloudWatchSinkOptions
{
LogGroupName = settings.LogGroup,
CreateLogGroup = true,
MinimumLogEventLevel = LogEventLevel.Information,
TextFormatter = new JsonFormatter()
};
var awsOptions = config.GetAWSOptions();
var cloudwatchClient = awsOptions.CreateServiceClient<IAmazonCloudWatchLogs>();
loggerConfiguration
.WriteTo.AmazonCloudWatch(options, cloudwatchClient);
}
}
Here's the full entry found in Cloudwatch
{
"Timestamp": "2021-07-05T09:08:32.5118371-06:00",
"Level": "Error",
"MessageTemplate": "Hello {person}, {question} are you {time}?",
"Properties": {
"person": "Dave",
"question": "how",
"time": "today",
"SourceContext": "Testing",
"ActionId": "54758041-ee5f-4297-a7b3-adaa5e675901",
"ActionName": "Testing.Ping (TestController)",
"RequestId": "80000007-0005-ff00-b63f-84710c7967bb",
"RequestPath": "/Testing/Ping"
}
}
All the information we need to construct the message ourselves is there, but the log is not as readable as if I could see the substituted string as well. Is there something I'm missing or doing wrong? Maybe it's just a configuration in Cloudwatch to show the string with substitutions? It would be better if it were done there I guess to cut down on the log sizes.
Appreciate the help all.
Simplest fix is:
TextFormatter = new JsonFormatter(renderMessage: true)
Note true
to render the message.