Multiline strings in CloudWatch

Viewed 39

I have the following NLog setup:

// Custom serializer for exceptions
LogManager.Setup().SetupSerialization(s =>
   s.RegisterObjectTransformation<Exception>(ex => new {
       Data = ex.ToBetterString()
   })
);

// In the layout I configure the exception like this:
jsonLayout.Attributes.Add(new JsonAttribute("exception", "${exception:format=@}"));

So this gets my exception and parses the exception text in a more beautiful way, then put it in an anonymous object in a Data property. So this property is a multiline string.

When the log arrives at CloudWatch, I get the following result:

enter image description here

As you can see in the image, there are two problems:

  1. the property is being recognized as a string instead of an object
  2. the \r\n characters are not being parsed as newline characters

Is there any way to properly see this in CloudWatch?

---------------- UPDATE -----------------

As pointed by @Stefan adding encode = false helped a little bit. Now the exception property is recognized as json, just the multiline string is not being rendered properly:

enter image description here

3 Answers

Just for future reference, for someone that might have the same issue, this was my solution:

I updated the custom serializer to this:

LogManager.Setup().SetupSerialization(s =>
    s.RegisterObjectTransformation<Exception>(ex => new ExceptionData(ex))
);

And the ExceptionData class:

public class ExceptionData
{
    public ExceptionData(Exception exception)
    {
        Message = exception.Message;
        HResult = exception.HResult;
        Source = exception.Source;
        StackTrace = exception.StackTrace.Replace("\r", "").Split('\n');

        foreach (var item in exception.Data)
        {
            if (Data == null)
            {
                Data = new Dictionary<string, object>();
            }
            var dictionaryEntry = (DictionaryEntry)item;
            Data.Add(dictionaryEntry.Key.ToString(), dictionaryEntry.Value);
        }

        if (exception.InnerException != null)
        {
            InnerException = new ExceptionData(exception.InnerException);
        }
    }

    public string Message { get; set; }
    public long HResult { get; set; }
    public string Source { get; set; }
    public string[] StackTrace { get; set; }
    public ExceptionData InnerException { get; set; }
    public Dictionary<string, object> Data { get; set; }
}

It seems CloudWatch doesn't support displaying strings in multiple lines, so for the stacktrace I opted to use an array of strings. Now the logs looks like this:

enter image description here

The issue is that your exception is added as a string to the JSON string - effectively resulting in JSON in JSON.

Either add all the seperate objects as seperate attributes or check NLog documentation for more options.

Here's also a post which could help you: NLog: logging an object serialized to JSON

When you know that the output is already valid JSON, then you must tell the JsonLayout attribute to not encode:

jsonLayout.Attributes.Add(new JsonAttribute("exception", "${exception:format=@}", encode: false));

To remove the newlines then you can apply this transformation:

jsonLayout.Attributes.Add(new JsonAttribute("exception", "${replace-newlines:${exception:format=@}}", encode: false));

But be careful, as some exceptions can be dangerous (Like EF-Core Exceptions that will output the entire database). So it is probably best to rely on RegisterObjectTransformation.

See also: https://github.com/NLog/NLog/wiki/JsonLayout

Related