Skip tracing for introspection queries #841
This commit is contained in:
parent
5b49a9d891
commit
13a66a5013
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# [4.0.15] 2022-10-01
|
||||
|
||||
- Skip tracing for introspection queries. [#841](https://github.com/async-graphql/async-graphql/issues/841)
|
||||
|
||||
# [4.0.14] 2022-09-25
|
||||
|
||||
- Implement a simple approach to using the link directive. [#1060](https://github.com/async-graphql/async-graphql/pull/1060)
|
||||
|
|
|
@ -70,7 +70,7 @@ fast_chemail = { version = "0.9.6", optional = true }
|
|||
hashbrown = { version = "0.12.0", optional = true }
|
||||
iso8601-duration = { version = "0.1.0", optional = true }
|
||||
log = { version = "0.4.16", optional = true }
|
||||
opentelemetry = { version = "0.17.0", optional = true, default-features = false, features = [
|
||||
opentelemetry = { version = "0.18.0", optional = true, default-features = false, features = [
|
||||
"trace",
|
||||
] }
|
||||
rust_decimal = { version = "1.14.3", optional = true }
|
||||
|
|
|
@ -336,6 +336,7 @@ pub fn generate(
|
|||
return_type: &<<#stream_ty as #crate_name::futures_util::stream::Stream>::Item as #crate_name::OutputType>::qualified_type_name(),
|
||||
name: field.node.name.node.as_str(),
|
||||
alias: field.node.alias.as_ref().map(|alias| alias.node.as_str()),
|
||||
is_for_introspection: false,
|
||||
};
|
||||
let resolve_fut = async {
|
||||
#crate_name::OutputType::resolve(&msg, &ctx_selection_set, &*field)
|
||||
|
|
2
examples
2
examples
|
@ -1 +1 @@
|
|||
Subproject commit e7f936e6b675b6b237c137eb8690ca49742f2b5b
|
||||
Subproject commit bb0fa782053271096cf8c61eaf6e670b9d08ae15
|
|
@ -236,6 +236,8 @@ impl<'a> std::iter::FusedIterator for Parents<'a> {}
|
|||
pub struct ContextBase<'a, T> {
|
||||
/// The current path node being resolved.
|
||||
pub path_node: Option<QueryPathNode<'a>>,
|
||||
/// If `true` means the current field is for introspection.
|
||||
pub(crate) is_for_introspection: bool,
|
||||
#[doc(hidden)]
|
||||
pub item: T,
|
||||
#[doc(hidden)]
|
||||
|
@ -287,6 +289,7 @@ impl QueryEnv {
|
|||
) -> ContextBase<'a, T> {
|
||||
ContextBase {
|
||||
path_node,
|
||||
is_for_introspection: false,
|
||||
item,
|
||||
schema_env,
|
||||
query_env: self,
|
||||
|
@ -319,6 +322,7 @@ impl<'a, T> ContextBase<'a, T> {
|
|||
parent: self.path_node.as_ref(),
|
||||
segment: QueryPathSegment::Name(&field.node.response_key().node),
|
||||
}),
|
||||
is_for_introspection: self.is_for_introspection,
|
||||
item: field,
|
||||
schema_env: self.schema_env,
|
||||
query_env: self.query_env,
|
||||
|
@ -332,6 +336,7 @@ impl<'a, T> ContextBase<'a, T> {
|
|||
) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
||||
ContextBase {
|
||||
path_node: self.path_node,
|
||||
is_for_introspection: self.is_for_introspection,
|
||||
item: selection_set,
|
||||
schema_env: self.schema_env,
|
||||
query_env: self.query_env,
|
||||
|
@ -605,6 +610,7 @@ impl<'a> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
|||
parent: self.path_node.as_ref(),
|
||||
segment: QueryPathSegment::Index(idx),
|
||||
}),
|
||||
is_for_introspection: self.is_for_introspection,
|
||||
item: self.item,
|
||||
schema_env: self.schema_env,
|
||||
query_env: self.query_env,
|
||||
|
|
|
@ -125,6 +125,9 @@ pub struct ResolveInfo<'a> {
|
|||
|
||||
/// Current field alias
|
||||
pub alias: Option<&'a str>,
|
||||
|
||||
/// If `true` means the current field is for introspection.
|
||||
pub is_for_introspection: bool,
|
||||
}
|
||||
|
||||
type RequestFut<'a> = &'a mut (dyn Future<Output = Response> + Send + Unpin);
|
||||
|
|
|
@ -168,24 +168,35 @@ where
|
|||
info: ResolveInfo<'_>,
|
||||
next: NextResolve<'_>,
|
||||
) -> ServerResult<Option<Value>> {
|
||||
let attributes = vec![
|
||||
KEY_PARENT_TYPE.string(info.parent_type.to_string()),
|
||||
KEY_RETURN_TYPE.string(info.return_type.to_string()),
|
||||
];
|
||||
let span = self
|
||||
.tracer
|
||||
.span_builder(info.path_node.to_string())
|
||||
.with_kind(SpanKind::Server)
|
||||
.with_attributes(attributes)
|
||||
.start(&*self.tracer);
|
||||
next.run(ctx, info)
|
||||
.with_context(OpenTelemetryContext::current_with_span(span))
|
||||
.inspect_err(|err| {
|
||||
let current_cx = OpenTelemetryContext::current();
|
||||
current_cx
|
||||
.span()
|
||||
.add_event("error".to_string(), vec![KEY_ERROR.string(err.to_string())]);
|
||||
})
|
||||
.await
|
||||
let span = if !info.is_for_introspection {
|
||||
let attributes = vec![
|
||||
KEY_PARENT_TYPE.string(info.parent_type.to_string()),
|
||||
KEY_RETURN_TYPE.string(info.return_type.to_string()),
|
||||
];
|
||||
Some(
|
||||
self.tracer
|
||||
.span_builder(info.path_node.to_string())
|
||||
.with_kind(SpanKind::Server)
|
||||
.with_attributes(attributes)
|
||||
.start(&*self.tracer),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let fut = next.run(ctx, info).inspect_err(|err| {
|
||||
let current_cx = OpenTelemetryContext::current();
|
||||
current_cx
|
||||
.span()
|
||||
.add_event("error".to_string(), vec![KEY_ERROR.string(err.to_string())]);
|
||||
});
|
||||
|
||||
match span {
|
||||
Some(span) => {
|
||||
fut.with_context(OpenTelemetryContext::current_with_span(span))
|
||||
.await
|
||||
}
|
||||
None => fut.await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,22 +133,29 @@ impl Extension for TracingExtension {
|
|||
info: ResolveInfo<'_>,
|
||||
next: NextResolve<'_>,
|
||||
) -> ServerResult<Option<Value>> {
|
||||
let span = span!(
|
||||
target: "async_graphql::graphql",
|
||||
Level::INFO,
|
||||
"field",
|
||||
path = %info.path_node,
|
||||
parent_type = %info.parent_type,
|
||||
return_type = %info.return_type,
|
||||
);
|
||||
next.run(ctx, info)
|
||||
.map_err(|err| {
|
||||
tracinglib::info!(target: "async_graphql::graphql",
|
||||
error = %err.message,
|
||||
"error");
|
||||
err
|
||||
})
|
||||
.instrument(span)
|
||||
.await
|
||||
let span = if !info.is_for_introspection {
|
||||
Some(span!(
|
||||
target: "async_graphql::graphql",
|
||||
Level::INFO,
|
||||
"field",
|
||||
path = %info.path_node,
|
||||
parent_type = %info.parent_type,
|
||||
return_type = %info.return_type,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let fut = next.run(ctx, info).inspect_err(|err| {
|
||||
tracinglib::info!(
|
||||
target: "async_graphql::graphql",
|
||||
error = %err.message,
|
||||
"error",
|
||||
);
|
||||
});
|
||||
match span {
|
||||
Some(span) => fut.instrument(span).await,
|
||||
None => fut.await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,6 +239,7 @@ impl<'a> Fields<'a> {
|
|||
.alias
|
||||
.as_ref()
|
||||
.map(|alias| alias.node.as_str()),
|
||||
is_for_introspection: ctx_field.is_for_introspection,
|
||||
};
|
||||
|
||||
let resolve_fut = root.resolve_field(&ctx_field);
|
||||
|
@ -263,6 +264,7 @@ impl<'a> Fields<'a> {
|
|||
{
|
||||
let ctx_directive = ContextBase {
|
||||
path_node: ctx_field.path_node,
|
||||
is_for_introspection: false,
|
||||
item: directive,
|
||||
schema_env: ctx_field.schema_env,
|
||||
query_env: ctx_field.query_env,
|
||||
|
|
|
@ -26,6 +26,7 @@ pub async fn resolve_list<'a, T: OutputType + 'a>(
|
|||
return_type: &T::qualified_type_name(),
|
||||
name: field.node.name.node.as_str(),
|
||||
alias: field.node.alias.as_ref().map(|alias| alias.node.as_str()),
|
||||
is_for_introspection: ctx_idx.is_for_introspection,
|
||||
};
|
||||
let resolve_fut = async {
|
||||
OutputType::resolve(&item, &ctx_idx, field)
|
||||
|
|
|
@ -609,6 +609,7 @@ where
|
|||
// execute
|
||||
let ctx = ContextBase {
|
||||
path_node: None,
|
||||
is_for_introspection: false,
|
||||
item: &env.operation.node.selection_set,
|
||||
schema_env: &self.env,
|
||||
query_env: &env,
|
||||
|
|
|
@ -34,7 +34,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
|||
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
|
||||
) {
|
||||
if ctx.item.node.name.node == "__schema" {
|
||||
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
ctx_obj.is_for_introspection = true;
|
||||
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
|
||||
return OutputType::resolve(
|
||||
&__Schema::new(&ctx.schema_env.registry, &visible_types),
|
||||
|
@ -45,7 +46,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
|||
.map(Some);
|
||||
} else if ctx.item.node.name.node == "__type" {
|
||||
let (_, type_name) = ctx.param_value::<String>("name", None)?;
|
||||
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
ctx_obj.is_for_introspection = true;
|
||||
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
|
||||
return OutputType::resolve(
|
||||
&ctx.schema_env
|
||||
|
@ -81,7 +83,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
|||
.await?;
|
||||
return Ok(Some(Value::List(res)));
|
||||
} else if ctx.item.node.name.node == "_service" {
|
||||
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
||||
ctx_obj.is_for_introspection = true;
|
||||
return OutputType::resolve(
|
||||
&Service {
|
||||
sdl: Some(
|
||||
|
|
Loading…
Reference in New Issue