Adding Serilog to Azure Functions created using .NET 5

The post is based on .NET 5.0

Before the release of .NET 5, all functions developed using .NET ran as a class library in Azure and it was running inside the same process as the host. But with .NET 5, a function app built with .NET 5 runs in an isolated worker process which lets you decouple your function code from the runtime. A .NET isolated function is basically a console application targeting .NET 5 and requires the following files

  • host.json file
  • local.settings.json file
  • C# project file which defines the project and dependencies
  • Program.cs file(entry point of the app)

In this post, I will go through the steps that are needed for creating a .NET 5 Azure function, integrating Serilog for file logging, debugging, and running it locally, and then move on to publishing the function to Azure. You may already know that Azure functions already support some form of logging out of the box, but you may need to implement custom logging mechanisms depending on your need or for satisfying organizational requirements. I am going to use Serilog, which is a third-party logging provider which supports .NET and is also one of the most widely used in the ecosystem

Pre-requisites

There are some things you need before you start implementing this one. Azure Subscription is needed for hosting the functions in Azure, .NET 5 SDK, and Azure Functions Core Tools. Azure CLI is needed for developing, debugging, and publishing the app to Azure and VS Code for writing code. 

Azure Subscription

.NET 5 SDK

Azure Function Core Tools version 3.0.3381 or greater

Visual Studio Code

Azure CLI

Step 1 

The first step is to create a new Functions project, we will be using the func command to create a new one from the command line. Even though you can edit and debug the project in Visual Studio, full support is not yet available as the project templates for creating the project and all. The following command will create a new Azure Function project and specifying the runtime as dotnetisolated enables you to run the app on .NET 5

func init FunctionLogger --worker-runtime dotnetisolated

When this command is executed, it will create all the necessary files including the host.json and local.settings.json files. The host.json file contains the configuration options affecting all the functions in your app whereas the other file can be used for storing options such as connection strings, secrets, and other settings used by your app. Since this file can have sensitive data, it is excluded when you check in the code to source control

Step 2 

Next, we will move on to create a new function in the project which is triggered by an HTTP request. The below statement creates a function named HttpExample using the HttpTrigger template and enables anonymous authentication

func new --name HttpExample --template "HTTP trigger" --authlevel "anonymous"

public  class HttpExample
    {
        [Function("HttpExample")]
        public  HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("HttpExample");
            logger.LogInformation("C# HTTP trigger function processed a request.");

            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            response.WriteString("Welcome to Azure Functions!");

            return response;
        }
    }

We are not going to modifying the contents of the function created by default, because these statements are sufficient for demonstrating the logging mechanism

Step 3 

To use Serilog, you will need to add some packages in order to use it in your application. The package named Serilog is having the core functionality and Serilog.File and Serilog.Console is having the logic for writing it to the console and file respectively. In Serilog, these are called Sinks and there are a lot of them available for writing logs to Database, Seq, App Insights etc 

dotnet add package Microsoft.Azure.Functions.Extensions
dotnet add package Serilog
dotnet add package Serilog.Extensions.Logging
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File

Step 4

In a .NET 5 isolated function, you can configure the startup option by modify the main method in the Program.cs file. The entry point of your function is this method and here you will be able to configure the host options. To integrate Serilog, you will need to import them into your project first and then configure the pipeline as shown below. Here I'm enabling both the file and console sinks, and the file sink is configured as a rolling file which creates a new file for each day.

    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                // .ConfigureAppConfiguration((hostingcontext,config)=>{

                // })
                .ConfigureServices(s=>
                {
                     var logger = new LoggerConfiguration()
                    .WriteTo.Console()
                    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
                    .CreateLogger();
                    s.AddLogging(lb => lb.AddSerilog(logger));
                })
                .Build();

            host.Run();
        }
    }

Step 5

Let's compile the project and run the app by going to the terminal and executing the below command. It will run the function locally using Azure Function core tools
func start --dotnet-isolated

Multiple Log Files in Serilog

Multiple Log Files in Serilog

When the HTTP trigger function is executed by invoking the request from the browser, you can see that information is now being written to the console as well as the log file. The file will be created by the Serilog provider if it is not there and will be rolled over at the end of each day

Step 6

Now, let's publish the function app to Azure. As of now, functions developed using .NET 5 can be published only using the Azure CLI and are not supported in Portal as well as Visual Studio. 

First, I am going to create a resource group and a storage account in Azure which are the pre-requisites for creating a function app in Azure

You can either use the portal or Azure CLI for the same

Multiple Log Files in Serilog

Multiple Log Files in Serilog

Now, we will proceed to create the function app from the CLI using the below command. It will create the function in the resource group created previously and will use a consumption plan. It will use the storage account which we created earlier for the function management and uses .NET 5 and function V3 runtime for executing the function

az functionapp create --resource-group function-demo-rg --consumption-plan-location eastus --runtime dotnet-isolated --runtime-version 5.0 --functions-version 3 --name FunctionLoggerApp --storage-account functiondemostorage
Note: Make sure that you have the latest version of the Azure CLI, otherwise you get errors saying "dotnet-isolated is not a valid value for --runtime"

Multiple Log Files in Serilog

We will need to make a slight adjustment in our code to specify the location of the log file path. When I tried to put the log file in the folder from where our application was running, the logs were not getting written into it. By default, Azure creates a log folder outside the root folder of your app to write all the telemetry generated by the runtime. So when I used that path, it started writing information into it. Now my Program.cs code looks like the one below

     var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                // .ConfigureAppConfiguration((hostingcontext,config)=>{

                // })
                .ConfigureServices(s=>
                {
//If the app is hosted in Azure, then the env variable WEBSITE_SITE_NAME will have a value var filepath = !string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"))?@"D:\home\LogFiles\Application\log.txt":"log.txt"; var logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File(filepath, rollingInterval: RollingInterval.Day) .CreateLogger(); s.AddLogging(lb => lb.AddSerilog(logger)); }) .Build(); host.Run();

To publish the app to Azure

func azure functionapp publish FunctionLoggerApp

Multiple Log Files in Serilog

If you browse to the endpoint of your function app using a browser, you will see the same message we got while testing in local, and our log file in the cloud will now have info written into it

Multiple Log Files in Serilog


No Comments

Add a Comment