Skip tracing for introspection queries #841
This commit is contained in:
parent
f1bac10120
commit
57d592b250
|
@ -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/),
|
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).
|
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
|
# [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)
|
- 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 }
|
hashbrown = { version = "0.12.0", optional = true }
|
||||||
iso8601-duration = { version = "0.1.0", optional = true }
|
iso8601-duration = { version = "0.1.0", optional = true }
|
||||||
log = { version = "0.4.16", 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",
|
"trace",
|
||||||
] }
|
] }
|
||||||
rust_decimal = { version = "1.14.3", optional = true }
|
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(),
|
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(),
|
name: field.node.name.node.as_str(),
|
||||||
alias: field.node.alias.as_ref().map(|alias| alias.node.as_str()),
|
alias: field.node.alias.as_ref().map(|alias| alias.node.as_str()),
|
||||||
|
is_for_introspection: false,
|
||||||
};
|
};
|
||||||
let resolve_fut = async {
|
let resolve_fut = async {
|
||||||
#crate_name::OutputType::resolve(&msg, &ctx_selection_set, &*field)
|
#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> {
|
pub struct ContextBase<'a, T> {
|
||||||
/// The current path node being resolved.
|
/// The current path node being resolved.
|
||||||
pub path_node: Option<QueryPathNode<'a>>,
|
pub path_node: Option<QueryPathNode<'a>>,
|
||||||
|
/// If `true` means the current field is for introspection.
|
||||||
|
pub(crate) is_for_introspection: bool,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub item: T,
|
pub item: T,
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -287,6 +289,7 @@ impl QueryEnv {
|
||||||
) -> ContextBase<'a, T> {
|
) -> ContextBase<'a, T> {
|
||||||
ContextBase {
|
ContextBase {
|
||||||
path_node,
|
path_node,
|
||||||
|
is_for_introspection: false,
|
||||||
item,
|
item,
|
||||||
schema_env,
|
schema_env,
|
||||||
query_env: self,
|
query_env: self,
|
||||||
|
@ -319,6 +322,7 @@ impl<'a, T> ContextBase<'a, T> {
|
||||||
parent: self.path_node.as_ref(),
|
parent: self.path_node.as_ref(),
|
||||||
segment: QueryPathSegment::Name(&field.node.response_key().node),
|
segment: QueryPathSegment::Name(&field.node.response_key().node),
|
||||||
}),
|
}),
|
||||||
|
is_for_introspection: self.is_for_introspection,
|
||||||
item: field,
|
item: field,
|
||||||
schema_env: self.schema_env,
|
schema_env: self.schema_env,
|
||||||
query_env: self.query_env,
|
query_env: self.query_env,
|
||||||
|
@ -332,6 +336,7 @@ impl<'a, T> ContextBase<'a, T> {
|
||||||
) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
) -> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
||||||
ContextBase {
|
ContextBase {
|
||||||
path_node: self.path_node,
|
path_node: self.path_node,
|
||||||
|
is_for_introspection: self.is_for_introspection,
|
||||||
item: selection_set,
|
item: selection_set,
|
||||||
schema_env: self.schema_env,
|
schema_env: self.schema_env,
|
||||||
query_env: self.query_env,
|
query_env: self.query_env,
|
||||||
|
@ -605,6 +610,7 @@ impl<'a> ContextBase<'a, &'a Positioned<SelectionSet>> {
|
||||||
parent: self.path_node.as_ref(),
|
parent: self.path_node.as_ref(),
|
||||||
segment: QueryPathSegment::Index(idx),
|
segment: QueryPathSegment::Index(idx),
|
||||||
}),
|
}),
|
||||||
|
is_for_introspection: self.is_for_introspection,
|
||||||
item: self.item,
|
item: self.item,
|
||||||
schema_env: self.schema_env,
|
schema_env: self.schema_env,
|
||||||
query_env: self.query_env,
|
query_env: self.query_env,
|
||||||
|
|
|
@ -125,6 +125,9 @@ pub struct ResolveInfo<'a> {
|
||||||
|
|
||||||
/// Current field alias
|
/// Current field alias
|
||||||
pub alias: Option<&'a str>,
|
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);
|
type RequestFut<'a> = &'a mut (dyn Future<Output = Response> + Send + Unpin);
|
||||||
|
|
|
@ -168,24 +168,35 @@ where
|
||||||
info: ResolveInfo<'_>,
|
info: ResolveInfo<'_>,
|
||||||
next: NextResolve<'_>,
|
next: NextResolve<'_>,
|
||||||
) -> ServerResult<Option<Value>> {
|
) -> ServerResult<Option<Value>> {
|
||||||
let attributes = vec![
|
let span = if !info.is_for_introspection {
|
||||||
KEY_PARENT_TYPE.string(info.parent_type.to_string()),
|
let attributes = vec![
|
||||||
KEY_RETURN_TYPE.string(info.return_type.to_string()),
|
KEY_PARENT_TYPE.string(info.parent_type.to_string()),
|
||||||
];
|
KEY_RETURN_TYPE.string(info.return_type.to_string()),
|
||||||
let span = self
|
];
|
||||||
.tracer
|
Some(
|
||||||
.span_builder(info.path_node.to_string())
|
self.tracer
|
||||||
.with_kind(SpanKind::Server)
|
.span_builder(info.path_node.to_string())
|
||||||
.with_attributes(attributes)
|
.with_kind(SpanKind::Server)
|
||||||
.start(&*self.tracer);
|
.with_attributes(attributes)
|
||||||
next.run(ctx, info)
|
.start(&*self.tracer),
|
||||||
.with_context(OpenTelemetryContext::current_with_span(span))
|
)
|
||||||
.inspect_err(|err| {
|
} else {
|
||||||
let current_cx = OpenTelemetryContext::current();
|
None
|
||||||
current_cx
|
};
|
||||||
.span()
|
|
||||||
.add_event("error".to_string(), vec![KEY_ERROR.string(err.to_string())]);
|
let fut = next.run(ctx, info).inspect_err(|err| {
|
||||||
})
|
let current_cx = OpenTelemetryContext::current();
|
||||||
.await
|
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<'_>,
|
info: ResolveInfo<'_>,
|
||||||
next: NextResolve<'_>,
|
next: NextResolve<'_>,
|
||||||
) -> ServerResult<Option<Value>> {
|
) -> ServerResult<Option<Value>> {
|
||||||
let span = span!(
|
let span = if !info.is_for_introspection {
|
||||||
target: "async_graphql::graphql",
|
Some(span!(
|
||||||
Level::INFO,
|
target: "async_graphql::graphql",
|
||||||
"field",
|
Level::INFO,
|
||||||
path = %info.path_node,
|
"field",
|
||||||
parent_type = %info.parent_type,
|
path = %info.path_node,
|
||||||
return_type = %info.return_type,
|
parent_type = %info.parent_type,
|
||||||
);
|
return_type = %info.return_type,
|
||||||
next.run(ctx, info)
|
))
|
||||||
.map_err(|err| {
|
} else {
|
||||||
tracinglib::info!(target: "async_graphql::graphql",
|
None
|
||||||
error = %err.message,
|
};
|
||||||
"error");
|
|
||||||
err
|
let fut = next.run(ctx, info).inspect_err(|err| {
|
||||||
})
|
tracinglib::info!(
|
||||||
.instrument(span)
|
target: "async_graphql::graphql",
|
||||||
.await
|
error = %err.message,
|
||||||
|
"error",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
match span {
|
||||||
|
Some(span) => fut.instrument(span).await,
|
||||||
|
None => fut.await,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,7 @@ impl<'a> Fields<'a> {
|
||||||
.alias
|
.alias
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|alias| alias.node.as_str()),
|
.map(|alias| alias.node.as_str()),
|
||||||
|
is_for_introspection: ctx_field.is_for_introspection,
|
||||||
};
|
};
|
||||||
|
|
||||||
let resolve_fut = root.resolve_field(&ctx_field);
|
let resolve_fut = root.resolve_field(&ctx_field);
|
||||||
|
@ -263,6 +264,7 @@ impl<'a> Fields<'a> {
|
||||||
{
|
{
|
||||||
let ctx_directive = ContextBase {
|
let ctx_directive = ContextBase {
|
||||||
path_node: ctx_field.path_node,
|
path_node: ctx_field.path_node,
|
||||||
|
is_for_introspection: false,
|
||||||
item: directive,
|
item: directive,
|
||||||
schema_env: ctx_field.schema_env,
|
schema_env: ctx_field.schema_env,
|
||||||
query_env: ctx_field.query_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(),
|
return_type: &T::qualified_type_name(),
|
||||||
name: field.node.name.node.as_str(),
|
name: field.node.name.node.as_str(),
|
||||||
alias: field.node.alias.as_ref().map(|alias| alias.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 {
|
let resolve_fut = async {
|
||||||
OutputType::resolve(&item, &ctx_idx, field)
|
OutputType::resolve(&item, &ctx_idx, field)
|
||||||
|
|
|
@ -609,6 +609,7 @@ where
|
||||||
// execute
|
// execute
|
||||||
let ctx = ContextBase {
|
let ctx = ContextBase {
|
||||||
path_node: None,
|
path_node: None,
|
||||||
|
is_for_introspection: false,
|
||||||
item: &env.operation.node.selection_set,
|
item: &env.operation.node.selection_set,
|
||||||
schema_env: &self.env,
|
schema_env: &self.env,
|
||||||
query_env: &env,
|
query_env: &env,
|
||||||
|
|
|
@ -34,7 +34,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
||||||
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
|
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
|
||||||
) {
|
) {
|
||||||
if ctx.item.node.name.node == "__schema" {
|
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);
|
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
|
||||||
return OutputType::resolve(
|
return OutputType::resolve(
|
||||||
&__Schema::new(&ctx.schema_env.registry, &visible_types),
|
&__Schema::new(&ctx.schema_env.registry, &visible_types),
|
||||||
|
@ -45,7 +46,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
||||||
.map(Some);
|
.map(Some);
|
||||||
} else if ctx.item.node.name.node == "__type" {
|
} else if ctx.item.node.name.node == "__type" {
|
||||||
let (_, type_name) = ctx.param_value::<String>("name", None)?;
|
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);
|
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
|
||||||
return OutputType::resolve(
|
return OutputType::resolve(
|
||||||
&ctx.schema_env
|
&ctx.schema_env
|
||||||
|
@ -81,7 +83,8 @@ impl<T: ObjectType> ContainerType for QueryRoot<T> {
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(Some(Value::List(res)));
|
return Ok(Some(Value::List(res)));
|
||||||
} else if ctx.item.node.name.node == "_service" {
|
} 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(
|
return OutputType::resolve(
|
||||||
&Service {
|
&Service {
|
||||||
sdl: Some(
|
sdl: Some(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user