Skip to main content
Version: v2.5.0

Using Arcus & Serilog in Azure Functions

When using Arcus Observability & Serilog it is mandatory that your application is configured correctly to ensure everything works smoothly and all features are working fine.

We encourage you to follow the standard Serilog instructions on setting your application up.

Some aspects we would like to highlight are:

  • Make sure to call UseSerilog when creating a IHostBuilder
  • Remove the default Microsoft's ApplicationInsightsLoggerProvider via the RemoveMicrosoftApplicationInsightsLoggerProvider extension
  • Remove the Logging section from the appsettings.json (if applicable) as this is not used by Serilog

We need to call RemoveMicrosoftApplicationInsightsLoggerProvider to remove Microsoft's ApplicationInsightsLoggerProvider because it would conflict with our own Serilog Application Insights sink. We can't guarantee stable telemetry if Microsoft's logger provider is registered as this provider manipulates the telemetry before it get's send out to Application Insights. Removing it ensure that Arcus is in full control of the send-out telemetry.

Setting up Serilog with Azure Functions#

Using Serilog with Azure Functions requires some guidance and we've made it a bit easier to use.

Before we get started, install our NuGet package for Azure Functions:

PM > Install-Package -Name Arcus.Observability.Telemetry.AzureFunctions

Once that is done, you can configure Serilog during startup as following:

using Microsoft.Extensions.Logging;
[assembly: FunctionsStartup(typeof(Startup))]namespace Arcus.Samples.AzureFunction{    public class Startup : FunctionsStartup    {        public override void Configure(IFunctionsHostBuilder builder)        {            var config = builder.GetContext().Configuration;
            var instrumentationKey = config.GetValue<string>("APPINSIGHTS_INSTRUMENTATIONKEY");
            var logger = new LoggerConfiguration()                .MinimumLevel.Debug()                .MinimumLevel.Override("Microsoft", LogEventLevel.Information)                .Enrich.FromLogContext()                .Enrich.WithComponentName("Docker Hub Metrics Scraper")                .Enrich.WithVersion()                .WriteTo.Console()                .WriteTo.AzureApplicationInsights(instrumentationKey)                .CreateLogger();
            builder.Services.AddLogging(loggingBuilder =>            {                loggingBuilder.RemoveMicrosoftApplicationInsightsLoggerProvider()                              .AddSerilog(logger);            });        }    }}

Here is an example of how you can use ILogger to write multi-dimensional metrics with Arcus. If Serilog would not be setup correctly (see above), it would only report the metric without the dimensions.

using Microsoft.Azure.Databricks.Client;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Logging;
public class DockerHubMetricScraperFunction{    private readonly DockerHubClient _dockerHubClient;    private readonly IConfiguration _configuration;    private readonly ILogger<DockerHubMetricScraperFunction> _logger;
    public DockerHubMetricScraperFunction(DockerHubClient dockerHubClient, IConfiguration configuration, ILogger<DockerHubMetricScraperFunction> logger)    {        Guard.NotNull(dockerHubClient, nameof(dockerHubClient));        Guard.NotNull(configuration, nameof(configuration));        Guard.NotNull(logger, nameof(logger));
        _dockerHubClient = dockerHubClient;        _configuration = configuration;        _logger = logger;    }
    [FunctionName("docker-hub-metric-scraper")]    public async Task Run([TimerTrigger("0 */15 * * * *")] TimerInfo timer)    {        _logger.LogInformation($"Starting to scrape Docker Hub metrics at {DateTime.UtcNow}");
        var repoName = _configuration["DOCKER_HUB_REPO_NAME"];        var imageName = _configuration["DOCKER_HUB_IMAGE_NAME"];
        var pullCount = await _dockerHubClient.GetImageMetricsAsync(repoName, imageName);
        var contextualInformation = new Dictionary<string, object>        {            {"Repo Name", repoName},            {"Image Name", imageName},            {"Image ID", $"{repoName}/{imageName}"}        };
        _logger.LogMetric("Image Pulls", pullCount, contextualInformation);    }}