I have a Azure Function app in .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 after configuring Serilog logs are getting logged twice in Application Insights.
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...
}
If I remove below code from startup.cs
, then it's not logging twice and only Serilog logs are shown, but I can't remove that code as I also need custom telemetry processor.
So basically when I register custom telemetry processor it also activating Microsoft Logger and that's why I'm getting logs twice as per my understating.
// 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();
How I can register custom telemetry processor with Serilog, without activating Microsoft logger?
Serilog logs are getting logged twice in Application Insights.
Below code worked for me and logged only required logs and there were no duplicates:
Function1.cs:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
namespace FunctionApp16
{
public class Function1
{
private readonly Rith_Logger<Function1> rith_lg;
public Function1(Rith_Logger<Function1> logger)
{
rith_lg = logger;
}
[FunctionName("Function1")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
{
rith_lg.LogInformation("Hello Rithwik Bojja !!!");
var rith_obj = new { Weight = 60, Height = 170 };
var rith_e = 24;
rith_lg.LogInformation("Hello the structered log is {@rith_obj} in {rith_e} age", rith_obj, rith_e);
return new OkObjectResult("Hello Rithwik Bojja !!!");
}
}
}
host.json:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"enableLiveMetricsFilters": true,
"samplingSettings": {
"isEnabled": false,
"excludedTypes": "Request"
}
},
"console": {
"isEnabled": true,
"logLevel": {
"default": "Information"
}
}
}
}
Here samplingSettings is set to false.
Startup.cs:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Serilog;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.Extensions.Logging;
using Microsoft.ApplicationInsights.Channel;
[assembly: FunctionsStartup(typeof(FunctionApp16.Startup))]
namespace FunctionApp16
{
internal class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var rith_tc = TelemetryConfiguration.CreateDefault();
rith_tc.ConnectionString = "InstrumentationKey=af34a9dc-f1df-4ff8-9ac9-6c1f0401ef4c;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=ff7a6";
var rith_dm = new DependencyTrackingTelemetryModule();
rith_dm.Initialize(rith_tc);
var rit_tpb = rith_tc.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
var rih_conf = builder.Services.BuildServiceProvider().GetService<IConfiguration>();
rit_tpb.Use(next => new CustomTelemetryProcessor(next, rih_conf));
rit_tpb.Build();
Log.Logger = new LoggerConfiguration()
.WriteTo.ApplicationInsights(rith_tc, TelemetryConverter.Traces)
.CreateLogger();
builder.Services.AddSingleton(rith_tc);
builder.Services.AddSingleton(typeof(Rith_Logger<>), typeof(AppLogger<>));
builder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddSerilog(Log.Logger, dispose: true);
});
}
}
public class CustomTelemetryProcessor : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
private readonly IConfiguration rith_conf;
public CustomTelemetryProcessor(ITelemetryProcessor next, IConfiguration configuration)
{
Next = next;
rith_conf = configuration;
}
public void Process(ITelemetry rit)
{
Next.Process(rit);
}
}
public interface Rith_Logger<T>
{
void LogInformation(string rith_ms, object rith_po, int rith);
void LogInformation(string rith_ms);
}
public class AppLogger<T> : Rith_Logger<T>
{
private readonly ILogger<T> rith_lg;
public AppLogger(ILogger<T> logger)
{
rith_lg = logger;
}
public void LogInformation(string rith_ms, object rith_po, int rith)
{
rith_lg.LogInformation(rith_ms, rith_po, rith);
}
public void LogInformation(string rith_ms)
{
rith_lg.LogInformation(rith_ms);
}
}
}
Output:
My pacakages in csproj:
<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>