use tracing::info_span;
use crate::plugins::telemetry::Telemetry;
use crate::plugins::telemetry::consts::CONNECT_REQUEST_SPAN_NAME;
use crate::plugins::telemetry::consts::ROUTER_SPAN_NAME;
use crate::plugins::telemetry::consts::SUBGRAPH_SPAN_NAME;
use crate::plugins::telemetry::consts::SUPERGRAPH_SPAN_NAME;
use crate::services::SubgraphRequest;
use crate::services::SupergraphRequest;
pub(crate) fn create_router<B>(_request: &http::Request<B>) -> ::tracing::span::Span {
info_span!(
ROUTER_SPAN_NAME,
"otel.name" = ::tracing::field::Empty,
"otel.kind" = "SERVER",
"otel.status_code" = ::tracing::field::Empty,
"apollo_router.license" = ::tracing::field::Empty,
"apollo_private.duration_ns" = ::tracing::field::Empty,
"apollo_private.http.request_headers" = ::tracing::field::Empty,
"apollo_private.http.response_headers" = ::tracing::field::Empty,
"apollo_private.request" = true,
)
}
pub(crate) fn create_router_rejection() -> ::tracing::span::Span {
info_span!(
ROUTER_SPAN_NAME,
"otel.name" = ::tracing::field::Empty,
"otel.kind" = "SERVER",
"otel.status_code" = ::tracing::field::Empty,
"http.response.status_code" = ::tracing::field::Empty,
"apollo_router.license" = ::tracing::field::Empty,
"apollo_private.duration_ns" = ::tracing::field::Empty,
"apollo_private.http.request_headers" = ::tracing::field::Empty,
"apollo_private.http.response_headers" = ::tracing::field::Empty,
"apollo_private.request" = true,
)
}
pub(crate) fn create_supergraph(
config: &crate::plugins::telemetry::apollo::Config,
request: &SupergraphRequest,
field_level_instrumentation_ratio: f64,
) -> ::tracing::span::Span {
let send_variable_values = config.send_variable_values.clone();
info_span!(
SUPERGRAPH_SPAN_NAME,
"otel.kind" = "INTERNAL",
apollo_private.field_level_instrumentation_ratio = field_level_instrumentation_ratio,
apollo_private.operation_signature = ::tracing::field::Empty,
apollo_private.graphql.variables = Telemetry::filter_variables_values(
&request.supergraph_request.body().variables,
&send_variable_values,
),
)
}
pub(crate) fn create_subgraph(
_subgraph_name: &str,
_req: &SubgraphRequest,
) -> ::tracing::span::Span {
info_span!(
SUBGRAPH_SPAN_NAME,
"otel.kind" = "INTERNAL",
"apollo_private.ftv1" = ::tracing::field::Empty,
"otel.status_code" = ::tracing::field::Empty,
)
}
pub(crate) fn create_connector(_source_name: &str) -> ::tracing::span::Span {
info_span!(
CONNECT_REQUEST_SPAN_NAME,
"otel.kind" = "INTERNAL",
"otel.status_code" = ::tracing::field::Empty,
"apollo.connector.response.aborted" = ::tracing::field::Empty,
)
}
#[cfg(test)]
mod tests {
use tracing_mock::expect;
use tracing_mock::subscriber;
use crate::plugins::telemetry::consts::ROUTER_SPAN_NAME;
#[test]
fn test_specific_span() {
let request = http::Request::builder()
.method("GET")
.uri("http://example.com/path/to/location?with=query&another=UN1QU3_query")
.header("apollographql-client-name", "client")
.body("useful info")
.unwrap();
let expected_fields = expect::field("otel.kind")
.with_value(&"SERVER")
.and(expect::field("apollo_private.request").with_value(&true));
let expected_span = expect::span()
.named(ROUTER_SPAN_NAME)
.with_fields(expected_fields);
let (subscriber, handle) = subscriber::mock()
.new_span(expected_span)
.enter(ROUTER_SPAN_NAME)
.event(expect::event())
.exit(ROUTER_SPAN_NAME)
.run_with_handle();
tracing::subscriber::with_default(subscriber, || {
let span = super::create_router(&request);
let _guard = span.enter();
tracing::info!("an event happened!");
});
handle.assert_finished();
}
}