-
Notifications
You must be signed in to change notification settings - Fork 242
Enhance GraphQL OTEL instrumentation with custom metrics and traces #2673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
10a180c
0b1052a
c77736f
af25287
59737fa
2373499
0ba881b
f740a79
84bd1ef
252a656
34e13f6
31a4af4
1978033
54d6abe
0cb7a79
f294f49
9309980
2b0fe5b
94e2e56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
using System.Diagnostics; | ||
using System.Globalization; | ||
using System.Text.Json; | ||
using Azure.DataApiBuilder.Config.ObjectModel; | ||
using Azure.DataApiBuilder.Core.Configurations; | ||
using Azure.DataApiBuilder.Core.Models; | ||
using Azure.DataApiBuilder.Core.Resolvers; | ||
using Azure.DataApiBuilder.Core.Resolvers.Factories; | ||
using Azure.DataApiBuilder.Core.Telemetry; | ||
using Azure.DataApiBuilder.Service.GraphQLBuilder; | ||
using Azure.DataApiBuilder.Service.GraphQLBuilder.CustomScalars; | ||
using Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes; | ||
|
@@ -17,6 +19,7 @@ | |
using HotChocolate.Resolvers; | ||
using HotChocolate.Types.NodaTime; | ||
using NodaTime.Text; | ||
using Kestral = Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpMethod; | ||
|
||
namespace Azure.DataApiBuilder.Service.Services | ||
{ | ||
|
@@ -50,6 +53,8 @@ public ExecutionHelper( | |
/// </param> | ||
public async ValueTask ExecuteQueryAsync(IMiddlewareContext context) | ||
{ | ||
using Activity? activity = StartQueryActivity(context); | ||
|
||
string dataSourceName = GraphQLUtils.GetDataSourceNameFromGraphQLContext(context, _runtimeConfigProvider.GetConfig()); | ||
DataSource ds = _runtimeConfigProvider.GetConfig().GetDataSourceFromDataSourceName(dataSourceName); | ||
IQueryEngine queryEngine = _queryEngineFactory.GetQueryEngine(ds.DatabaseType); | ||
|
@@ -91,6 +96,8 @@ public async ValueTask ExecuteQueryAsync(IMiddlewareContext context) | |
/// </param> | ||
public async ValueTask ExecuteMutateAsync(IMiddlewareContext context) | ||
{ | ||
using Activity? activity = StartQueryActivity(context); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is the end of this activity marked? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on Tomasso's PR, I thought that we did not have to explicitly end the activity. Or am I wrong about that? |
||
|
||
string dataSourceName = GraphQLUtils.GetDataSourceNameFromGraphQLContext(context, _runtimeConfigProvider.GetConfig()); | ||
DataSource ds = _runtimeConfigProvider.GetConfig().GetDataSourceFromDataSourceName(dataSourceName); | ||
IQueryEngine queryEngine = _queryEngineFactory.GetQueryEngine(ds.DatabaseType); | ||
|
@@ -127,6 +134,31 @@ public async ValueTask ExecuteMutateAsync(IMiddlewareContext context) | |
} | ||
} | ||
|
||
/// <summary> | ||
/// Starts the activity for the query | ||
/// </summary> | ||
/// <param name="context"> | ||
/// The middleware context. | ||
/// </param> | ||
private Activity? StartQueryActivity(IMiddlewareContext context) | ||
{ | ||
string route = _runtimeConfigProvider.GetConfig().GraphQLPath.Trim('/'); | ||
Kestral method = Kestral.Post; | ||
|
||
Activity? activity = TelemetryTracesHelper.DABActivitySource.StartActivity($"{method} /{route}"); | ||
|
||
if (activity is not null) | ||
{ | ||
string dataSourceName = GraphQLUtils.GetDataSourceNameFromGraphQLContext(context, _runtimeConfigProvider.GetConfig()); | ||
DataSource ds = _runtimeConfigProvider.GetConfig().GetDataSourceFromDataSourceName(dataSourceName); | ||
activity.TrackQueryActivityStarted( | ||
databaseType: ds.DatabaseType, | ||
dataSourceName: dataSourceName); | ||
} | ||
|
||
return activity; | ||
} | ||
|
||
/// <summary> | ||
/// Represents a pure resolver for a leaf field. | ||
/// This resolver extracts the field value from the json object. | ||
|
@@ -425,7 +457,7 @@ internal static IType InnerMostType(IType type) | |
|
||
public static InputObjectType InputObjectTypeFromIInputField(IInputField field) | ||
{ | ||
return (InputObjectType)(InnerMostType(field.Type)); | ||
return (InputObjectType)InnerMostType(field.Type); | ||
} | ||
|
||
/// <summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you test this? Could you please add it to the description?
Can we add some integration tests as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done as part of the local testing. I will try and add some integration tests as well.