0
votes

We've a bunch of azure functions log metrics against the execution context... you don't seem to be able to do this using the OOTB TraceWriter, or ILogger (at least in what i have seen) as there isn't an equivalent to what i assume would be named log.LogEvent()..

So.. this url (https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring#custom-telemetry-in-c-functions) shows a pattern for leveraging a TelemetryClient() inside of Azure Function to do the same, with examples for rolling your own for EventTelemetry() etc, however to ensure the correlation works you have to set the context for each thing you log:

var evt = new EventTelemetry("Function called");
evt.Context.Operation.Id = executionContext.InvocationId.ToString();
telemetryClient.TrackEvent(evt);

This all seems fairly logical, except i have a shared class (TelemetryManager) that helps creation of TelemetryClient() - so we don't have to repeat code in every, single, function that just news up a client with a series of additional settings.. this also implements a logging interface ITelemetry so that we have an interface later to unit test against, and lets you do.. (here using trace for simplicity):

static CustomTelemetryManager logger = new CustomTelemetryManager();
logger.Trace($"thing i want to trace: {x.value}");

logger.Trace() method simply does is call the telemetryClient.TrackTrace() method in the CustomTelemetryManager() class - some other methods are more complex.

Anyway, the interface is there so that when unit testing we can just do:

 // gets all the app insights key, and sets various other properties.        
static DebugLogger logger = new DebugLogger();
logger.Trace($"thing i want to trace: {x.value}");

and it will just Debug.WriteLine() instead of attempting to call out to AI

Question 1: Is there a "better" way to swap out Application Insights code for unit tests, as this is the only reason that we have this ITelemetry interface at all... to facilitate a dummy logger for unit tests.

Ultimately though, what i need to do, is give the telemetryClient.TrackTrace() the context of the invocation that is being executed, and the only way i have found to do that right now is, similar to the track event code above..

var trace = new TraceTelemetry($"i am a trace.");
trace.Context.Operation.Id = context.InvocationId.ToString();
logger.Trace(trace);

Because the TelemetryClient is shared over all functions, i need to apply the context to the metric directly before sending it to log..

Question 2: Is the only way i can do this.. something like:

public void TrackTrace(string msg, ExecutionContext ctx)
{
    var trace = new TraceTelemetry(msg);
    trace.Context.Operation.Id = ctx.InvocationId.ToString();
    client.TrackTrace(trace);
}

As this will mean modifying the interface, and then also mean for unit testing i shall also need to supply some sort of dummy context to the debug logger, which feels a bit clunky..

Somewhere in here, i think there is a simple tweak to simplify this needlessly confusing problem.. but i can't quite see the wood for the trees!

1
Your problem is not exactly clear to me. Maybe you could make your desired code more clear and highlight the exact issue? I don't see how setting the properties of trace prevents you from mocking TelemetryClient.Mikhail Shilkov
tbh @Mikhail i probably havn't explain it well, as i wrote that in a bit of a rush... i'll have another look - is there a way i should mock TelemetryClient ?m1nkeh
@m1nkeh did you ever find a good way to mock the TelemetryClient?Adam Stapleton
@AdamStapleton, i did not. It might be a lot easier now though.. i did this on Azure Functions v1.0 which didn't even support DI, and of course it's now on v3.0 which i think does??! I might take a look at this again, and update with a solution if i have time.m1nkeh
also @AdamStapleton i can't fully remember the actual gritty detail of this question... i didn't know much about Azure Functions when i wrote it, so it might be a really stupid question now! 😂m1nkeh

1 Answers

1
votes

You can take the context in your CustomTelemetryManager constructor assuming you create a new CustomTelemetryManager object per invocation.

In the CustomTelemetryManager implementation you can always use the same static TelemetryClient, but since your CustomTelemetryManager has the context already, it just adds it to every call of telemetryClient.TrackEvent() call you make.