Skip to content

Commit

Permalink
Add cost information to protobuf traces
Browse files Browse the repository at this point in the history
  • Loading branch information
bryn committed Jun 12, 2024
1 parent a0b9d34 commit 6ff866c
Show file tree
Hide file tree
Showing 9 changed files with 727 additions and 19 deletions.
2 changes: 2 additions & 0 deletions apollo-router/src/plugins/demand_control/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub(crate) struct CostContext {
pub(crate) estimated: f64,
pub(crate) actual: f64,
pub(crate) result: &'static str,
pub(crate) strategy: &'static str,
}

impl Default for CostContext {
Expand All @@ -51,6 +52,7 @@ impl Default for CostContext {
estimated: 0.0,
actual: 0.0,
result: "COST_OK",
strategy: "COST_STRATEGY_UNKNOWN",
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl StrategyImpl for StaticEstimated {
.and_then(|cost| {
request.context.extensions().with_lock(|mut lock| {
let cost_result = lock.get_or_default_mut::<CostContext>();
cost_result.strategy = "static_estimated";
cost_result.estimated = cost;
if cost > self.max {
Err(
Expand Down
11 changes: 10 additions & 1 deletion apollo-router/src/plugins/telemetry/config_new/cost/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use opentelemetry::metrics::MeterProvider;
use opentelemetry_api::KeyValue;
use opentelemetry_api::{Key, KeyValue};
use parking_lot::Mutex;
use schemars::JsonSchema;
use serde::Deserialize;
Expand All @@ -24,6 +24,15 @@ use crate::services::supergraph::Request;
use crate::services::supergraph::Response;
use crate::Context;

pub(crate) const APOLLO_PRIVATE_COST_ESTIMATED: Key =
Key::from_static_str("apollo_private.cost.estimated");
pub(crate) const APOLLO_PRIVATE_COST_ACTUAL: Key =
Key::from_static_str("apollo_private.cost.actual");
pub(crate) const APOLLO_PRIVATE_COST_STRATEGY: Key =
Key::from_static_str("apollo_private.cost.strategy");
pub(crate) const APOLLO_PRIVATE_COST_RESULT: Key =
Key::from_static_str("apollo_private.cost.result");

static COST_ESTIMATED: &str = "cost.estimated";
static COST_ACTUAL: &str = "cost.actual";
static COST_DELTA: &str = "cost.delta";
Expand Down
2 changes: 1 addition & 1 deletion apollo-router/src/plugins/telemetry/config_new/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub(crate) mod attributes;
pub(crate) mod conditions;

mod conditional;
mod cost;
pub(crate) mod cost;
pub(crate) mod events;
mod experimental_when_header;
pub(crate) mod extendable;
Expand Down
33 changes: 31 additions & 2 deletions apollo-router/src/plugins/telemetry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,17 @@ use crate::metrics::filter::FilterMeterProvider;
use crate::metrics::meter_provider;
use crate::plugin::Plugin;
use crate::plugin::PluginInit;
use crate::plugins::demand_control::CostContext;
use crate::plugins::telemetry::apollo::ForwardHeaders;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::node::Id::ResponseName;
use crate::plugins::telemetry::apollo_exporter::proto::reports::StatsContext;
use crate::plugins::telemetry::config::AttributeValue;
use crate::plugins::telemetry::config::MetricsCommon;
use crate::plugins::telemetry::config::TracingCommon;
use crate::plugins::telemetry::config_new::cost::{
APOLLO_PRIVATE_COST_ACTUAL, APOLLO_PRIVATE_COST_ESTIMATED, APOLLO_PRIVATE_COST_RESULT,
APOLLO_PRIVATE_COST_STRATEGY,
};
use crate::plugins::telemetry::config_new::graphql::GraphQLInstruments;
use crate::plugins::telemetry::config_new::instruments::SupergraphInstruments;
use crate::plugins::telemetry::dynamic_attribute::SpanDynAttribute;
Expand Down Expand Up @@ -588,15 +593,16 @@ impl Plugin for Telemetry {

(req.context.clone(), custom_instruments, custom_attributes, supergraph_events, custom_graphql_instruments)
},
move |(ctx, custom_instruments, custom_attributes, supergraph_events, custom_graphql_instruments): (Context, SupergraphInstruments, Vec<KeyValue>, SupergraphEvents, GraphQLInstruments), fut| {
move |(ctx, custom_instruments, mut custom_attributes, supergraph_events, custom_graphql_instruments): (Context, SupergraphInstruments, Vec<KeyValue>, SupergraphEvents, GraphQLInstruments), fut| {
let config = config_map_res.clone();
let sender = metrics_sender.clone();
let start = Instant::now();

async move {
let span = Span::current();
span.set_span_dyn_attributes(custom_attributes);
let mut result: Result<SupergraphResponse, BoxError> = fut.await;
add_cost_attributes(&ctx, &mut custom_attributes);
span.set_span_dyn_attributes(custom_attributes);
match &result {
Ok(resp) => {
span.set_span_dyn_attributes(config.instrumentation.spans.supergraph.attributes.on_response(resp));
Expand Down Expand Up @@ -774,6 +780,29 @@ impl Plugin for Telemetry {
}
}

fn add_cost_attributes(context: &Context, custom_attributes: &mut Vec<KeyValue>) {
context.extensions().with_lock(|c| {
if let Some(cost) = c.get::<CostContext>().cloned() {
custom_attributes.push(KeyValue::new(
APOLLO_PRIVATE_COST_ESTIMATED.clone(),
AttributeValue::I64(cost.estimated as i64),
));
custom_attributes.push(KeyValue::new(
APOLLO_PRIVATE_COST_ACTUAL.clone(),
AttributeValue::I64(cost.actual as i64),
));
custom_attributes.push(KeyValue::new(
APOLLO_PRIVATE_COST_RESULT.clone(),
AttributeValue::String(cost.result.into()),
));
custom_attributes.push(KeyValue::new(
APOLLO_PRIVATE_COST_STRATEGY.clone(),
AttributeValue::String(cost.strategy.into()),
));
}
});
}

impl Telemetry {
pub(crate) fn activate(&self) {
let mut activation = self.activation.lock();
Expand Down
62 changes: 60 additions & 2 deletions apollo-router/src/plugins/telemetry/tracing/apollo_telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_pla
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_plan_node::ParallelNode;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_plan_node::ResponsePathElement;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_plan_node::SequenceNode;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::Details;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::Http;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::QueryPlanNode;
use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::{Details, Limits};
use crate::plugins::telemetry::apollo_exporter::ApolloExporter;
use crate::plugins::telemetry::apollo_otlp_exporter::ApolloOtlpExporter;
use crate::plugins::telemetry::config::Sampler;
Expand Down Expand Up @@ -96,6 +96,14 @@ const APOLLO_PRIVATE_HTTP_RESPONSE_HEADERS: Key =
Key::from_static_str("apollo_private.http.response_headers");
pub(crate) const APOLLO_PRIVATE_OPERATION_SIGNATURE: Key =
Key::from_static_str("apollo_private.operation_signature");
pub(crate) const APOLLO_PRIVATE_COST_ESTIMATED: Key =
Key::from_static_str("apollo_private.cost.estimated");
pub(crate) const APOLLO_PRIVATE_COST_ACTUAL: Key =
Key::from_static_str("apollo_private.cost.actual");
pub(crate) const APOLLO_PRIVATE_COST_STRATEGY: Key =
Key::from_static_str("apollo_private.cost.strategy");
pub(crate) const APOLLO_PRIVATE_COST_RESULT: Key =
Key::from_static_str("apollo_private.cost.result");
pub(crate) const APOLLO_PRIVATE_FTV1: Key = Key::from_static_str("apollo_private.ftv1");
const PATH: Key = Key::from_static_str("graphql.path");
const SUBGRAPH_NAME: Key = Key::from_static_str("apollo.subgraph.name");
Expand All @@ -110,7 +118,7 @@ pub(crate) const OPERATION_SUBTYPE: Key = Key::from_static_str("apollo_private.o
const EXT_TRACE_ID: Key = Key::from_static_str("trace_id");

/// The set of attributes to include when sending to the Apollo Reports protocol.
const REPORTS_INCLUDE_ATTRS: [Key; 18] = [
const REPORTS_INCLUDE_ATTRS: [Key; 22] = [
APOLLO_PRIVATE_REQUEST,
APOLLO_PRIVATE_DURATION_NS_KEY,
APOLLO_PRIVATE_SENT_TIME_OFFSET,
Expand All @@ -119,6 +127,10 @@ const REPORTS_INCLUDE_ATTRS: [Key; 18] = [
APOLLO_PRIVATE_HTTP_RESPONSE_HEADERS,
APOLLO_PRIVATE_OPERATION_SIGNATURE,
APOLLO_PRIVATE_FTV1,
APOLLO_PRIVATE_COST_STRATEGY,
APOLLO_PRIVATE_COST_RESULT,
APOLLO_PRIVATE_COST_ESTIMATED,
APOLLO_PRIVATE_COST_ACTUAL,
PATH,
SUBGRAPH_NAME,
CLIENT_NAME_KEY,
Expand Down Expand Up @@ -261,6 +273,7 @@ enum TreeData {
operation_signature: String,
operation_name: String,
variables_json: HashMap<String, String>,
limits: Option<Limits>,
},
QueryPlanNode(QueryPlanNode),
DeferPrimary(DeferNodePrimary),
Expand Down Expand Up @@ -395,13 +408,15 @@ impl Exporter {
operation_signature,
operation_name,
variables_json,
limits,
} => {
root_trace.field_execution_weight = self.field_execution_weight;
root_trace.signature = operation_signature;
root_trace.details = Some(Details {
variables_json,
operation_name,
});
root_trace.limits = limits;
results.push(root_trace.clone());
}
TreeData::Execution(operation_type) => {
Expand Down Expand Up @@ -572,6 +587,35 @@ impl Exporter {
)]
}
SUPERGRAPH_SPAN_NAME => {
let limits = span
.attributes
.get(&APOLLO_PRIVATE_COST_RESULT)
.and_then(extract_string)
.map(|result| {
Limits {
result,
strategy: span
.attributes
.get(&APOLLO_PRIVATE_COST_STRATEGY)
.and_then(extract_string)
.unwrap_or_default(),
cost_estimated: span
.attributes
.get(&APOLLO_PRIVATE_COST_ESTIMATED)
.and_then(extract_u64)
.unwrap_or_default(),
cost_actual: span
.attributes
.get(&APOLLO_PRIVATE_COST_ACTUAL)
.and_then(extract_u64)
.unwrap_or_default(),
// Not extracted yet
depth: 0,
height: 0,
alias_count: 0,
root_field_count: 0,
}
});
//Currently some data is in the supergraph span as we don't have the a request hook in plugin.
child_nodes.push(TreeData::Supergraph {
operation_signature: span
Expand All @@ -589,6 +633,7 @@ impl Exporter {
.get(&APOLLO_PRIVATE_GRAPHQL_VARIABLES)
.and_then(extract_json)
.unwrap_or_default(),
limits,
});
child_nodes
}
Expand Down Expand Up @@ -751,6 +796,7 @@ impl Exporter {
.and_then(extract_string)
.unwrap_or_default(),
variables_json: HashMap::new(),
limits: None,
});

child_nodes.push(TreeData::Execution(
Expand Down Expand Up @@ -821,6 +867,18 @@ pub(crate) fn extract_i64(v: &Value) -> Option<i64> {
}
}

pub(crate) fn extract_u64(v: &Value) -> Option<u64> {
if let Value::I64(v) = v {
if *v > 0 {
Some(*v as u64)
} else {
None
}
} else {
None
}
}

pub(crate) fn extract_ftv1_trace_with_error_count(
v: &Value,
error_config: &ErrorConfiguration,
Expand Down
Loading

0 comments on commit 6ff866c

Please sign in to comment.