Press enter to see results or esc to cancel.

Enabling Nodinite Logging in Azure Functions [Hybrid Scenario Series Part 1]

Nodinite enables you to centralize documentation, logging and monitoring for your workflows and system integration solutions for all system integration platforms. We at Nodinite have built-in support for many platforms, such as Mule ESB, Microsoft BizTalk Server, Microsoft Azure Logic Apps, IBM, etc and we are continuously developing support for more platforms. Using the API:s you are free to add custom code for your custom solutions to make sure you get self service from end to.

In this blog post we will cover how to enable logging using Nodinite in your .NET Azure Functions. This is part of a series of blog posts in which we will cover “how to enable end-to-end logging and monitoring of hybrid integrations end to end”.

Azure Functions play an important role in today’s system integration solutions built with the Azure’s integration stack. Azure Functions are used to either receive, transform or send data; Where Logic Apps usually fail, Azure Functions will cover your custom needs and special cases.

Logging to Nodinite in this blog post is done using Nodinite’s Serilog API Sink, which uses Nodinite’s Log API. The Log API is designed to support logging from any application for which we did not (yet) create a logging agent or for customers/partners wanting to build custom solutions.

Before we start

To follow this tutorial, make sure that you have the following:

  1. Azure CLI installed on your local machine
  2. Access to an active Azure Subscription for your Azure Function
  3. A running instance of Nodinite (if you do not have a running instance, get in touch with us and we will provide you with a time limited demo environment for free)
  4. Your IDE (we will use Visual Studio Code in this blog post)

And also, it would be good for you to have

  1. An understanding on how Nodinite works – you can read more on our documentation. Or get in touch with us!
  2. A basic understanding of Azure Functions
  3. An understanding or worked with Serilog

Get started

Create your Azure Function

We will use the Azure CLI to quickly get us started with an empty Azure Function project.

  • Open your command prompt and run the following command:
func init MyFunctionProj

This will automatically create a new folder with the same name as the project.

  • Navigate into the newly created folder MyFunctionProj (cd MyFunctionProj) and to add our first function to the project, run the following command:
func new --name MyHttpTrigger --template "HttpTrigger"

The command above creates a function that is triggered using an HTTP call. It really does not matter which type of trigger you are using in your Azure Function for this example to work.

Open the project in your IDE

Since we are using Visual Studio Code, the next thing we need to do next is to open the Azure Function project from the previous steps and write “code .” into the command prompt and an instance will be started with the current directory as the default directory. If everything has been done correctly, your IDE should show a similar file structure as in the image below.

Image 2: File structure in Visual Studio Code

Add the required Nuget Packages to the Project

In order for us to log from an Azure Function, we need to add three different Nuget packages to the project:

  1. Newtonsoft.JSON, this package is automatically part of your project, but needs to be added as a PackageReference due to the need of a higher version
  2. Serilog
  3. Nodinite.Serilog.ApiSink

Adding these references is done by opening the MyFunctionProj.csproj and add the following rows to the Project/ItemGroup tag:

  1. <PackageReference Include=”Newtonsoft.Json” Version=”12.0.1″ />
  2. <PackageReference Include=”Serilog” Version=”2.8.0″ />
  3. <PackageReference Include=”Nodinite.Serilog.ApiSink” Version=”1.0.0″ />

This will let your Azure Function project know that there are new packages to install and these will automatically be installed when starting the project.

Add the Serilog Logger Configuration to your Function

Since the required nuget packages are now installed, we can start adding the Serilog logger library  to our Azure Function.

Start by adding the required “usings” by opening the MyHTTPTrigger.cs file:

using Serilog;
using Nodinite.Serilog.Models;
using Nodinite.Serilog.ApiSink;

And add the required configuration into the run function – these are mapped to the Log API specific properties:

var nodiniteApiUrl = "https://{yourNodiniteInstance}/LogApi/api/";
var settings = new NodiniteLogEventSettings()
{
    LogAgentValueId = 503,
    EndPointDirection = 0,
    EndPointTypeId = 0,
    EndPointUri = "Nodinite.Serilog.ApiSink.AzureFunction.Serilog",
    EndPointName = "Nodinite.Serilog.ApiSink.AzureFunction",
    OriginalMessageTypeName = "Serilog.LogEvent",
    ProcessingUser = "NODINITE",
    ProcessName = "Azure.FunctionApp.MyFunctionProj.MyHttpTrigger",
    ProcessingMachineName = "Azure",
    ProcessingModuleName = "Azure.FunctionApp.MyFunctionProj",
    ProcessingModuleType = "Azure.FunctionApp"
};

string orderId = req.Query["orderId"];
string correlationId = req.Query["correlationId"];
            
Serilog.ILogger nodiniteLogger = new LoggerConfiguration()
    .WriteTo.NodiniteApiSink(nodiniteApiUrl, settings)
    .CreateLogger()
    .ForContext("CorrelationdId", correlationId)
    .ForContext("OrderId", orderId);

That’s it! This is all you need to configure to enable Nodinite logging using the Nodinite’s Serilog API Sink.
In the configuration above, we also added contextual values to be logged using “.ForContext(…, …)”. This helps us when using Nodinite to search for messages that correlate with each other, making it simpler for the user to understand what happened with the different messages along the road.

Create your first Logged Message

What’s left is to put in your log points and tell the Sink what to log, see example below:

nodiniteLogger.Information("C# HTTP trigger function processed a request.");

Important Notice: The serilog sink does not extend the existing Microsoft.Extensions.Logging.ILogger. If you still want to log to the Azure Function Trace, make sure you log to both the trace and the serilog logger.

The final result should look like the code snippet below:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Nodinite.Serilog.Models;
using Serilog;
using Nodinite.Serilog.ApiSink;

namespace MyFunctionProj
{
    public static class MyHttpTrigger
    {
        [FunctionName("MyHttpTrigger")]
        public static async Task Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            Microsoft.Extensions.Logging.ILogger log)
        {
            var nodiniteApiUrl = "https://{yourNodiniteInstance}/LogApi/api/";
            var settings = new NodiniteLogEventSettings()
            {
                LogAgentValueId = 503,
                EndPointDirection = 0,
                EndPointTypeId = 0,
                EndPointUri = "Nodinite.Serilog.ApiSink.AzureFunction.Serilog",
                EndPointName = "Nodinite.Serilog.ApiSink.AzureFunction",
                OriginalMessageTypeName = "Serilog.LogEvent",
                ProcessingUser = "NODINITE",
                ProcessName = "Azure.FunctionApp.MyFunctionProj.MyHttpTrigger",
                ProcessingMachineName = "Azure",
                ProcessingModuleName = "Azure.FunctionApp.MyFunctionProj",
                ProcessingModuleType = "Azure.FunctionApp"
            };

            string orderId = req.Query["orderId"];
            string correlationId = req.Query["correlationId"];
            
            Serilog.ILogger nodiniteLogger = new LoggerConfiguration()
                .WriteTo.NodiniteApiSink(nodiniteApiUrl, settings)
                .CreateLogger()
                .ForContext("CorrelationdId", correlationId)
                .ForContext("OrderId", orderId);

            string msg = $"Order #{orderId} processed.";
            nodiniteLogger.Information(msg);
            log.LogInformation(msg);

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            return (ActionResult)new OkObjectResult(msg);
        }
    }
}

Run the Azure Function

Before you build and run the newly created Azure Function, make sure you have saved all the changes first.

Open your command prompt and run the following command

func host start --build

This will automatically restore all Nuget packages for you, build the code and then host your Azure Function on your local machine. If everything went as it should, it looks like the image below.

Image 3: Console output of Azure CLI

Now open your browser and browse to http://0.0.0.0:7071/api/MyHttpTrigger?orderId=1337&correlationId=5ef8731d-88d2-44c9-b229-ec35d8bebae4 (this is not a public URL, this will be available after you executed the “func host start –build” command).
Important: When you run the example above, the network port might differ.

Which should show the following

Image 4: Browser result of Azure Function endpoint.

Have a look in your Nodinite Instance

By searching in for example the Admin View we can search for all kind of messages that have been logged to Nodinite and in our case, especially for the messages being logged from our Azure Function.

Image 5: Nodinite search result

The image above shows the search result in Nodinite, showing the actual message from our Azure Function.

In a real world scenario, we recommend you to create custom log views in Nodinite for you to easier see all messages from a specific Azure Function and also to combine your logs for your entire integration chain (commonly in Azure integrations: Azure Logic Apps, Azure API Management, etc).

Image 6: Nodinite contextual properties

And since we log contextual values (see image above) we could create search fields to simply search for a specific “order” or the “correlation id”, making it really simple to search for what you are looking for!

And we are done! We now have an Azure Function that will logs all your messages to Nodinite! The working example of this blog post is published to github and can be found here.

Conclusion

By using Nodinite’s Serilog API Sink you can simply centralize all log messages to one single place – Nodinite. And combining the logs with other log sources like Microsoft BizTalk Server, Azure API Management, Azure Logic Apps – you can correlate and follow your messages from end to end!

Nodinite has built in logging support for

In the next blog post, we will cover how to achieve the best result with logging from your Azure Logic Apps – Important Notice: We do not require your solution to change to enable logging! And we also do support Microsoft’s built-in tracking id and tracked properties functionality while logging.

Comments

Leave a Comment