Mastering Application Insights: Logging using NLOG, log4net and serilog

Tapesh Mehta Tapesh Mehta | Published on: Feb 21, 2024 | Est. reading time: 6 minutes
logging in .net applications

Logging, especially in the context of .Net applications, continues to be a core practice in the evolving software development landscape. Why, you ask? Imagine not having a compass to navigate the complexity of today’s applications. That’s where logging steps in – it’s not just a practice but a lifeline. Essentially, log gives you a transparent view of the application’s running operations and offers insights that are vital for your maintenance, debugging or improving.

In addition, logging becomes the eyes and ears of the development team in a dynamic and sometimes unpredictable production environment. It’s a real time monitoring tool that alerts team members to issues often before users see them. User satisfaction and trust in the application are enhanced by this active approach to resolving problems. Additionally, logs play a pivotal role in compliance and auditing processes, ensuring that applications meet regulatory standards and security requirements.

Given its importance, it’s no surprise that a large number of logging libraries have been created to meet the needs of .Net ecosystem, each with different features and capabilities. Nlog, log4net and Serilog are some of the more popular ones. These libraries are distinguished by their flexibility, ease of integration and comprehensive logging capabilities that enable developers to choose which .Net applications they want to install strong logging features on. These libraries provide the tools necessary for efficient data collection and analysis of applications, whether it’s plain log messages or complicated structured data, so that developers can gain an understanding of what they need to keep up with their applications and make them better.

Now, we’ll explore how to implement each of these libraries, spicing it up with code samples and all the nitty-gritty details for setting things up.

Table of Contents

NLog: The Flexible Friend

NLog is a flexible logging framework that’s easy to set up and incredibly malleable when it comes to configuring. In the .NET universe, it’s like a Swiss Army knife for logging frameworks. Let’s learn how to set it up and use it in an ASP.NET Core application.

Getting Started with NLog

First things first, you need to add NLog to your project. Pop open your terminal or package manager and run:

Install-Package NLog.Web.AspNetCore

This command fetches the NLog package tailored for ASP.NET Core applications.

Option 1: Setting up NLog via Nlog.config

In .Net Core 8, you configure NLog in the Program.cs. Here’s a basic setup:

var builder = WebApplication.CreateBuilder(args);

// NLog configuration
builder.Logging.ClearProviders();
builder.Host.UseNLog();

var app = builder.Build();

Here is the sample NLog.config

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      throwConfigExceptions="true"
      internalLogLevel="Info"
      internalLogFile="internal-nlog.txt">

  <!-- Define where the logs are written -->
  <targets>
    <!-- Write logs to file -->
    <target xsi:type="File" name="logfile" fileName="${basedir}/logs/logfile-${shortdate}.txt"
            layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=toString,Data}" />

    <!-- Write logs to console -->
    <target xsi:type="Console" name="logconsole"
            layout="${date:format=HH\:mm\:ss} ${level} ${message}" />
  </targets>

  <!-- Rules for mapping loggers to targets -->
  <rules>
    <!-- All logs, including from Microsoft.*, will be sent to "logconsole" -->
    <logger name="*" minlevel="Debug" writeTo="logconsole" />

    <!-- Skip Microsoft logs and only write them to "logfile" -->
    <logger name="Microsoft.*" minlevel="Info" writeTo="logfile" final="true" />

    <!-- All other logs from application will be written to both "logfile" and "logconsole" -->
    <logger name="*" minlevel="Debug" writeTo="logfile,logconsole" />
  </rules>
</nlog>

Option 2: Setting up NLog via appsettings.json

Ensure your appsettings.json includes the NLog configuration section. Here’s an example snippet that you might include in your appsettings.json:

"NLog": {
  "autoReload": true,
  "throwConfigExceptions": true,
  "internalLogLevel": "Warn",
  "internalLogFile": "internal-nlog.txt",
  "targets": {
    "logfile": {
      "type": "File",
      "fileName": "${currentdir}/logs/nlog-${shortdate}.log",
      "layout": "${longdate} ${uppercase:${level}} ${message} ${exception:format=toString}"
    },
    "console": {
      "type": "Console"
    }
  },
  "rules": [
    {
      "logger": "*",
      "minLevel": "Debug",
      "writeTo": "logfile,console"
    }
  ]
}

and add this code in the Program.cs:

// Adding NLog to ASP.NET Core
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
builder.Host.UseNLog(); // This configures NLog using NLog's own section in appsettings.json

Option 3: Setting up NLog via Fluent Configuration

The NLog LogFactory has support for fluent setup of the initial NLog configuration.

Build NLog config that writes everything to console:

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger().WriteToConsole()
});

Build NLog config that writes to file and console:

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger().FilterMinLevel(LogLevel.Info).WriteToConsole();
   builder.ForLogger().FilterMinLevel(LogLevel.Debug).WriteToFile(fileName: "App_${shortdate}.txt");
});

Build NLog config that writes to custom target::

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger().FilterMinLevel(LogLevel.Info).WriteTo(new MyCustomTarget() { Layout = "${message}" });
});

Build NLog config that restricts output from noisy logger:

NLog.LogManager.Setup().LoadConfiguration(builder => {
   builder.ForLogger("Microsoft.*").WriteToNil(finalMinLevel: LogLevel.Warn);
   builder.ForLogger().FilterMinLevel(LogLevel.Info).WriteToConsole();
});

Logging Examples

Inject ILogger into your controllers or services and use it to log at different levels.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Homepage visited");
        _logger.LogWarning("This is a warning");
        _logger.LogError("This is an error");
        return View();
    }
}

And that’s it! You’ve got NLog up and running.

log4net: The Old Guard

In the world of .NET, log4net is the Gandalf of logging frameworks. It has been here for a long time, proving its reliability and robustness. Maybe it’s not the newest tool in the shed, but its power and adaptability are undeniable.

Adding log4net to Your Arsenal

To start with log4net, add it to your project:

Install-Package Microsoft.Extensions.Logging.Log4Net.AspNetCore

This package integrates log4net with the ASP.NET Core logging system.

Option 1: Setting Up log4net via log4net.config

With .Net Core 8, configuring log4net involves specifying the configuration file and adding it as a logging provider:

var builder = WebApplication.CreateBuilder(args);

// log4net configuration
builder.Logging.AddLog4Net("log4net.config");

var app = builder.Build();
<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="logs/myapp.log" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="10" />
    <maximumFileSize value="10MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
  </appender>
  <root>
    <level value="INFO" />
    <appender-ref ref="RollingFile" />
  </root>
</log4net>

This configuration sets up a rolling file appender that logs info-level messages to a file, myapp.log.

Option 2: Setting Up log4net via appsettings.json

Traditionally, Log4Net configurations live in their own XML file, but with a little bit of setup, we can make appsettings.json its new home.

You’ll add a section in your appsettings.json file that holds your Log4Net configurations. It might look a bit alien compared to the XML format, but it’s all about getting the JSON structure right. Here’s a simple example:

"Log4Net": {
  "Appenders": [
    {
      "Type": "log4net.Appender.RollingFileAppender",
      "File": "Logs/myapp.log",
      "AppendToFile": true,
      "MaxSizeRollBackups": 5,
      "MaximumFileSize": "10MB",
      "RollingStyle": "Size",
      "StaticLogFileName": true,
      "Layout": {
        "Type": "log4net.Layout.PatternLayout",
        "ConversionPattern": "%date [%thread] %-5level %logger - %message%newline"
      }
    }
  ],
  "Root": {
    "Level": "DEBUG"
  }
}

Now configure your Program.cs to use the above section like below. Basically I’ve created a ConfigureLog4Net method and called it by passing IConfiguration.

ConfigureLog4Net(app.Services.GetRequiredService<IConfiguration>());
void ConfigureLog4Net(IConfiguration configuration)
{
    var loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());

    var log4NetConfig = configuration.GetSection("Log4Net");
    var appendersConfig = log4NetConfig.GetSection("Appenders").GetChildren();

    foreach (var appenderConfig in appendersConfig)
    {
        var appender = CreateAppender(appenderConfig);
        if (appender != null)
        {
            ((Hierarchy)loggerRepository).Root.AddAppender(appender);
        }
    }

    var rootLogLevel = log4NetConfig.GetSection("Root:Level").Value;
    ((Hierarchy)loggerRepository).Root.Level = loggerRepository.LevelMap[rootLogLevel];
    ((Hierarchy)loggerRepository).Configured = true;
}

IAppender CreateAppender(IConfigurationSection appenderConfig)
{
    var appenderType = appenderConfig.GetValue<string>("Type");

    // Here you would create a switch or if-else chain based on the appenderType
    // For this example, let's assume it's a RollingFileAppender
    if (appenderType == "log4net.Appender.RollingFileAppender")
    {
        var appender = new RollingFileAppender
        {
            File = appenderConfig.GetValue<string>("File"),
            AppendToFile = appenderConfig.GetValue<bool>("AppendToFile"),
            RollingStyle = RollingFileAppender.RollingMode.Size,
            MaxSizeRollBackups = appenderConfig.GetValue<int>("MaxSizeRollBackups"),
            MaximumFileSize = appenderConfig.GetValue<string>("MaximumFileSize"),
            StaticLogFileName = appenderConfig.GetValue<bool>("StaticLogFileName"),
            Layout = new PatternLayout(appenderConfig.GetSection("Layout:ConversionPattern").Value)
        };
        appender.ActivateOptions(); // Important to activate the options
        return appender;
    }

    // Add other appender types as needed
    return null;
}

Logging Example

Injecting and using log4net in your classes is straightforward, similar to NLog:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Visited the Index page");
        _logger.Warn("Warning - Check this out!");
        _logger.Error("Error occurred");
        return View();
    }
}

Serilog: The Modern Maestro

Serilog is like a cool new kid on the block, bringing structured logging into the mainstream. It is designed to be as easy to record as possible, in particular when dealing with complex data or where it is necessary to insert the records into different outputs.

Adding Serilog to Your Application

NuGet Package Installation

Install Serilog and its ASP.NET Core integration with:

Install-Package Serilog.AspNetCore

Configure Serilog in Program.cs

Setup Serilog in Program.cs to define where logs should be written:

var builder = WebApplication.CreateBuilder(args);

// Serilog configuration
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .WriteTo.Console()
    .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

builder.Host.UseSerilog();

var app = builder.Build();

Logging Examples

Use Serilog’s Log class directly or inject ILogger:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        Log.Information("Homepage visited");
        Log.Warning("This is a warning with Serilog");
        Log.Error("This is an error with Serilog");
        return View();
    }
}

Comparison

Each of these logging frameworks has its strengths and weaknesses, and the best choice often depends on specific project requirements, team familiarity, and the ecosystem within which the application operates.

Here’s a simplified comparison table highlighting some key features and considerations:

Feature/AspectNLogLog4NetSerilog
PerformanceHigh, optimized for speed and flexibility.Good, with a focus on reliability.High, especially with structured logging.
ConfigurationXML, JSON, code.XML, JSON, code.JSON, code.
Structured LoggingSupported with structured logging layout.Basic support through custom appenders.First-class support for structured logging.
ExtensibilityHighly extensible with custom targets.Extensible with custom appenders.Highly extensible with sinks.
Async LoggingBuilt-in async support.Async support via external packages.Built-in async support.
Target/SinksWide range of targets.Wide range of appenders.Wide range of sinks, especially for modern platforms and services.
Community and SupportLarge community, active development.Large, mature community.Large, active community with innovative plugins.
Learning CurveModerate.Moderate.Moderate to low, with a focus on simplicity.
DocumentationExtensive.Good.Excellent, with a focus on getting started quickly.
IntegrationBroad integration.Broad integration.Excellent integration, especially with .NET Core/ASP.NET Core.
LicenseBSD.Apache License 2.0.MIT.
Initial Release2006.2001.2013.
Unique FeaturesRich set of layout renderers and targets.Traditional and widely used.Emphasis on structured logging and powerful query capabilities.

FAQ (Frequently Asked Questions)

Q1: What are NLog, log4net, and Serilog?

A: NLog, log4net, and Serilog are all logging frameworks for .NET applications. They provide mechanisms to output log messages from your applications to various targets (files, databases, consoles, etc.) with configurable levels of severity.

Q2: Which logging framework is the easiest to configure?

A: Serilog is often praised for its simplicity and powerful structured logging capabilities right out of the box. It has a straightforward API and fluent configuration system that many find intuitive. NLog and log4net also support flexible configurations but might require more setup for advanced scenarios.

Q3: Can I use these logging frameworks in .NET Core or .NET 5/6/7 applications?

A: Yes, all three logging frameworks are compatible with .NET Core and the latest .NET versions. They have been updated to work seamlessly with modern .NET applications, including web, desktop, and console apps.

Q4: Which framework should I use if structured logging is a priority?

A: Serilog is designed with structured logging as a core feature, making it the go-to choice for applications where structured logging is a priority. It allows you to log complex data types and query them efficiently.

Q5: How do NLog, log4net, and Serilog differ in performance?

A: Performance can vary based on the configuration and usage patterns. In general, all three frameworks are designed to be efficient and have minimal impact on application performance. However, Serilog’s focus on structured logging can lead to slightly higher memory usage in scenarios involving complex log data. NLog and log4net are highly optimized for speed and efficiency, especially in their latest versions.

Q6: Are there any significant differences in the types of logging outputs supported by these frameworks?

A: All three frameworks support a wide range of logging outputs, including file, console, database, and network targets. Serilog stands out for its extensive support for structured data sinks, making it easier to integrate with modern data storage and analysis tools.

Q7: How do I decide which logging framework to use for my project?

A: The choice depends on your project’s specific requirements:
Serilog: Ideal for applications where structured logging and querying log data are crucial.
NLog: Offers a great balance between performance, flexibility, and ease of use, suitable for both traditional and modern .NET applications.
Log4Net: A solid choice for projects that require a mature and proven logging solution, especially if you are familiar with the Apache logging ecosystem.
Remember, the best logging framework is one that suits your project’s needs, integrates well with your existing infrastructure, and has a learning curve and complexity level that your team is comfortable with.

Conclusion

Finally, in order to build and maintain robust .Net applications, it is essential that logging be part of the process. It plays a critical role in monitoring application health and user interaction, not only in troubleshooting and debugging. The development community has a powerful tool at their disposal that makes it easy for them to implement complete log strategies, thanks to the advent of advanced logs libraries like NLog, Log4net and Serilog.

NLog is flexible and easy to use, log4net has a long history of reliability, and Serilog shines with its structured logging capabilities. In order to ensure that the integration of robust logging into applications is more easy than ever, each library has been adapted for seamless compatibility with .Net Core 8. These libraries are suited to applications of any size and complexity, offering a mix of flexibility, ease of use as well as modern features.

Are you looking for enterprise-grade .Net applications solutions? Look no further than WireFuture. WireFuture is your ideal partner to exploit the full potential of .Net technology, with a proven track record in delivering high quality, scalable and secure .Net solutions.

In order to meet the unique challenges of your business, hire .NET developers from our team of experienced professionals to be able to tailor solutions to meet your specific needs, ensuring that your application performs flawlessly and stands out in today’s competitive environment. Choose WireFuture for unparalleled expertise and innovation in the development of .Net applications.

clutch profile good firms
Bring Your Ideas to Life with Expert Developers! 🚀

At WireFuture, we believe every idea has the potential to disrupt markets. Join us, and let's create software that speaks volumes, engages users, and drives growth.

Hire Now

Categories
.NET Development Angular Development JavaScript Development KnockoutJS Development NodeJS Development PHP Development Python Development React Development Software Development VueJS Development All
About Author
wirefuture - founder

Tapesh Mehta

verified Verified
Expert in Software Development

Tapesh Mehta is a seasoned tech worker who has been making apps for the web, mobile devices, and desktop for over 13+ years. Tapesh knows a lot of different computer languages and frameworks. For robust web solutions, he is an expert in Asp.Net, PHP, and Python. He is also very good at making hybrid mobile apps, which use Ionic, Xamarin, and Flutter to make cross-platform user experiences that work well together. In addition, Tapesh has a lot of experience making complex desktop apps with WPF, which shows how flexible and creative he is when it comes to making software. His work is marked by a constant desire to learn and change.

Get in Touch
Your Ideas, Our Strategy – Let's Connect.

No commitment required. Whether you’re a charity, business, start-up or you just have an idea – we’re happy to talk through your project.

Embrace a worry-free experience as we proactively update, secure, and optimize your software, enabling you to focus on what matters most – driving innovation and achieving your business goals.

Hire Your A-Team Here to Unlock Potential & Drive Results
You can send an email to contact@wirefuture.com
clutch profile good firms award-3 award-4 award-5 award-6