0
votes

I have a C# .NET Core Azure Function App, and I am using the ILogger to send logs to Application Insights. This is working well so far.

Function header:

public static void Run([TimerTrigger("0 30 * * * *")] TimerInfo myTimer, ILogger log, ExecutionContext context)

ILogger usage:

log.LogInformation($"MyFunction trigger function executed at: {DateTime.Now}");

In App Insights, I see the log which has default information like which Function App it came from, as well as the message which contains the above string.

However, now I want to log a custom log. I have an IEnumerable<IDictionary<string, string>> and I want each dictionary element of the list to be a separate log. Ideally, I could have a log with each field being a key from the dictionary, and its value to be the corresponding value. Alternatively, I would be fine with some sort of customDimensions field in the log, which would be an object containing all the key-value pairs from 1 dictionary in the list.

The intent is to make the logs simple to query in Kusto. I want to avoid having to parse them when querying them in App Insights.

Notes:

  • since I already use the ILogger for existing logging, is there a way to do the above object-logging with the ILogger interface?
  • if not, how can I log an object like mentioned above with a different logger?

I looked at numerous other similar posts, but none of them seemed to be fully answered.

1
Create a logger scope (log.BeginScope()) and pass it your dictionary. Alternatively add your dictionary to Activity.Current's Baggage/Tags. App insights will add custom dimensions for either scenario. For Activity, if one doesn't exist then start a new one. Everything else is automagic - pinkfloydx33

1 Answers

1
votes

Here is a pattern I have used previously:

public class LogService : ILogService
{
    private readonly ILogger<LogService> _log;
    
    private readonly Dictionary<string, object> _customProperties = new Dictionary<string, object>();

    public LogService(ILogger<LogService> log)
    {
        _log = log;
    }
    
    public void SetCustomProperty(string key, object value)
    {
        _customProperties.Add(key, value);
    }

    public void LogInformation(string message, params object[] args)
    {
        Log(LogLevel.Information, message, args);
    }

    public void LogWarning(string message, params object[] args)
    {
        Log(LogLevel.Warning, message, args);
    }
    
    ...etc 

    private void Log(LogLevel logLevel, string message, params object[] args)
    {
        using (_log.BeginScope(_customProperties))
        {
            _log.Log(logLevel, message, args);
        }
    }
}

The important bit is the last method Log(LogLevel logLevel, string message, params object[] args). It wraps the _log.Log() in a using and uses the _log.BeginScope() to add the custom properties to the log message which should be visible in the Application Insights "Custom Properties" section.