0

Does anyone know how to change the behavior/format of the structured logging in .NET Core C# to be camel case (ex: camelCase)? I'm trying to leverage structured logging like as follows:

Logger.LogInformation("Some text here. My object: {@some_class}", someClass);

Let's say some class looks like as follows:

class SomeClass {
  [JsonProperty(PropertyName = "intField")] // this does NOT work for structured logging
  int IntField {get;set;}
  string StrField {get;set;}
}

For the sake of brevity, I'll receive some output like follows:

{
  ...
  "message": "Some text here. My object: {\"IntField\":5,\"StrField\":\"I'm here\"}",
  "some_class": {
    "IntField":5,
    "StrField":"I'm here"
  },
  ...
}

But what I want is for all the fields to be camel case like all the parent fields in the log are. The following is the desired outcome:

{
  ...
  "message": "Some text here. My object: {\"IntField\":5,\"StrField\":\"I'm here\"}",
  "some_class": {
    "intField":5,
    "strField":"I'm here"
  },
  ...
}

I've tried setting up my JsonConvert.DefaultSettings with a new JsonSerializerSettings object to force camel casing, but I'm assuming this only works if I'm actually serializing to string (got this from StackOverflow question). To which I'm guessing the logger does not use under the hood.

If it helps I'm using I am using .NET Core 2.2 and v4.8.1.

JVIH
  • 103
  • 1
  • 1
  • 8
  • 2
    You can change to JSON.NET: https://github.com/NLog/NLog/wiki/How-to-use-structured-logging#i-like-to-use-jsonnet-for-creating-json and configure the JSON.NET serializer-settings to be camel-case. – Rolf Kristensen Dec 11 '19 at 06:17
  • Awesome, this worked, but luckily I caught an adverse side effect. In another part of code, I was using a lazy logger to log a LogEventInfo with properties that was logging an exception which created an infinite loop in the logger (well long enough where I had to kill it). Now I have to, ToString() my exception. I didn't see an easy way to address this through the serializer settings. – JVIH Dec 11 '19 at 20:15
  • Should be handled with JSON.NET `ReferenceLoopHandling = ReferenceLoopHandling.Ignore`. You can also register special types to be ignored by JSON.NET if logging Entity-Framework-Exceptions – Rolf Kristensen Dec 11 '19 at 20:29
  • Hmmm, I have that. Maybe its not a reference loop, but the exception is just super deep in its property tree looking like this --> exception.targetSite.module.assembly.customAttributes[].constructor.module.assembly... Also, thank you for your help. – JVIH Dec 11 '19 at 22:42
  • Exception.TargetSite should be excluded with Json.Net 12.0.3. See also https://github.com/JamesNK/Newtonsoft.Json/pull/1897 – Rolf Kristensen Dec 11 '19 at 22:51

1 Answers1

1

1) Create your custom serializer with CamelCaseNamingStrategy as NamingStrategy config.

    internal class JsonNetSerializer : NLog.IJsonConverter
    {
        private readonly DefaultContractResolver contractResolver;

        public JsonNetSerializer()
        {
            contractResolver = new DefaultContractResolver
            {
                // KEY CONFIG !!!
                NamingStrategy = new CamelCaseNamingStrategy()
            };
        }

        /// <summary>Serialization of an object into JSON format.</summary>
        /// <param name="value">The object to serialize to JSON.</param>
        /// <param name="builder">Output destination.</param>
        /// <returns>Serialize succeeded (true/false)</returns>
        public bool SerializeObject(object value, StringBuilder builder)
        {
            try
            {
                string json = JsonConvert.SerializeObject(value, new JsonSerializerSettings
                {
                    ContractResolver = contractResolver
                });

                builder.Append(json);
            }
            catch (Exception e)
            {
                NLog.Common.InternalLogger.Error(e, "Error when custom JSON serialization");
                return false;
            }
            return true;
        }
    }
}

2) Change default for the new custom

var customConverter = new JsonNetSerializer();
ConfigurationItemFactory.Default.JsonConverter = customConverter;

Use it, send your Json to NLog log.Info("Metadata: {@source}", metadata);

Market
  • 450
  • 6
  • 17