How to Log with CloudWatch Logs, ASP.NET and Log4Net

The Apache Software Foundation’s Logging Services project aims to provide a group of cross-language logging services that allows producers of software to debug and audit their software. The project includes Log4j, Log4j Audit, Log4j Kotlin, Log4j Scala, Log4cxx, Log4Net and Log4PHP.

We’ll spend our time in this tutorial with Log4Net, the .NET port of Log4j. We’ll build a very basic API application to demonstrate how .NET apps can use Log4Net to output logs to Amazon CloudWatch Logs.

Photo by Osman Rana on Unsplash

The Solution

In this tutorial, we will provide a simple example where we log to Amazon CloudWatch Logs using ASP.NET and Log4Net.

Remember, for any example solution from AWS with .NET, we focus on the code that exemplifies the problem we are trying to solve. We don’t include logging, input validation, exception handling, etc., and we embed the configuration data within classes instead of using environment variables, configuration files, key/value stores and the like. These items should not be skipped for proper solutions.

Prerequisites

To complete this solution, you will need the .NET CLI which is included in the .NET SDK. In addition, you will need to configure your development environment to interact with AWS and create an AWS IAM user with the appropriate permissions to interact with Amazon CloudWatch Logs.

Warning: some AWS services may have fees associated with them.

Our Dev Environment

This tutorial was developed/updated using Ubuntu 24.10, .NET 8 SDK and Visual Studio Code 1.95.3. Some commands/constructs may vary across systems.

Develop the ASP.NET CloudWatch App

Step one is to create the ASP.NET App using the .NET CLI.

$ dotnet new webapi -n CloudWatchLog4Net --use-controllers

Add Application Dependencies

With the ASP.NET app created, now add the application dependencies.

$ dotnet add package AWS.Logger.Log4Net
$ dotnet add package Microsoft.Extensions.Logging.Log4Net.AspNetCore

Log4Net/CloudWatch Logs Configuration

For better or for worse, Log4Net is a port of Log4j. And, often times, ports come with moving old patterns/tech forward. In this case, we will be configuring our logging solution using XML. It’s not that XML is inadequate here, it’s that this solution lacks flexibility and JSON is the standard language for .NET configuration files. Checkout the Log4Net configuration page, for all the information on the configuration options using Log4Net. Not a fan of using XML? Try our other CloudWatch Logs tutorials using Serilog or NLog.

Let’s now set up our logging configuration using the XML below.

<?xml version="1.0" encoding="utf-8" ?>  
<log4net>  
  <appender name="AWS" type="AWS.Logger.Log4net.AWSAppender,AWS.Logger.Log4net">  
    <LogGroup>AWSwithDotnetLog4net</LogGroup>  
    <Region>us-east-1</Region>  
    <layout type="log4net.Layout.PatternLayout">  
      <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />  
    </layout>  
  </appender>  
  <root>  
    <level value="DEBUG" />  
    <appender-ref ref="AWS" />  
  </root>  
</log4net>

Let’s take a look behind some of the configuration data that we entered:

Appender: Log4Net defines an appender as an output destination for log data. This configuration section contains one or more appender configurations. In this case we configure the Amazon CloudWatch Logs appender. We’ll give this appender the name of, “AWS”, which we will use later below.
Appender.LogGroup: The Amazon CloudWatch Logs log group.
Appender.Region: The AWS region to log to.
Appender.Layout: In Log4Net, the layout is responsible for formatting the logging request.
Appender.Layout.ConversionPatterm; Sets the actual format for the layout.
Root: Defines the configuration of the root logger.
Root.Level: This section represents the log level threshold.
Root.Appender: Instructs Log4Net to use the specified appender. We’ll use the appender that was configured earlier: “AWS” (Amazon CloudWatch Logs).

Update the Program.cs file for the ASP.NET app

With the configuration set up, let’s now update the Program.cs file to integrate Log4Net into our .NET application.

For the first step, add the following using statement at the top of the file.

using Microsoft.Extensions.Logging;

With the using statement in place, update Program.cs to pull in Log4Net using the WebApplicationBuilder.

var builder = WebApplication.CreateBuilder(args);  
builder.Logging.ClearProviders();  
builder.Logging.AddLog4Net();

When completed, the Program.cs file should look something like the following:

using Microsoft.Extensions.Logging;  
  
var builder = WebApplication.CreateBuilder(args);  
builder.Logging.ClearProviders();  
builder.Logging.AddLog4Net();  
  
builder.Services.AddControllers();  
builder.Services.AddEndpointsApiExplorer();  
builder.Services.AddSwaggerGen();  
  
var app = builder.Build();  
  
if (app.Environment.IsDevelopment())  
{  
    app.UseSwagger();  
    app.UseSwaggerUI();  
}  
  
app.UseHttpsRedirection();  
  
app.UseAuthorization();  
  
app.MapControllers();  
  
app.Run();

Create an Endpoint to test the .NET Application

We’ll now create a controller to test logging to CloudWatch Logs. We’ll call this controller, LoggingTestController. Let’s develop a simple controller with a just a single GET method.

One thing that should be highlighted here is that we are using constructor injection to retrieve an instance of an ILogger object. This was setup in Program.cs when we added the Log4Net constructs.

using Microsoft.AspNetCore.Mvc;  
  
namespace CloudWatchLogNet.Controllers;  
  
[ApiController]  
[Route("[controller]")]  
public class LoggingTestController : ControllerBase  
{  
    private readonly ILogger<LoggingTestController> _logger;  
  
    public LoggingTestController(ILogger<LoggingTestController> logger)  
    {  
        _logger = logger;  
    }  
  
    public string Get()  
    {  
  
    }  
}

To test the Cloud Watch Logs integration via Log4Net, fill out the Get method like so.

public string Get()  
{  
    string thatThingToLog = "This is a test string to log via Log4Net";  
  
    _logger.LogError(thatThingToLog);  
  
    return thatThingToLog;  
}

First, we create a string variable named thatThingToLog and we provide a value for testing. We then log the error using the logger instance and the variable that we just created.

We finally return the variable to complete the method.

With the Get method complete, the LoggingTestController class should look similar to the code below.

using Microsoft.AspNetCore.Mvc;  
  
namespace CloudWatchLogNet.Controllers;  
  
[ApiController]  
[Route("[controller]")]  
public class LoggingTestController : ControllerBase  
{  
  
    private readonly ILogger<LoggingTestController> _logger;  
  
    public LoggingTestController(ILogger<LoggingTestController> logger)  
    {  
        _logger = logger;  
    }  
  
    public string Get()  
    {  
        string thatThingToLog = "This is a test string to log via Log4Net";  
  
        _logger.LogError(thatThingToLog);  
  
        return thatThingToLog;  
    }  
}

Log4Net/CloudWatch Logs ASP.NET App Test

With the .NET application completed, we can now test everything.

The first thing we’ll do is run the ASP.NET Web API from the CLI with the following command.

$ dotnet run

Using the details from the host data that is provided in the console, go to the URL of the LoggingTestController endpoint that we created. In our test environment, the full URL is: http://localhost:5064/loggingtest.

The browser should display the following message from the LoggingTestController endpoint.

This is a test string to log via Log4Net

Now let’s hit the AWS Console and take a look at CloudWatch Logs. Specifically let’s take a look at the AWSwithDotnetLog4net CloudWatch Logs log group. Let’s look for log entries like the following:

2024-09-12T14:24:38.456Z This is a test string to log via Log4Net

Summary

We have now finished this tutorial on logging ASP.NET log events to Amazon CloudWatch Logs using Log4Net.

Want to know more about the tech in this article?  Checkout these resources:

.NET CLI.NET SDKAWS .NET SDKAmazon CloudWatch Logs, Log4Net