Skip to content

Logging with .NET Standard 2.0

jbe2277 edited this page Mar 12, 2021 · 6 revisions

Introduction

Logging in re-usable .NET Standard 2.0 libraries

TraceSource

This chapter contains some guidelines how the TraceSource might be used for logging.

using System.Diagnostics;

namespace SampleLibrary.Logging
{
    public static class Log
    {
        public static TraceSource Default { get; } = new TraceSource("SampleLibrary");
    }
}
  • Create a public static Log class per assembly.
    • It must be public so that an application can configure the TraceSource. The configuration includes defining Listeners (e.g. File, Console) and the minimum log level (Switch).
    • .NET Framework apps can use App.config files to configure TraceSources. .NET Core does not support this approach anymore.
  • Provide a Default TraceSource instance.
    • Optional: Add more static instances if more selective log configuration is needed.
  • Use a separate namespace xx.Logging for the Log class because multiple Log classes might exist.
    • Note: The application need to use this namespace just once for configuration.
internal static class TraceSourceExtensions
{
    public static bool IsInfoEnabled(this TraceSource traceSource)
    {
        return traceSource.Switch.ShouldTrace(TraceEventType.Information);
    }

    public static void Info(this TraceSource traceSource, [Localizable(false)] string message)
    {
        if (IsInfoEnabled(traceSource)) traceSource.TraceEvent(TraceEventType.Information, 0, message);
    }

    public static void Info(this TraceSource traceSource, [Localizable(false)] string format, params object[] arguments)
    {
        if (IsInfoEnabled(traceSource)) traceSource.TraceEvent(TraceEventType.Information, 0, format, arguments);
    }
...
  • Consider including the TraceSourceExtensions class. It provides a more compact API for logging.
    • Copy the source file to your project (keep it as an internal class).
    • If your library references System.Waf.Core then you could use the implementation from this library.

Integration with 3rd party logger

  • Most 3rd party logging frameworks provide TraceSource Listeners for integration.
  • Sample for NLog: https://github.com/jbe2277/LoggingSample
    • NLogConfigSample: Use NLog via NLog.config file and listens to TraceSource logging.
    • NLogCodeSample: Use NLog via code configuration and listens to TraceSource logging.
    • Integration is done with the NLogHelper class.
internal static class NLogHelper
{
    public static SourceLevels ToSourceLevels(this LogLevel level)
    {
        if (level == LogLevel.Trace) return SourceLevels.Verbose;
        if (level == LogLevel.Debug) return SourceLevels.Verbose;
        if (level == LogLevel.Info) return SourceLevels.Information;
        if (level == LogLevel.Warn) return SourceLevels.Warning;
        if (level == LogLevel.Error) return SourceLevels.Error;
        if (level == LogLevel.Fatal) return SourceLevels.Critical;
        return SourceLevels.Off;
    }

    public static void ConfigureTraceSource(TraceSource traceSource)
    {
        traceSource.Listeners.Clear();
        traceSource.Listeners.Add(new NLogTraceListener());
        var rule = LogManager.Configuration.LoggingRules
            .FirstOrDefault(x => x.LoggerNamePattern == traceSource.Name) 
                ?? throw new NotSupportedException(traceSource.Name);
        // Levels.First -> minLevel (ordered list)
        traceSource.Switch.Level = rule.Levels.Any() ? rule.Levels[0].ToSourceLevels() : SourceLevels.Off;
    }
}