I’ve been playing around with telemetry sampling in order to avoid hitting App Insights daily logs cap. Ideally, I want to apply sampling to everything but exclude exceptions and preserve related traces (same operation id) for the exceptions.
I’ve created a sample console app to test things and so far I can successfully sample and preserve exceptions. But related traces get sampled as well.
I looked at implementing custom ITelemetryProcessor
, but it processes one entry at a time. So I’m not sure if it is even possible with custom processor. Maybe there is something that help achieve desired behavior.
The Program.cs
code is below
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
const string appInsightConnString = "<connection string>";
const double samplingPercentage = 50;
var services = new ServiceCollection();
// add context
var context = new Context();
services.AddSingleton(context);
// configure application insights
services.AddApplicationInsightsTelemetryWorkerService(
(options) =>
{
// disable adaptive sampling
options.EnableAdaptiveSampling = false;
options.ConnectionString = appInsightConnString;
});
// configure logging
services.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.Services.AddSingleton<ILoggerProvider, ContextApplicationInsightsLoggerProvider>();
loggingBuilder.AddConsole();
});
var serviceProvider = services.BuildServiceProvider();
// setup sampling
var telemetryConfiguration = serviceProvider.GetRequiredService<TelemetryConfiguration>();
var telemetryBuilder = telemetryConfiguration.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
telemetryBuilder.UseSampling(samplingPercentage, excludedTypes: "Exception");
telemetryBuilder.Build();
// get logger
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
// do something important
DoWork(context, logger);
// explicitly call Flush() followed by sleep is required in console apps.
// this is to ensure that even if application terminates, telemetry is sent to the back-end.
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();
telemetryClient.Flush();
Task.Delay(10000).Wait();
Console.WriteLine("Flushed. Press any key to exit");
Console.ReadKey();
static void DoWork(Context context, ILogger logger)
{
const int iterations = 50;
const int errors = 15;
// session Id to filter logs
var sessionId = Guid.NewGuid().ToString();
Console.WriteLine($"Session Id: {sessionId}");
// randomize errors
var random = new Random();
var errorsHash = new HashSet<int>();
while (errorsHash.Count < errors)
{
errorsHash.Add(random.Next(0, iterations));
}
// log
for (var i = 0; i < iterations; i++)
{
context.CorrelationId = Guid.NewGuid().ToString();
logger.LogInformation($"Begin operation: {context.CorrelationId}. Session Id: {sessionId}");
if (errorsHash.Contains(i))
logger.LogError(new Exception("test ex"), $"Error operation: {context.CorrelationId}. Session Id: {sessionId}");
logger.LogInformation($"End operation: {context.CorrelationId}. Session Id: {sessionId}");
}
}
2
Answers
Just wanted to post what I've came up so far after looking more into implementing custom telemetry processor. The idea to keep accumulating buckets of telemetry for some time before making sampling decision. It creates a bit of lag, but that's the best I've got so far.
The code below uses Microsoft Application Insights for monitoring and logging within a console application, utilizing the
ITelemetryProcessor
interface from Application Insights. TheRelatedTelemetryProcessor
class implements theITelemetryProcessor
and preserve related entries along with excluded items when using Application InsightsI referred to this doc for filtering and preprocessing in the Application Insights SDK Azure Monitor.
RelatedTelemetryProcessor
) is used, which preserves all telemetry items related to exceptions based on their operation ID. Sampling is also employed while excluding exceptions (excludedTypes: "Exception"
) with the default telemetry processor chain.To ensure that related traces are preserved when there is an exception while applying sampling to other telemetry items, you can adjust your custom telemetry processor to handle both cases properly.
In your
Main
method:The custom
ITelemetryProcessor
processes one telemetry item at a time, which can make it challenging to ensure that related traces are preserved when exceptions occur.