We should add another provider for our instrumentation so that we have a native integration with application insights.
@michaelstaib Do you have any suggestion on how you would do this without having this functionality built into Hot Chocolate?
I have implemented a solution that I think gets "close" to what I want. I am using the IDiagnosticObserver to instrument most things. Including:
HotChocolate.Execution.Query.StartHotChocolate.Execution.Query.StopHotChocolate.Execution.Query.ErrorHotChocolate.Execution.Validation.ErrorHotChocolate.Execution.Resolver.ErrorWhich is almost everything I would want. I get a Dependency entry for every query and appropriate errors.
However, I don't get an "overall" entry for each request (which would include other things like authentication/authorization work). I was looking at using a AddQueryRequestInterceptor to add this, but then realized I would need a "begin" and "end". At this point I am not sure where to go or if I can/should do more.
Just to clarify, my ideal would be a structure similar to the following.
Other work being any other dependencies that might happen as part of a request.
we will add more events to this. We currently work on the new execution engine and have more events on the list.
@mdressel I've managed to get request logging working with AI. The trick is to create and start the request operation in the HotChocolate.Execution.Query.Start method, then STORE the operation in a dictionary so that you can fetch it later during the HotChocolate.Execution.Query.Stop phase.
The HttpContext has a handy TraceIdentifier property, which makes for a great key for the dictionary.
So you can imagine something like this:
```c#
private Dictionary
[DiagnosticName("HotChocolate.Execution.Query.Start")]
public void BeginQueryExecute(IQueryContext context)
{
var httpContext = GetHttpContextFrom(context);
if (httpContext == null) return;
// Create a new request
var requestTelemetry = new RequestTelemetry()
{
Name = $"{httpContext.Request.Method} {httpContext.Request.GetUri().GetLeftPart(UriPartial.Path)}",
Url = new Uri(httpContext.Request.GetUri().AbsoluteUri)
};
requestTelemetry.Context.Operation.Id = GetOperationIdFrom(httpContext);
requestTelemetry.Context.Operation.ParentId = GetOperationIdFrom(httpContext);
requestTelemetry.Properties.Add("GraphQL Query", context.Request.Query.ToString());
// Start the operation, and store it in the dictionary
var operation = _telemetryClient.StartOperation(requestTelemetry);
_inFlightOperations.Add(GetOperationIdFrom(httpContext), operation);
}
[DiagnosticName("HotChocolate.Execution.Query.Stop")]
public void EndQueryExecute(IQueryContext context, IExecutionResult result)
{
var httpContext = GetHttpContextFrom(context);
if (httpContext == null) return;
if (_inFlightOperations.ContainsKey(GetOperationIdFrom(httpContext)))
{
var operation = _inFlightOperations[GetOperationIdFrom(httpContext)];
_inFlightOperations.Remove(GetOperationIdFrom(httpContext));
// handle any final request logging here (GraphQL query errors, success, etc)
// e.g:
operation.Telemetry.Success = true;
operation.Telemetry.ResponseCode = "200";
// Then stop the operation. This completes the request.
_telemetryClient.StopOperation(operation);
}
}
The two helper methods in that code simply fetch the httpcontext from the IQueryContext, and return the trace identifier:
```c#
private HttpContext GetHttpContextFrom(IQueryContext context)
{
// This method is used to enable start/stop events for query.
if (!context.ContextData.ContainsKey("HttpContext"))
return null;
return context.ContextData["HttpContext"] as HttpContext;
}
private string GetOperationIdFrom(HttpContext context)
{
return context.TraceIdentifier;
}
I've included the query in the request metadata (custom properties), but you can extend it to include whatever you like. In my implementation I've appended the request URI to include the IQueryContext's QueryHash, which allows AI to separate the requests by query, rather than everything just being logged into the /graph endpoint.
Similarly, you need to handle the other events:
HotChocolate.Execution.Query.Error
HotChocolate.Execution.Validation.Error
HotChocolate.Execution.Resolver.Error
in a similar way to create a full picture in AI. Just make sure to lookup and stop the operation in each of these error methods.
We also simplified the whole story around this with the current 11 preview versions. For this, I will close this issue.
Excellent - I look forward to upgrading ;)
@michaelstaib can you clarify what was simplified and how?
@rsantosdev we originally built all the instrumentation on top of DiagnosticSource and also originally isolated the execution services from the application services which made implementing providers not so nice. With version 11 we have now introduced a new abstraction for execution events. We provide now more instrumentation events and easier implementation. While we are not providing a direct integration into ApplicationInsights it is now very simple to implement and you can choose how much telemetry you want.