Basics of logging in ASP NET Core

Basics of logging in ASP NET Core
Photo by Sebastian Pociecha / Unsplash

Hey guys, I’m so glad to see you again on my blog. Today I’ll show you how to add logging to your asp net core applications and why you should do it. I’ll show you the basic aspects of application logging with Serilog however I’m pretty sure this article will help you even if you already have some knowledge working with Serilog or application logging in general.

What this post will cover

  • What is logging
  • Why is it so important
  • What is Serilog
  • Serilog Installation
  • Serilog Configuration
  • Implementing Logging into your code

What is logging?

In simple terms, logging is the practice of recording events and actions that occur within an application. These events can include things like errors, warnings, and informational messages that can be used to diagnose issues when they arise.

Logs are typically stored in text files or databases and can be analyzed using tools like log viewers, search engines, or even machine learning algorithms to identify patterns and trends.

Why is logging so important?

Logging is critical for several reasons:

Debugging

When something goes wrong in your application, logging can be an invaluable tool for debugging. By reviewing your application logs, you can get a better understanding of what happened leading up to the issue and pinpoint the cause.

Troubleshooting

Logs can also be used to troubleshoot issues in production environments. When users report problems, you can use logs to identify the source of the issue and determine the best course of action to fix it.

Analytics

Logs can provide valuable insights into how users are interacting with your application. By analyzing your logs, you can identify usage patterns, identify areas for improvement, and optimize your application for better performance.

What is Serilog ?

Serilog is a popular logging framework for .NET applications. It's built with a focus on structured logging, making it easier to search, filter, and analyze logs. Serilog supports various output formats like text files, databases, and cloud services like Azure Application Insights.

Clone the GitHub repo

Before we start coding I recommend you to clone the Github repo from the web API that we have been working with all this time. Make sure you clone the “DatabaseSeeding” branch which is the latest one.

GitHub - Osempu/BlogAPI at DataSeeding
Contribute to Osempu/BlogAPI development by creating an account on GitHub.

Installing Serilog

Let’s begin installing serilog into our web API using the dotnet cli.

dotnet add package Serilog.AspNetCore

dotnet add package Serilog.Sinks.Console

dotnet add package Serilog.Sinks.File

dotnet add package Serilog.Enrichers.Thread

The first command will install the required Serilog package to work with asp net core, the sinks.console, and sinks.file packages will allow us to write our logs to the console or to a file to store them and consult them later and last the enrichers.thread package will allow us to add the current working thread to the logs so we can get even more information.

Serilog Configuration

In our Program.cs file add the following code to set up serilog

Log.Logger = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .Enrich.WithThreadId()
                    .WriteTo.Console()
                    .WriteTo.File("logs/serilogFile.txt",
                                    outputTemplate: "{Timestamp:HH:mm} [{Level}] ({ThreadId}) {Message}{NewLine}{Exception}",
                                    rollingInterval: RollingInterval.Day)
                    .CreateLogger();
...
builder.Host.UseSerilog();

We are creating a new instance of the logger with the logger configuration fluent builder. We specify a filter to only see logs going from debug and up to critical avoiding informational logs, next we enrich our logs with the currently running thread it and specify to write the logs to the console and to a file, then we specify the path to that file and the output template for our logs and lastly we call the UseSerilog.

Logging in action

Now we shall proceed to add some useful logging into our API endpoints in our PostsController.cs file.

...	

private readonly ILogger<PostsController> logger;

public PostsController(BlogDbContext context, ILogger<PostsController> logger)
{
    this.context = context;
    this.logger = logger;
}

[HttpGet]
public IActionResult GetPost()
{
    var posts = context.Posts.ToList();
    logger.LogDebug($"Get method called, got {posts.Count()} results");
    return Ok(posts);
}

[HttpGet("{id:int}")]
public IActionResult GetPost(int id)
{
    try
    {
        var post = context.Posts.Find(id);
        return Ok(post);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, $"Error getting post with id {id}");
        throw;
    }
}

[HttpPost]
public IActionResult CreatePost(Post post)
{
    try
    {
        context.Add(post);
        context.SaveChanges();

        return CreatedAtAction(nameof(GetPost), new { id = post.Id }, null);
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "Unexpected error on Post method");
        throw;
    }
}

[HttpPut]
public IActionResult EditPost(int id, [FromBody] Post post)
{
    var postToEdit = context.Posts.Find(id);

    if (postToEdit is null)
    {
        logger.LogError($"Post with id {id} was not found");
        throw new NullReferenceException("Post with id {id} was not found");
    }

    postToEdit.Title = post.Title;
    postToEdit.Body = post.Body;
    postToEdit.Author = post.Author;

    context.SaveChanges();

    return NoContent();
}

[HttpDelete("{id:int}")]
public IActionResult DeletePost(int id)
{
    try
    {
        var post = context.Posts.Find(id);
        context.Posts.Remove(post);
        context.SaveChanges();

        return NoContent();
    }
    catch (Exception ex)
    {
        logger.LogError(ex, $"Unexpected error on Delete method trying to delete post with Id {id}");
				throw;
    }
}

The first thing we have to make sure of is to inject our serilog logger through dependency injection using the ILogger<T> interface.

Get method

Here we are using logging to notify how many posts we are retrieving, this is a great example that logging is not only used to log errors but we can use it in an analytical way.

Get(id) method

Now on this method, we log an error specifying what post we were trying to get so that whenever we check the app logs this gives us a hint of what can be causing the error.

Post method

In our post method, we just notify that the error occurred while trying to call the post endpoint.

Put method

Now, this is another great example of the power of logging. If the post we are trying to update is null that means it does not exist and we log that out specifying the post id we were trying to call and was not found.

Delete method

Lastly on this method like on the post method, we log that the error occurred when someone tried to call the delete endpoint and then it points out what post was trying to get deleted.

Conclusion

Logging is not something that you can just copy from somebody else’s code and make it work perfectly on your code. Logging is tied to your app logic and needs and what you need to show when your app is working fine and what you need to see when it goes down. That is why even when logging is really important for our application health we don’t see that many developers enforce its use and that is because not everybody understands its power or how to really create high-value logs and not just print out random messages on your console and files.

That’s it for today!

Once again I’m here thanking you for reading my article and spending your precious time on something that I have written. I’ve been kinda absent and that’s because I’m still trying to get consistent in writing, sometimes I feel like I don’t know what to write about or how to start but I’m still going forward and have a lot of plans to do on my blog and things to offer to you guys so you get better at coding and can get that dreamed job or become a code wizard like I’m still trying to do.

Thanks and remember to support me on my blog unitcoding.com and on my youtube channel Unit Coding. Have a great day and keep on coding!