Create telemetry properties inside a IServiceScope
See original GitHub issueI have a WebJob running an infinite loop. For each iteration of this loop, I want to log some informations (traces, exceptions and one request) to AppInsights. And I need that each of those informations, for a same iteration loop, share the same correlationId (to be able to group all logs in the azure portal).
Here the code I use to declare AppInsights :
this.hostBuilder = new HostBuilder()
.ConfigureLogging((context, builder) =>
{
builder.AddConfiguration(context.Configuration.GetSection("Logging"))
AddApplicationInsights(options => options.InstrumentationKey = context.Configuration["ApplicationInsightsInstrumentationKey"]);
});
Then I have a hosted service which run multiples tasks, and an infinite loop in each task :
internal class MyHostedService : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
this.taskCancellationToken = new CancellationTokenSource();
foreach (var xxx in yyy)
{
this.tasks.Add(Task.Run(async () =>
{
while (!this.taskCancellationToken.IsCancellationRequested)
{
using (var scope = this.serviceScopeFactory.CreateScope())
{
[...]
}
}
}
}
}
}
So each iteration has its own scope.
Then, to be able to log a request, I create an operation based on the TelemetryClient
:
using(var operationHolder = this.telemetryClient.StartOperation<RequestTelemetry>("myoperation"))
{
try
{
[...]
operationHolder.Telemetry.Success = true;
}
catch(Exception e)
{
operationHolder.Telemetry.Success = false;
}
}
And I also add some logs:
var logger = scope.ServiceProvider.GetRequiredService<ILogger<MyHostedService>>();
logger.LogInformation("Process ended successfully");
I want that both my logger and operationHolder share the same properties (mainly the correlationId which is a Guid).
My operationHolder properties are initialized in that way and it’s working correctly :
operationHolder.Telemetry.Properties["correlationId"] = correlationId.ToString();
The ApplicationInsightsLogger, which is used when I call logger.LogInformation
, creates a TraceTelemetry which use the TelemetryClient (but not the same telemetry as the operationholder) to get properties to add to AppInsights. My problem here is that the TelemetryClient is declared as Singleton. So I can declare GlobalProperties but not Properties specific to each iteration of my loop.
My only workaround is to create LoggerScope and add my properties in the state :
var loggerScope = logger.BeginScope(new Dictionary<string, object>
{
["correlationId"] = correlationId
});
The only problem here is that my correlationId appears as prop___correlationId
, I think to avoid collision between state and telemetry properties.
Expected behavior
Be able to declare scoped properties inside a TelemetryClient.
Actual behavior
TelemetryClient is a Singleton so I can’t declare properties for a scope.
Known workarounds
As exposed previously, use a BeginScope in addition of StartOperation.
Related information
Provide any related information
- Microsoft.Azure.WebJobs.Logging.ApplicationInsights : 3.0.6
- Microsoft.Azure.WebJobs.Extensions : 3.0.2
Issue Analytics
- State:
- Created 4 years ago
- Reactions:3
- Comments:13 (1 by maintainers)
Top GitHub Comments
Ultimately – you want that correllationId to be attached to all telemetry inside that operation, but without the
prop__
prefix?One thing you may be able to do is take advantage of Activity and use an
ITelemetryInitializer
to stick your correllation id onto your telemetry.If I’m undnerstanding your scenario correctly, I wrote an
IHostedService
like this:Notice the
Activity.Current
line.Then you can write an
ITelemetryInitializer
that looks atActivity.Current
, pulls out the relevant details, and applies them directly to the telemetry however you want.Nice one…I will not harp on about it but I still think using
RequestTelemetry
inside theIHostedService
is a little bit of a misuse. But I totally see your predicament. 😃