Интеграция Azure Application Insights с API GraphQL — платформа HotChocolate

#.net #azure #azure-application-insights #hotchocolate

Вопрос:

Есть ли какой-либо способ интегрировать Azure App Insights с платформой Hotchoclate graphql? В настоящее время существует несколько способов совместного взлома.

Каков наилучший способ получить всю информацию о приложениях с разбивкой по запросам в приложении, как это было бы с помощью REST api

Ответ №1:

В HC вам нужно подключиться к прослушивателю диагностических событий, чтобы получить представление о конвейере, и оттуда вы можете подключаться к различным событиям и регистрировать телеметрию. Главное здесь-убедиться, что вы различаете запрос с именем запроса, чтобы он правильно отображался в app insights, в остальном все будет на конечной точке /graphql

 public class AppInsightsDiagnosticEventListener : ExecutionDiagnosticEventListener {  private readonly TelemetryClient _telemetryClient;   public AppInsightsDiagnosticEventListener(TelemetryClient telemetryClient) =gt; _telemetryClient = telemetryClient;   public override IDisposable ExecuteRequest(IRequestContext context)  {  var httpContext = GetHttpContextFrom(context);  if (httpContext == null)  return EmptyScope;   //During debugging every playground action will come here so we want this while debugging  #if DEBUG  if (context.Request.OperationName == "IntrospectionQuery")  return EmptyScope;  #endif   //Create a new telemetry request  var operationPath = $"{context.Request.OperationName ?? "UnknownOperation"} - {context.Request.QueryHash}";  var requestTelemetry = new RequestTelemetry()  {  Name = $"/graphql{operationPath}",  Url = new Uri(httpContext.Request.GetUri().AbsoluteUri   operationPath),  };   requestTelemetry.Context.Operation.Name = $"POST /graphql/{operationPath}";  requestTelemetry.Context.Operation.Id = GetOperationIdFrom(httpContext);  requestTelemetry.Context.Operation.ParentId = GetOperationIdFrom(httpContext);  requestTelemetry.Context.User.AuthenticatedUserId = httpContext.User.Identity?.Name ?? "Not authenticated";   if (context.Request.Query != null)  requestTelemetry.Properties.Add("GraphQL Query", context.Request.Query.ToString());   var operation = _telemetryClient.StartOperation(requestTelemetry);  return new ScopeWithEndAction(() =gt; OnEndRequest(context, operation));  }   private void OnEndRequest(IRequestContext context, IOperationHolderlt;RequestTelemetrygt; operation)  {  var httpContext = GetHttpContextFrom(context);  operation.Telemetry.Success = httpContext.Response.StatusCode is gt;= 200 and lt;= 299;  operation.Telemetry.ResponseCode = httpContext.Response.StatusCode.ToString();   if (context.Exception != null)  {  operation.Telemetry.Success = false;  operation.Telemetry.ResponseCode = "500";  _telemetryClient.TrackException(context.Exception);  }   if (context.ValidationResult?.HasErrors ?? false)  {  operation.Telemetry.Success = false;  operation.Telemetry.ResponseCode = "400";  }   if (context.Result?.Errors != null)  {  foreach (var error in context.Result.Errors)  {  if (error.Exception != null)  {  operation.Telemetry.Success = false;  _telemetryClient.TrackException(error.Exception);  }  }  }   _telemetryClient.StopOperation(operation);  }   public override void RequestError(IRequestContext context, Exception exception)  {  _telemetryClient.TrackException(exception);  base.RequestError(context, exception);  }   public override void ValidationErrors(IRequestContext context, IReadOnlyListlt;IErrorgt; errors)  {  foreach (var error in errors)  {  _telemetryClient.TrackTrace("GraphQL validation error: "   error.Message, SeverityLevel.Warning);  }  base.ValidationErrors(context, errors);  }   private HttpContext GetHttpContextFrom(IRequestContext 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) =gt; context.TraceIdentifier; }  internal class ScopeWithEndAction : IDisposable {  private readonly Action _disposeAction;   public ScopeWithEndAction(Action disposeAction) =gt; _disposeAction = disposeAction;   public void Dispose() =gt; _disposeAction.Invoke(); }  

И в запуске

 services.AddApplicationInsightsTelemetry();  services.AddGraphQLServer()  .AddDiagnosticEventListenerlt;AppInsightsDiagnosticEventListenergt;((sp) =gt; new AppInsightsDiagnosticEventListener(sp.GetServicelt;TelemetryClientgt;()));