.NET logging framework
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

README.md

LogMagic NuGet

logmagic icon

Why LogMagic

Like many other libraries for .NET, LogMagic provides diagnostic logging into files, the console, and elsewhere. It's probably the easiest framework to setup, has a clean API, extremely extensible.

LogMagic also supports a relatively new paradigm of structured logging.

Index

Installation

Installing from NuGet

The core logging package is LogMagic. Supported frameworks are:

  • .NET 4.5
  • .NET Standard 1.6. By supporting .NET Standard we ensure that LogMagic works on .NET Core, Android, iOS or anything else.

Note to ASP.NET Core users: LogMagic does not integrate with ASP.NET Core logging system, it's a separate logging framework you can use in conjunction with or instead of it. Both system have their pros and cons.

PM> Install-Package LogMagic

Setup

Types are in LogMagic namespace

using LogMagic;

An ILog instance is the one used to log events and can be created in one of three ways by calling to global static L class.

Create using current class type name

ILog _log = L.G();

Or by specifying type explicitly

ILog _log = L.G<T>;			//using generics
ILog _log = L.G(typeof(T));	//passing type

Or by specifying name explicitly

ILog _log = L.G("instance name");

By default LogMagic doesn't write events anywhere and you need to configure it:

L.Config.WriteTo.Console();

This is typically done once at application startup.

Example application

The complete example below shows logging in a simple console application, with events sent to the console as well as to file on disk.

  1. Create a new Console Application project
  2. Install the core LogMagic package

In Visual Studio, open Package Manager Console and type:

Install-Package LogMagic
  1. Add the following code to Program.cs
using System;
using LogMagic;

namespace LogMagicExample
{
   public class Program
   {
      private readonly ILog _log = L.G();

      public static void Main(string[] args)
      {
         L.Config
            .WriteTo.Console()
            .EnrichWith.ThreadId();

         new Program().Run();

         Console.ReadLine();
      }

      private void Run()
      {
         _log.Trace("hello, LogMagic!");

         int a = 10, b = 0;

         try
         {
            _log.Trace("dividing {a} by {b}", a, b);
            Console.WriteLine(a / b);
         }
         catch(Exception ex)
         {
            _log.Trace("unexpected error", ex);
         }

         _log.Trace("attempting to divide by zero");
      }

   }
}
  1. Run the program

Logging Exceptions

LogMagic always check last parameter of Trace() arguments whether it's an exception class and eliminates from the argument list.

Configuration Basics

LogMagic uses C# API to configure logging.

Log writers

Log event writers generally record log events to some external representation, typically console, file, or external data store. LogMagic has a few built-in writers to get you started. More writers are redistributed via NuGet.

A curated list of available packages are listed below on this page.

Writers are configure using WriteTo congiguration object.

L.Config.WriteTo.PoshConsole();

Multiple writers can be active at the same time.

L.Config
	.WriteTo.PoshConsole()
	.WriteTo.Trace();

Formatting

Text-based writers support message formatting. Whenever a format parameter appears in writer configuration you can specify your own one:

L.Config
	.EnrichWith.ThreadId()
	.WriteTo.Console("{time:H:mm:ss,fff}|{threadId}{level,-7}|{source}|{message}{error}");

Enriched properties can also appear in the output. In the example above a threadId comes from thread ID ennricher.

Formatting syntax

Built-in property names:

  • {time} - used to reference event time
  • {level} - prints message severity
  • {source} - logging source name
  • {message} - log message
  • {error} - error

All of the properties support standard .NET formatting used in string.Format().

Enrichers

Enrichers are simple components that add properties to a log event. This can be used for the purpose of attaching a thread id, machine IP address etc. for example.

L.Config.EnrichWith.ThreadId();

Context Information

Sometimes it's useful to add context information to a logging session during a call duration scope. LogMagic achieves it by dynamically adding and removing propeties from the ambient "execution context". For example, all messages during a transaction might carry the id of that transaction, and so on.

The feature does not need any special configuration, and properties can be added an removed using L.Context():

log.Trace("no properties");

using(L.Context("A", "id1"))
{
	log.Trace("carries property A=id1");

	using(L.Context("B", "id2"))
	{
		log.Trace("carries A=id1 and B=id2");
	}

	log.Trace("carries property A=id1");

	using(L.Context("A", "id3"))
	{
		log.Trace("carries property A=id3");
	}

	log.Trace("carries property A=id1");
}

log.Trace("no properties");

Pushing property onto the context will override any existing properties with the same name, until the object returned from L.Context() is disposed, as the property A in the example demonstrates.

L.Context() accepts multiple properties at once if you need to:

using(L.Context("A", "id1",  "B", "id2"))
{
	//...
}

Logging context is used extensively by LogMagic plugins to carry execution context information across the application. For instance, web applications need to known which request the code is related to etc.

Important: properties must be popped from the context in the precise order in which they were added. Behavior otherwise is undefined.

You can also get context property value by name at any time in any place in your code by calling to L.GetContextValue(propertyName) which returns null if property doesn't exist.

Important: Log context is not available when you target for .NET Framework 4.5 due to the reason that this version doesn't have any options to track execution. If you are still using .NET 4.5 or earlier it's time to upgrade to .NET 4.6.

Writing log events

Log events are written to writers using the ILog interface. Typically you will instantiate it on top of your class definition you want to log from.

private readonly ILog _log = L.G<Class>();

// ...

_log.Trace("application v{version} started on {date}", "1.0", DateTime.UtcNow);

Message template syntax

the string above "application v{version} started on {date}" is a message template. Message templates are superset of standard .NET format string, so any format string acceptable to string.Format() will also be correctly processed by LogMagic.

  • Property names are written between { and } brackets
  • Formats that use numeric property names, like {0} and {1} exclusively, will be matched with the log method's parameters by treating the property names as indexes; this is identical to string.Format()'s behavior
  • If any of the property names are non-numeric, then all property names will be matched from left-to-right with the log method's parameters
  • Property names, both numeric and named, may be suffixed with an optional format, e.g. :000 to control how the property is rendered; these format strings behave exactly as their counterparts within the string.Format() syntax

Log event levels

LogMagic doesn't have the classic logging levels (i.e. debug, info, warn etc.) as this is proven to be rarely used. Instead you only need one single Trace() method. Due to the fact that structured logging is supported and promoted there is no need to have logging levels as you can always filter based on a custom property if you ever need to.

Tracking performance

You can track system or process performance by using the performance counter feature from LogMagic. This feature essentially emits a certain value on schedule, like average memory usage, average CPU usage etc. To configure a performance counter you would use CollecPerformanceCounter sentence in the configuration like so:

L.Config
   .WriteTo.PoshConsole()
   .CollectPerformanceCounters.WindowsCounter("Machine CPU Load (%)", "Processor", "% Processor Time", "_Total");

In this case LogMagic will periodicall (every 10 seconds) collect windows performance counter value and emit a log event.

If you don't know which counters you need you can always use .CollectPerformanceCounters.PlatformDefault() which on Windows will add the following counters to the collection list:

  • "Machine CPU Load (%)", "Processor", "% Processor Time", "_Total"
  • "Machine Available Memory (bytes)", "Memory", "Available Bytes"
  • "Process CPU Load (%)", "Process", "% Processor Time", processName
  • "Process Private Memory (bytes)", "Process", "Private Bytes", processName
  • "Process IO Data (bytes/sec)", "Process", "IO Data Bytes/sec", processName

where processName is current executing process name.

Performance counters in this version of LogMagic only work on Windows and only if you are using Desktop .NET framework or .NET Standard 2.0 and higher. In other cases performance counters are ignored. However, we are actively trying to support more platforms.

Known Writers and Enrichers

Name Description
System Console Simplest logger that outputs events to the system console.
Posh Console Simplest logger that outputs events to the system console, but also supports colorisation.
System Trace Writes to the system trace.
File on disk A really simple writer that outputs to a file on disk.
Azure Application Insights Emits telemetry into Azure Application Insights.
Azure Service Fabric Integrates with Azure Service Fabric by building correlating proxies, enrichers, and emitting cluster health events
ASP.NET Core Provides a custom middleware that automatically logs requests.
Azure Functions v2 Integrates with Azure Functions v2 Runtime.

Built-in enrichers

Writer Syntax Meaning
.Constant() adds a constant value to every log event
.MachineIp() current machine IP address
.MachineName() current machine DNS name
.MethodName() caller's method name
.ThreadId() managed thread id

Note that external packages may add more enrichers which are not listed here but documented on specific package page.

Async Helpers

Often tracking dependencies involves measuring time and catching exception whcih is a bit tedious.