2021-04-04 04:05:54 +00:00
|
|
|
use std::sync::Arc;
|
2020-10-15 06:38:10 +00:00
|
|
|
|
2022-04-19 04:25:11 +00:00
|
|
|
use futures_util::{stream::BoxStream, TryFutureExt};
|
2021-04-04 04:05:54 +00:00
|
|
|
use tracing_futures::Instrument;
|
|
|
|
use tracinglib::{span, Level};
|
2020-03-26 03:34:28 +00:00
|
|
|
|
2022-04-19 04:25:11 +00:00
|
|
|
use crate::{
|
|
|
|
extensions::{
|
|
|
|
Extension, ExtensionContext, ExtensionFactory, NextExecute, NextParseQuery, NextRequest,
|
|
|
|
NextResolve, NextSubscribe, NextValidation, ResolveInfo,
|
|
|
|
},
|
|
|
|
parser::types::ExecutableDocument,
|
|
|
|
Response, ServerError, ServerResult, ValidationResult, Value, Variables,
|
2021-04-04 04:05:54 +00:00
|
|
|
};
|
2021-03-20 11:42:00 +00:00
|
|
|
|
2020-11-07 13:23:22 +00:00
|
|
|
/// Tracing extension
|
|
|
|
///
|
|
|
|
/// # References
|
|
|
|
///
|
|
|
|
/// <https://crates.io/crates/tracing>
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2022-04-19 04:25:11 +00:00
|
|
|
/// use async_graphql::{extensions::Tracing, *};
|
2020-11-07 13:23:22 +00:00
|
|
|
///
|
|
|
|
/// #[derive(SimpleObject)]
|
|
|
|
/// struct Query {
|
|
|
|
/// value: i32,
|
|
|
|
/// }
|
|
|
|
///
|
2021-04-04 04:05:54 +00:00
|
|
|
/// let schema = Schema::build(Query { value: 100 }, EmptyMutation, EmptySubscription)
|
|
|
|
/// .extension(Tracing)
|
2020-11-07 13:23:22 +00:00
|
|
|
/// .finish();
|
|
|
|
///
|
2021-11-20 03:16:48 +00:00
|
|
|
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
|
|
|
|
/// schema.execute(Request::new("{ value }")).await;
|
|
|
|
/// # });
|
2020-11-07 13:23:22 +00:00
|
|
|
/// ```
|
2021-03-22 05:27:24 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "tracing")))]
|
2020-11-07 13:23:22 +00:00
|
|
|
pub struct Tracing;
|
|
|
|
|
2020-09-29 12:47:37 +00:00
|
|
|
impl ExtensionFactory for Tracing {
|
2021-04-04 04:05:54 +00:00
|
|
|
fn create(&self) -> Arc<dyn Extension> {
|
|
|
|
Arc::new(TracingExtension::default())
|
2020-09-29 12:47:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
2021-04-04 04:05:54 +00:00
|
|
|
struct TracingExtension;
|
2020-03-26 03:34:28 +00:00
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
#[async_trait::async_trait]
|
2020-09-29 12:47:37 +00:00
|
|
|
impl Extension for TracingExtension {
|
2021-04-05 04:21:02 +00:00
|
|
|
async fn request(&self, ctx: &ExtensionContext<'_>, next: NextRequest<'_>) -> Response {
|
|
|
|
next.run(ctx)
|
2021-04-04 04:05:54 +00:00
|
|
|
.instrument(span!(
|
2021-03-25 08:33:11 +00:00
|
|
|
target: "async_graphql::graphql",
|
|
|
|
Level::INFO,
|
2021-04-04 04:05:54 +00:00
|
|
|
"request",
|
|
|
|
))
|
|
|
|
.await
|
2020-09-25 04:58:45 +00:00
|
|
|
}
|
2020-08-31 01:01:53 +00:00
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
fn subscribe<'s>(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
stream: BoxStream<'s, Response>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextSubscribe<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> BoxStream<'s, Response> {
|
2021-04-05 04:21:02 +00:00
|
|
|
Box::pin(next.run(ctx, stream).instrument(span!(
|
2021-04-04 04:05:54 +00:00
|
|
|
target: "async_graphql::graphql",
|
|
|
|
Level::INFO,
|
|
|
|
"subscribe",
|
|
|
|
)))
|
2020-09-25 04:58:45 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn parse_query(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
query: &str,
|
|
|
|
variables: &Variables,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextParseQuery<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> ServerResult<ExecutableDocument> {
|
|
|
|
let span = span!(
|
|
|
|
target: "async_graphql::graphql",
|
|
|
|
Level::INFO,
|
|
|
|
"parse",
|
|
|
|
);
|
2021-04-07 08:23:28 +00:00
|
|
|
async move {
|
|
|
|
let res = next.run(ctx, query, variables).await;
|
|
|
|
if let Ok(doc) = &res {
|
|
|
|
tracinglib::Span::current().record(
|
|
|
|
"source",
|
|
|
|
&ctx.stringify_execute_doc(doc, variables).as_str(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|
|
|
|
.instrument(span)
|
|
|
|
.await
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn validation(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextValidation<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> Result<ValidationResult, Vec<ServerError>> {
|
|
|
|
let span = span!(
|
|
|
|
target: "async_graphql::graphql",
|
|
|
|
Level::INFO,
|
|
|
|
"validation"
|
|
|
|
);
|
2021-04-05 04:21:02 +00:00
|
|
|
next.run(ctx).instrument(span).await
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 02:17:33 +00:00
|
|
|
async fn execute(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
operation_name: Option<&str>,
|
|
|
|
next: NextExecute<'_>,
|
|
|
|
) -> Response {
|
2021-04-04 04:05:54 +00:00
|
|
|
let span = span!(
|
|
|
|
target: "async_graphql::graphql",
|
|
|
|
Level::INFO,
|
|
|
|
"execute"
|
|
|
|
);
|
2021-06-10 02:17:33 +00:00
|
|
|
next.run(ctx, operation_name).instrument(span).await
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|
2020-09-26 01:49:46 +00:00
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn resolve(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
info: ResolveInfo<'_>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextResolve<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> 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,
|
|
|
|
);
|
2021-04-05 04:21:02 +00:00
|
|
|
next.run(ctx, info)
|
2021-04-04 04:05:54 +00:00
|
|
|
.map_err(|err| {
|
2021-12-02 14:59:49 +00:00
|
|
|
tracinglib::info!(target: "async_graphql::graphql",
|
|
|
|
error = %err.message,
|
|
|
|
"error");
|
2021-04-04 04:05:54 +00:00
|
|
|
err
|
|
|
|
})
|
2021-05-19 02:49:06 +00:00
|
|
|
.instrument(span)
|
2021-04-04 04:05:54 +00:00
|
|
|
.await
|
2020-09-26 01:49:46 +00:00
|
|
|
}
|
2020-03-26 03:34:28 +00:00
|
|
|
}
|