Shri
Shri

Reputation: 367

Serilog structured log not working as expected in Azure Function using .NET 6 with Application Insights

I have a Azure Function App running on .NET 6, I am using Microsoft.Extension.Logging for logging and everything is working perfectly.

Now I have a new requirement to support structured logging, so I decided to use Serilog, but even after doing all configurations, structured logs are not showing up in application insights as expected.

This is my startup.cs configuration for Serilog:

public override void Configure(IFunctionsHostBuilder builder)
{
    var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
    telemetryConfiguration.ConnectionString = Settings.ApplicationInsightsConnectionString;

    // Create and initialize the dependency tracking module
    var dependencyModule = new DependencyTrackingTelemetryModule();
    dependencyModule.Initialize(telemetryConfiguration);

    // Create the custom telemetry processor
    var telemetryProcessorChainBuilder = telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
    var configuration = builder.Services.BuildServiceProvider().GetService<IConfiguration>();

    telemetryProcessorChainBuilder.Use(next => new CustomTelemetryProcessor(next, configuration));

    // Build the telemetry processor chain
    telemetryProcessorChainBuilder.Build();

    Log.Logger = new LoggerConfiguration()
                           .WriteTo.ApplicationInsights(telemetryConfiguration, TelemetryConverter.Traces)
                           .CreateLogger();

    builder.Services.AddSingleton(telemetryConfiguration);
    builder.Services.AddSingleton(typeof(IAppLogger<>), typeof(AppLogger<>));
  
    // rest of the code...
}

And this is the log I'm logging using AppLogger which uses Microsoft.Extension.Logging:

_logger.LogInformation("Log message {@LogMessage}", new LogMessage { ApplicationName = ApplicationDetails.ApplicationName, MethodName = AzureFunctionNames.Function1, IngressEvent = inputMessage.Payload.EventBody });

It's logging in Application Insight as serialised JSON of LogMessage, instead of logging in structured log format so that I should be able to query on each entity of LogMessage class.

What could be the reason that I am not able to see structured logs in Application Insights?

Providing Function App project packages with version,

<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.EventHubs" Version="5.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.ApplicationInsights" Version="2.22.0" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.60.3" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.3" />
<PackageReference Include="Serilog" Version="3.1.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="3.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />

Upvotes: 0

Views: 272

Answers (1)

Pavan
Pavan

Reputation: 1379

I have created Http trigger function with runtime stack .NET 6.0 version and configured Serilog and application insights in Startup.cs.

Function1.cs:

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;

namespace FunctionApp490028
{
    public class Function1
    {
        private readonly ILogger<Function1> _logger;

        public Function1(ILogger<Function1> logger)
        {
            _logger = logger;
        }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            _logger.LogInformation("Hello pavan");

            var Obj = new { Weight = 60, Height = 170 };
            var Obj1 = 24;

            _logger.LogInformation("Hello the structured log is {@Obj} in {Obj1} age", Obj, Obj1);

            return new OkObjectResult("Hello pavan");
        }
    }
}

Startup.cs

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.Extensions.Logging;
using Microsoft.ApplicationInsights.Channel;

[assembly: FunctionsStartup(typeof(FunctionApp490028.Startup))]

namespace FunctionApp490028
{
    internal class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // Configure Application Insights
            var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
            telemetryConfiguration.ConnectionString = "Your Appinsights conn-string";

            // Enable Dependency Tracking Telemetry Module
            var dependencyModule = new DependencyTrackingTelemetryModule();
            dependencyModule.Initialize(telemetryConfiguration);

            // Custom Telemetry Processor
            var telemetryProcessorChainBuilder = telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
            telemetryProcessorChainBuilder.Use(next => new CustomTelemetryProcessor(next));
            telemetryProcessorChainBuilder.Build();

            // Configure Serilog
            Log.Logger = new LoggerConfiguration()
                .WriteTo.ApplicationInsights(telemetryConfiguration, TelemetryConverter.Traces)
                .CreateLogger();

            // Add Serilog to Logging
            builder.Services.AddLogging(loggingBuilder =>
            {
                loggingBuilder.AddSerilog(Log.Logger, dispose: true);
            });

            // Register services
            builder.Services.AddSingleton(telemetryConfiguration);
            builder.Services.AddSingleton(typeof(ILogger<>), typeof(ILogger<>));
        }
    }

    public class CustomTelemetryProcessor : ITelemetryProcessor
    {
        private readonly ITelemetryProcessor _next;

        public CustomTelemetryProcessor(ITelemetryProcessor next)
        {
            _next = next;
        }

        public void Process(ITelemetry item)
        {
            _next.Process(item);
        }
    }
}

.cs proj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
      <PackageReference Include="Microsoft.ApplicationInsights" Version="2.22.0" />
      <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0" />
      <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
      <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.4.0" />
      <PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
      <PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
      <PackageReference Include="Serilog.Extensions.Logging" Version="3.0.2" />
      <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

By using above packages and Code able to get the structured logs successfully in Application insights. Check below:

Output:

enter image description here

enter image description here

Upvotes: 0

Related Questions