Stefan Holm Olsen

Telemetry correlation for Scheduled Jobs in Optimizely

In my last blog post, I presented a way to correlate Application Insights telemetry to those of us who use Hangfire for running jobs.

But even if you make your scheduled jobs based on Optimizely's scheduled job framework, you can still correlate all the telemetry generated while running a job.

I created a simple class, JobTelemetryScope, which easily wraps an operation telemetry for the duration of the job. It looks like this:

using System;
using EPiServer.ServiceLocation;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;

namespace SampleSite.ScheduledJobs;

public sealed class JobTelemetryScope : IDisposable
{
private readonly Injected<TelemetryClient> _telemetryClientInjected;
private readonly IOperationHolder<RequestTelemetry> _operationHolder;

public bool Success { get; set; }

public JobTelemetryScope(string jobName)
{
var telemetryClient = _telemetryClientInjected.Service;
if (!telemetryClient.IsEnabled())
{
return;
}

_operationHolder = telemetryClient.StartOperation<RequestTelemetry>($"JOB {jobName}");
}

public void Dispose()
{
if (_operationHolder == null)
{
return;
}

_operationHolder.Telemetry.Success = Success;
_operationHolder.Dispose();
}
}

This can then be used in a custom scheduled job, like this:

using System;
using EPiServer.PlugIn;
using EPiServer.Scheduler;

namespace SampleSite.ScheduledJobs;

[ScheduledPlugIn(
    DisplayName = "Test job",
    GUID = "F62C2AC3-A775-40E1-8F7D-62056E6E7C5E")]
public class TestJob : ScheduledJobBase
{
    public TestJob()
    {
        IsStoppable = true;
    }

    public override string Execute()
    {
        // Use in a try-catch-finally block.
        var telemetryScope = new JobTelemetryScope("TestJob");
        try
        {
            // TODO: Add your own code here. Remember to set Success to true.
            telemetryScope.Success = true;
        }
        catch (Exception ex)
        {
            // Success is false by default. No need to set it explicitly.
            return "Not OK";
        }
        finally
        {
            // End the telemetry correlation scope.
            telemetryScope.Dispose();
        }

        // Or a using statement.
        using var telemetryScope2 = new JobTelemetryScope("TestJob");
        try
        {
            // TODO: Add your own code here. Remember to set Success to true.
            telemetryScope2.Success = true;
        }
        catch (Exception ex)
        {
            return "Not OK";
        }

        return "OK";
    }
}

Be aware that this only works for your own scheduled jobs, where you can add the scope block. It cannot (yet) be applied to built-in Optimizely scheduled jobs.