diff --git a/.changesets/feat_bnjjj_add_operation_name_router_selector.md b/.changesets/feat_bnjjj_add_operation_name_router_selector.md new file mode 100644 index 0000000000..c853a3fb9f --- /dev/null +++ b/.changesets/feat_bnjjj_add_operation_name_router_selector.md @@ -0,0 +1,18 @@ +### Add selector for router service in custom telemetry ([PR #5392](https://github.com/apollographql/router/pull/5392)) + +Instead of having to access to the operation_name using the response_context at the router service, we now provide a selector for operation name at the router service in instrumentations. + +example: + +```yaml +telemetry: + instrumentation: + instruments: + router: + http.server.request.duration: + attributes: + graphql.operation.name: + operation_name: string +``` + +By [@bnjjj](https://github.com/bnjjj) in https://github.com/apollographql/router/pull/5392 \ No newline at end of file diff --git a/.changesets/maint_bryn_demand_control_studio_traces.md b/.changesets/maint_bryn_demand_control_studio_traces.md new file mode 100644 index 0000000000..d429855852 --- /dev/null +++ b/.changesets/maint_bryn_demand_control_studio_traces.md @@ -0,0 +1,5 @@ +### Add cost information to protobuf traces ([PR #5430](https://github.com/apollographql/router/pull/5430)) + +If `experimental_demand_control` is enabled, cost information for queries is now exported on Apollo protobuf traces for display in studio. + +By [@BrynCooke](https://github.com/BrynCooke) in https://github.com/apollographql/router/pull/5430 diff --git a/Cargo.lock b/Cargo.lock index d43efcabff..89f926f887 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -220,7 +220,7 @@ dependencies = [ [[package]] name = "apollo-federation" -version = "1.48.1" +version = "1.49.0-rc.1" dependencies = [ "apollo-compiler", "derive_more", @@ -266,7 +266,7 @@ dependencies = [ [[package]] name = "apollo-router" -version = "1.48.1" +version = "1.49.0-rc.1" dependencies = [ "access-json", "anyhow", @@ -430,7 +430,7 @@ dependencies = [ [[package]] name = "apollo-router-benchmarks" -version = "1.48.1" +version = "1.49.0-rc.1" dependencies = [ "apollo-parser", "apollo-router", @@ -446,7 +446,7 @@ dependencies = [ [[package]] name = "apollo-router-scaffold" -version = "1.48.1" +version = "1.49.0-rc.1" dependencies = [ "anyhow", "cargo-scaffold", @@ -5528,9 +5528,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -6228,12 +6228,14 @@ dependencies = [ [[package]] name = "serde_json_bytes" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb260b2939374fad6f939f803662d4971d03395fcd03752b674bdba06565779" +checksum = "9eb67259abd83636e3b2f4700ddc3ecfdbfe7b1b89e824da42bfea6530caf03b" dependencies = [ "bytes", "indexmap 2.2.3", + "jsonpath-rust", + "regex", "serde", "serde_json", ] diff --git a/Cargo.toml b/Cargo.toml index 26bbc24bfd..9ef784fc47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ serde_json = { version = "1.0.114", features = [ "preserve_order", "float_roundtrip", ] } -serde_json_bytes = { version = "0.2.2", features = ["preserve_order"] } +serde_json_bytes = { version = "0.2.3", features = ["preserve_order"] } sha1 = "0.10.6" tempfile = "3.10.0" tokio = { version = "1.36.0", features = ["full"] } diff --git a/apollo-federation/Cargo.toml b/apollo-federation/Cargo.toml index 188bb96c33..a24f1b0b0d 100644 --- a/apollo-federation/Cargo.toml +++ b/apollo-federation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "apollo-federation" -version = "1.48.1" +version = "1.49.0-rc.1" authors = ["The Apollo GraphQL Contributors"] edition = "2021" description = "Apollo Federation" diff --git a/apollo-federation/src/operation/mod.rs b/apollo-federation/src/operation/mod.rs index 070e49c7da..468730ab0b 100644 --- a/apollo-federation/src/operation/mod.rs +++ b/apollo-federation/src/operation/mod.rs @@ -188,13 +188,21 @@ impl Operation { /// - For the type, stores the schema and the position in that schema instead of just the /// `NamedType`. /// - Stores selections in a map so they can be normalized efficiently. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub(crate) struct SelectionSet { pub(crate) schema: ValidFederationSchema, pub(crate) type_position: CompositeTypeDefinitionPosition, pub(crate) selections: Arc, } +impl PartialEq for SelectionSet { + fn eq(&self, other: &Self) -> bool { + self.selections == other.selections + } +} + +impl Eq for SelectionSet {} + mod selection_map { use std::borrow::Cow; use std::iter::Map; diff --git a/apollo-federation/src/operation/tests/mod.rs b/apollo-federation/src/operation/tests/mod.rs index d66f263a83..ee98b0e06c 100644 --- a/apollo-federation/src/operation/tests/mod.rs +++ b/apollo-federation/src/operation/tests/mod.rs @@ -1439,9 +1439,7 @@ fn add_at_path_merge_subselections() { insta::assert_snapshot!(selection_set, @r#"{ a { b { c { d e(arg: 1) } } } }"#); } -// TODO: `.add_at_path` should collapse unnecessary fragments #[test] -#[ignore] fn add_at_path_collapses_unnecessary_fragments() { let schema = apollo_compiler::Schema::parse_and_validate(ADD_AT_PATH_TEST_SCHEMA, "schema.graphql") diff --git a/apollo-federation/src/query_graph/graph_path.rs b/apollo-federation/src/query_graph/graph_path.rs index fafda9a50a..0e6cc1debb 100644 --- a/apollo-federation/src/query_graph/graph_path.rs +++ b/apollo-federation/src/query_graph/graph_path.rs @@ -3562,12 +3562,18 @@ impl OpPath { match element.as_ref() { OpPathElement::InlineFragment(fragment) => { if let Some(type_condition) = &fragment.data().type_condition_position { - if schema.get_type(type_condition.type_name().clone()).is_ok() { - let updated_fragment = fragment.with_updated_type_condition(None); - filtered - .push(Arc::new(OpPathElement::InlineFragment(updated_fragment))); + if schema.get_type(type_condition.type_name().clone()).is_err() { + if element.directives().is_empty() { + continue; // skip this element + } else { + // Replace this element with an unconditioned inline fragment + let updated_fragment = fragment.with_updated_type_condition(None); + filtered.push(Arc::new(OpPathElement::InlineFragment( + updated_fragment, + ))); + } } else { - continue; + filtered.push(element.clone()); } } else { filtered.push(element.clone()); diff --git a/apollo-federation/src/query_plan/fetch_dependency_graph.rs b/apollo-federation/src/query_plan/fetch_dependency_graph.rs index 3f16e048e1..888c182ee3 100644 --- a/apollo-federation/src/query_plan/fetch_dependency_graph.rs +++ b/apollo-federation/src/query_plan/fetch_dependency_graph.rs @@ -3062,6 +3062,10 @@ fn compute_nodes_for_key_resolution<'a>( let dest = stack_item.tree.graph.node_weight(dest_id)?; // We shouldn't have a key on a non-composite type let source_type: CompositeTypeDefinitionPosition = source.type_.clone().try_into()?; + let source_schema: ValidFederationSchema = dependency_graph + .federated_query_graph + .schema_by_source(&source.source)? + .clone(); let dest_type: CompositeTypeDefinitionPosition = dest.type_.clone().try_into()?; let dest_schema: ValidFederationSchema = dependency_graph .federated_query_graph @@ -3153,7 +3157,7 @@ fn compute_nodes_for_key_resolution<'a>( let node = FetchDependencyGraph::node_weight_mut(&mut dependency_graph.graph, stack_item.node_id)?; let typename_field = Arc::new(OpPathElement::Field(Field::new_introspection_typename( - &dependency_graph.supergraph_schema, + &source_schema, &source_type, None, ))); @@ -3852,6 +3856,7 @@ fn handle_requires( let inputs = inputs_for_require( dependency_graph, entity_type_position.clone(), + entity_type_schema, query_graph_edge_id, context, false, @@ -4024,6 +4029,7 @@ fn defer_context_for_conditions(base_context: &DeferContext) -> DeferContext { fn inputs_for_require( fetch_dependency_graph: &mut FetchDependencyGraph, entity_type_position: ObjectTypeDefinitionPosition, + entity_type_schema: ValidFederationSchema, query_graph_edge_id: EdgeIndex, context: &OpGraphPathContext, include_key_inputs: bool, @@ -4108,7 +4114,7 @@ fn inputs_for_require( // should just use `entity_type` (that @interfaceObject type), not input type which will be an implementation the // subgraph does not know in that particular case. let mut key_inputs = - SelectionSet::for_composite_type(edge_conditions.schema.clone(), input_type.clone()); + SelectionSet::for_composite_type(entity_type_schema, entity_type_position.into()); key_inputs.add_selection_set(&key_condition)?; Ok(( @@ -4148,6 +4154,7 @@ fn add_post_require_inputs( let (inputs, key_inputs) = inputs_for_require( dependency_graph, entity_type_position.clone(), + entity_type_schema.clone(), query_graph_edge_id, context, true, diff --git a/apollo-federation/src/query_plan/query_planner.rs b/apollo-federation/src/query_plan/query_planner.rs index 8d8f9c7ac4..45102bcc62 100644 --- a/apollo-federation/src/query_plan/query_planner.rs +++ b/apollo-federation/src/query_plan/query_planner.rs @@ -2,21 +2,19 @@ use std::cell::Cell; use std::num::NonZeroU32; use std::sync::Arc; -use apollo_compiler::schema::ExtendedType; use apollo_compiler::schema::Name; use apollo_compiler::validation::Valid; use apollo_compiler::ExecutableDocument; use apollo_compiler::NodeStr; use indexmap::IndexMap; use indexmap::IndexSet; +use itertools::Itertools; use petgraph::csr::NodeIndex; use petgraph::stable_graph::IndexType; use crate::error::FederationError; use crate::error::SingleFederationError; use crate::link::federation_spec_definition::FederationSpecDefinition; -use crate::link::federation_spec_definition::FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC; -use crate::link::spec::Identity; use crate::operation::normalize_operation; use crate::operation::NamedFragments; use crate::operation::RebasedFragments; @@ -219,17 +217,6 @@ impl QueryPlanner { Some(true), )?; - let metadata = supergraph_schema.metadata().unwrap(); - - let federation_link = metadata.for_identity(&Identity::federation_identity()); - let interface_object_directive = - federation_link.map_or(FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC, |link| { - link.directive_name_in_schema(&FEDERATION_INTERFACEOBJECT_DIRECTIVE_NAME_IN_SPEC) - }); - - let is_interface_object = - |ty: &ExtendedType| ty.is_object() && ty.directives().has(&interface_object_directive); - let interface_types_with_interface_objects = supergraph .schema .get_types() @@ -237,16 +224,28 @@ impl QueryPlanner { TypeDefinitionPosition::Interface(interface_position) => Some(interface_position), _ => None, }) - .filter(|position| { - query_graph.subgraphs().any(|(_name, schema)| { - schema - .schema() - .types - .get(&position.type_name) - .is_some_and(is_interface_object) - }) + .map(|position| { + let is_interface_object = query_graph + .subgraphs() + .map(|(_name, schema)| { + let Some(position) = schema.try_get_type(position.type_name.clone()) else { + return Ok(false); + }; + schema.is_interface_object_type(position) + }) + .process_results(|mut iter| iter.any(|b| b))?; + Ok::<_, FederationError>((position, is_interface_object)) }) - .collect::>(); + .process_results(|iter| { + iter.flat_map(|(position, is_interface_object)| { + if is_interface_object { + Some(position) + } else { + None + } + }) + .collect::>() + })?; let is_inconsistent = |position: AbstractTypeDefinitionPosition| { let mut sources = query_graph.subgraphs().filter_map(|(_name, subgraph)| { @@ -995,10 +994,7 @@ type User "###); } - // TODO: This fails with "Subgraph unexpectedly does not use federation spec" - // which seems...unusual #[test] - #[ignore] fn plan_simple_root_field_query_for_multiple_subgraphs() { let supergraph = Supergraph::new(TEST_SUPERGRAPH).unwrap(); let planner = QueryPlanner::new(&supergraph, Default::default()).unwrap(); @@ -1022,26 +1018,70 @@ type User .unwrap(); let plan = planner.build_query_plan(&document, None).unwrap(); insta::assert_snapshot!(plan, @r###" - QueryPlan { - Parallel { - Fetch(service: "accounts") { - { + QueryPlan { + Parallel { + Fetch(service: "accounts") { + { userById(id: 1) { - name - email - } - } - } - Fetch(service: "products") { - { - bestRatedProducts { - id - avg_rating - } + name + email + } + } + }, + Sequence { + Fetch(service: "reviews") { + { + bestRatedProducts { + __typename + id + ... on Book { + __typename + id + reviews { + rating + } + } + ... on Movie { + __typename + id + reviews { + rating + } + } + } + } + }, + Flatten(path: "bestRatedProducts.@") { + Fetch(service: "products") { + { + ... on Book { + __typename + id + reviews { + rating + } + } + ... on Movie { + __typename + id + reviews { + rating + } + } + } => + { + ... on Book { + avg_rating + } + ... on Movie { + avg_rating + } + } + }, + }, + }, + }, } - } - } - } "###); } diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs index 67c56a7b70..edfdf0d972 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/fragment_autogeneration.rs @@ -22,9 +22,7 @@ const SUBGRAPH: &str = r#" #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure -// TODO: when QueryPlannerConfig::generate_query_fragments is implemented remove the -// "not implemented yet" note in its doc comment +// TODO: generate_query_fragments (https://apollographql.atlassian.net/browse/FED-76) fn it_respects_generate_query_fragments_option() { let planner = planner!( config = QueryPlannerConfig { generate_query_fragments: true, ..Default::default() }, @@ -74,7 +72,7 @@ fn it_respects_generate_query_fragments_option() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: generate_query_fragments (https://apollographql.atlassian.net/browse/FED-76) fn it_handles_nested_fragment_generation() { let planner = planner!( config = QueryPlannerConfig { generate_query_fragments: true, ..Default::default() }, @@ -137,7 +135,7 @@ fn it_handles_nested_fragment_generation() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: generate_query_fragments (https://apollographql.atlassian.net/browse/FED-76) fn it_handles_fragments_with_one_non_leaf_field() { let planner = planner!( config = QueryPlannerConfig { generate_query_fragments: true, ..Default::default() }, @@ -185,7 +183,7 @@ fn it_handles_fragments_with_one_non_leaf_field() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: generate_query_fragments (https://apollographql.atlassian.net/browse/FED-76) fn it_identifies_and_reuses_equivalent_fragments_that_arent_identical() { let planner = planner!( config = QueryPlannerConfig { generate_query_fragments: true, ..Default::default() }, @@ -235,7 +233,7 @@ fn it_identifies_and_reuses_equivalent_fragments_that_arent_identical() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: generate_query_fragments (https://apollographql.atlassian.net/browse/FED-76) fn fragments_that_share_a_hash_but_are_not_identical_generate_their_own_fragment_definitions() { let planner = planner!( config = QueryPlannerConfig { generate_query_fragments: true, ..Default::default() }, diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/handles_operations_with_directives.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/handles_operations_with_directives.rs index 5a75a437b9..986c43a0d2 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/handles_operations_with_directives.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/handles_operations_with_directives.rs @@ -40,7 +40,7 @@ const SUBGRAPH_B: &str = r#" #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (missing directives on fetch operation) fn test_if_directives_at_the_operation_level_are_passed_down_to_subgraph_queries() { let planner = planner!( subgraphA: SUBGRAPH_A, @@ -154,7 +154,7 @@ fn test_if_directives_at_the_operation_level_are_passed_down_to_subgraph_queries #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (missing `mutation` keyword and operation name) fn test_if_directives_on_mutations_are_passed_down_to_subgraph_queries() { let planner = planner!( subgraphA: SUBGRAPH_A, @@ -199,7 +199,7 @@ fn test_if_directives_on_mutations_are_passed_down_to_subgraph_queries() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (missing directives on fetch query) fn test_if_directives_with_arguments_applied_on_queries_are_ok() { let planner = planner!( Subgraph1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/interface_object.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/interface_object.rs index abf318737e..e0fbca7cdd 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/interface_object.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/interface_object.rs @@ -42,7 +42,7 @@ const SUBGRAPH2: &str = r#" #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (fetch node for `iFromS1.y` is missing) fn can_use_a_key_on_an_interface_object_type() { let planner = planner!( S1: SUBGRAPH1, @@ -93,10 +93,6 @@ fn can_use_a_key_on_an_interface_object_type() { } #[test] -#[should_panic( - expected = r#"Cannot add selection of field "I.__typename" to selection set of parent type "I" that is potentially an interface object type at runtime"# -)] -// TODO: investigate this failure fn can_use_a_key_on_an_interface_object_from_an_interface_object_type() { let planner = planner!( S1: SUBGRAPH1, @@ -178,9 +174,6 @@ fn only_uses_an_interface_object_if_it_can() { } #[test] -#[should_panic( - expected = "Cannot add selection of field \"I.__typename\" to selection set of parent type \"I\" that is potentially an interface object type at runtime" -)] fn does_not_rely_on_an_interface_object_directly_for_typename() { let planner = planner!( S1: SUBGRAPH1, @@ -231,10 +224,8 @@ fn does_not_rely_on_an_interface_object_directly_for_typename() { } #[test] -#[should_panic( - expected = r#"Cannot add selection of field "I.__typename" to selection set of parent type "I" that is potentially an interface object type at runtime"# -)] -// TODO: investigate this failure +#[should_panic(expected = r#"snapshot assertion"#)] +// TODO: investigate this failure (missing fetch node for `iFromS2 { ... on I { y } }`) fn does_not_rely_on_an_interface_object_directly_if_a_specific_implementation_is_requested() { let planner = planner!( S1: SUBGRAPH1, @@ -305,6 +296,7 @@ fn does_not_rely_on_an_interface_object_directly_if_a_specific_implementation_is #[test] #[should_panic(expected = "snapshot assertion")] +// TODO: investigate this failure (fetch node for `iFromS1.y` is missing) fn can_use_a_key_on_an_interface_object_type_even_for_a_concrete_implementation() { let planner = planner!( S1: SUBGRAPH1, @@ -377,10 +369,6 @@ fn can_use_a_key_on_an_interface_object_type_even_for_a_concrete_implementation( } #[test] -#[should_panic( - expected = r#"Cannot add selection of field "I.__typename" to selection set of parent type "I" that is potentially an interface object type at runtime"# -)] -// TODO: investigate this failure fn handles_query_of_an_interface_field_for_a_specific_implementation_when_query_starts_with_interface_object( ) { let planner = planner!( @@ -436,10 +424,8 @@ fn handles_query_of_an_interface_field_for_a_specific_implementation_when_query_ } #[test] -#[should_panic( - expected = r#"Cannot add selection of field "I.__typename" to selection set of parent type "I" that is potentially an interface object type at runtime"# -)] -// TODO: investigate this failure +#[should_panic(expected = r#"snapshot assertion"#)] +// TODO: investigate this failure (missing fetch node for "everything.@ { ... on I { expansiveField } }") fn it_avoids_buffering_interface_object_results_that_may_have_to_be_filtered_with_lists() { let planner = planner!( S1: r#" @@ -533,6 +519,7 @@ fn it_avoids_buffering_interface_object_results_that_may_have_to_be_filtered_wit #[test] #[should_panic(expected = "snapshot assertion")] +// TODO: investigate this failure (missing fetch nodes for i.x and i.y) fn it_handles_requires_on_concrete_type_of_field_provided_by_interface_object() { let planner = planner!( S1: r#" @@ -628,7 +615,7 @@ fn it_handles_requires_on_concrete_type_of_field_provided_by_interface_object() #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (missing fetch node for `i.t.relatedIs.id`) fn it_handles_interface_object_in_nested_entity() { let planner = planner!( S1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/introspection_typename_handling.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/introspection_typename_handling.rs index 4ef57db9ff..f615e7fa9e 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/introspection_typename_handling.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/introspection_typename_handling.rs @@ -65,7 +65,7 @@ fn it_preservers_aliased_typename() { #[test] #[should_panic(expected = r#"snapshot assertion"#)] -// TODO: investigate this failure (`x` is missing in the query plan) +// TODO: investigate this failure (`__typename: __typename` is not expected) fn it_does_not_needlessly_consider_options_for_typename() { let planner = planner!( Subgraph1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/merged_abstract_types_handling.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/merged_abstract_types_handling.rs index b188db4293..31b5503f42 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/merged_abstract_types_handling.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/merged_abstract_types_handling.rs @@ -633,7 +633,7 @@ fn handles_spread_unions_correctly() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (reverse order of parallel fetches) fn handles_case_of_key_chains_in_parallel_requires() { let planner = planner!( Subgraph1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/named_fragments.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/named_fragments.rs index bafb3ae907..a2d8b785f7 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/named_fragments.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/named_fragments.rs @@ -70,8 +70,6 @@ fn handles_mix_of_fragments_indirection_and_unions() { } #[test] -// #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure fn another_mix_of_fragments_indirection_and_unions() { // This tests that the issue reported on https://github.com/apollographql/router/issues/3172 is resolved. diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/provides.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/provides.rs index 891337b8a0..7bad39d1e1 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/provides.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/provides.rs @@ -247,7 +247,7 @@ fn it_works_on_interfaces() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (missing parallel fetches) fn it_works_on_unions() { let planner = planner!( Subgraph1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/requires.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/requires.rs index ccc3b7c299..e5fdc57813 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/requires.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/requires.rs @@ -180,7 +180,7 @@ fn it_handles_multiple_requires_within_the_same_entity_fetch() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure after optimize is merged +// TODO: investigate this failure after optimize is merged (reverse order of parallel fetches) fn handles_multiple_requires_involving_different_nestedness() { let planner = planner!( Subgraph1: r#" @@ -293,8 +293,6 @@ fn handles_multiple_requires_involving_different_nestedness() { /// require that depends on another require #[test] -#[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure fn it_handles_simple_require_chain() { let planner = planner!( Subgraph1: r#" @@ -447,8 +445,6 @@ fn it_handles_simple_require_chain() { } #[test] -#[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure fn it_handles_require_chain_not_ending_in_original_group() { // This is somewhat simiar to the 'simple require chain' case, but the chain does not // end in the group in which the query start @@ -634,8 +630,6 @@ fn it_handles_require_chain_not_ending_in_original_group() { /// a chain of 10 requires #[test] -#[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure fn it_handles_longer_require_chain() { let planner = planner!( Subgraph1: r#" @@ -1371,8 +1365,6 @@ fn it_can_require_at_inaccessible_fields() { } #[test] -#[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure fn it_require_of_multiple_field_when_one_is_also_a_key_to_reach_another() { // The specificity of this example is that we `T.v` requires 2 fields `req1` // and `req2`, but `req1` is also a key to get `req2`. This dependency was diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/requires/include_skip.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/requires/include_skip.rs index b07f265232..b981592f68 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/requires/include_skip.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/requires/include_skip.rs @@ -1,6 +1,6 @@ #[test] #[should_panic(expected = "snapshot assertion")] -// TODO will be fixed with selection set updates in https://apollographql.atlassian.net/browse/FED-241 +// TODO: investigate this failure (redundant inline spread) fn it_handles_a_simple_at_requires_triggered_within_a_conditional() { let planner = planner!( Subgraph1: r#" @@ -136,7 +136,7 @@ fn it_handles_an_at_requires_triggered_conditionally() { #[test] #[should_panic(expected = "snapshot assertion")] -// TODO: investigate this failure +// TODO: investigate this failure (redundant inline spread) fn it_handles_an_at_requires_where_multiple_conditional_are_involved() { let planner = planner!( Subgraph1: r#" diff --git a/apollo-federation/tests/query_plan/build_query_plan_tests/subscriptions.rs b/apollo-federation/tests/query_plan/build_query_plan_tests/subscriptions.rs index 6c67bdc7cc..67c3367c31 100644 --- a/apollo-federation/tests/query_plan/build_query_plan_tests/subscriptions.rs +++ b/apollo-federation/tests/query_plan/build_query_plan_tests/subscriptions.rs @@ -141,6 +141,7 @@ fn basic_subscription_with_single_subgraph() { // subscriptions". #[test] #[should_panic(expected = "snapshot assertion")] +// TODO: Subscription handling fn trying_to_use_defer_with_a_subcription_results_in_an_error() { let config = QueryPlannerConfig { incremental_delivery: QueryPlanIncrementalDeliveryConfig { enable_defer: true }, diff --git a/apollo-router-benchmarks/Cargo.toml b/apollo-router-benchmarks/Cargo.toml index 09e520db79..8aff17bc1b 100644 --- a/apollo-router-benchmarks/Cargo.toml +++ b/apollo-router-benchmarks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "apollo-router-benchmarks" -version = "1.48.1" +version = "1.49.0-rc.1" authors = ["Apollo Graph, Inc. "] edition = "2021" license = "Elastic-2.0" diff --git a/apollo-router-scaffold/Cargo.toml b/apollo-router-scaffold/Cargo.toml index 354486871e..86694809cd 100644 --- a/apollo-router-scaffold/Cargo.toml +++ b/apollo-router-scaffold/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "apollo-router-scaffold" -version = "1.48.1" +version = "1.49.0-rc.1" authors = ["Apollo Graph, Inc. "] edition = "2021" license = "Elastic-2.0" diff --git a/apollo-router-scaffold/templates/base/.scaffold.toml b/apollo-router-scaffold/templates/base/.scaffold.toml index c34e96f571..02fd1e20d9 100644 --- a/apollo-router-scaffold/templates/base/.scaffold.toml +++ b/apollo-router-scaffold/templates/base/.scaffold.toml @@ -18,6 +18,12 @@ Created new Apollo Router project '{{name}}'. > Read [our licensing page](https://www.apollographql.com/docs/resources/elastic-license-v2-faq/) for more details. """ +[hooks] +post = [ + "mv Cargo.template.toml Cargo.toml", + "mv xtask/Cargo.template.toml xtask/Cargo.toml", +] + [parameters] [parameters.name] type = "string" diff --git a/apollo-router-scaffold/templates/base/Cargo.toml b/apollo-router-scaffold/templates/base/Cargo.template.toml similarity index 96% rename from apollo-router-scaffold/templates/base/Cargo.toml rename to apollo-router-scaffold/templates/base/Cargo.template.toml index 62ebdff3d5..95de0477c1 100644 --- a/apollo-router-scaffold/templates/base/Cargo.toml +++ b/apollo-router-scaffold/templates/base/Cargo.template.toml @@ -22,7 +22,7 @@ apollo-router = { path ="{{integration_test}}apollo-router" } apollo-router = { git="https://github.com/apollographql/router.git", branch="{{branch}}" } {{else}} # Note if you update these dependencies then also update xtask/Cargo.toml -apollo-router = "1.48.1" +apollo-router = "1.49.0-rc.1" {{/if}} {{/if}} async-trait = "0.1.52" diff --git a/apollo-router-scaffold/templates/base/xtask/Cargo.toml b/apollo-router-scaffold/templates/base/xtask/Cargo.template.toml similarity index 92% rename from apollo-router-scaffold/templates/base/xtask/Cargo.toml rename to apollo-router-scaffold/templates/base/xtask/Cargo.template.toml index d6c86bde05..6614f941dd 100644 --- a/apollo-router-scaffold/templates/base/xtask/Cargo.toml +++ b/apollo-router-scaffold/templates/base/xtask/Cargo.template.toml @@ -13,7 +13,7 @@ apollo-router-scaffold = { path ="{{integration_test}}apollo-router-scaffold" } {{#if branch}} apollo-router-scaffold = { git="https://github.com/apollographql/router.git", branch="{{branch}}" } {{else}} -apollo-router-scaffold = { git = "https://github.com/apollographql/router.git", tag = "v1.48.1" } +apollo-router-scaffold = { git = "https://github.com/apollographql/router.git", tag = "v1.49.0-rc.1" } {{/if}} {{/if}} anyhow = "1.0.58" diff --git a/apollo-router/Cargo.toml b/apollo-router/Cargo.toml index fdf8e410bc..b296382eaa 100644 --- a/apollo-router/Cargo.toml +++ b/apollo-router/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "apollo-router" -version = "1.48.1" +version = "1.49.0-rc.1" authors = ["Apollo Graph, Inc. "] repository = "https://github.com/apollographql/router/" documentation = "https://docs.rs/apollo-router" @@ -68,7 +68,7 @@ askama = "0.12.1" access-json = "0.1.0" anyhow = "1.0.80" apollo-compiler.workspace = true -apollo-federation = { path = "../apollo-federation", version = "=1.48.1" } +apollo-federation = { path = "../apollo-federation", version = "=1.49.0-rc.1"} arc-swap = "1.6.0" async-channel = "1.9.0" async-compression = { version = "0.4.6", features = [ diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap index 0fc58297c6..f454c2f8ee 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__schema_generation.snap @@ -5097,6 +5097,25 @@ expression: "&schema" ], "type": "object" }, + { + "additionalProperties": false, + "description": "The operation name from the query.", + "properties": { + "default": { + "description": "Optional default value.", + "nullable": true, + "type": "string" + }, + "operation_name": { + "$ref": "#/definitions/OperationName", + "description": "#/definitions/OperationName" + } + }, + "required": [ + "operation_name" + ], + "type": "object" + }, { "additionalProperties": false, "description": "A value from baggage.", diff --git a/apollo-router/src/plugin/serde.rs b/apollo-router/src/plugin/serde.rs index 5c627de5d6..390b871e54 100644 --- a/apollo-router/src/plugin/serde.rs +++ b/apollo-router/src/plugin/serde.rs @@ -6,7 +6,6 @@ use std::str::FromStr; use access_json::JSONQuery; use http::header::HeaderName; use http::HeaderValue; -use jsonpath_rust::JsonPathInst; use regex::Regex; use serde::de; use serde::de::Error; @@ -211,7 +210,9 @@ where deserializer.deserialize_str(RegexVisitor) } -pub(crate) fn deserialize_jsonpath<'de, D>(deserializer: D) -> Result +pub(crate) fn deserialize_jsonpath<'de, D>( + deserializer: D, +) -> Result where D: serde::Deserializer<'de>, { @@ -221,7 +222,7 @@ where struct JSONPathVisitor; impl<'de> serde::de::Visitor<'de> for JSONPathVisitor { - type Value = JsonPathInst; + type Value = serde_json_bytes::path::JsonPathInst; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { write!(formatter, "a JSON path") @@ -231,6 +232,6 @@ impl<'de> serde::de::Visitor<'de> for JSONPathVisitor { where E: serde::de::Error, { - JsonPathInst::from_str(s).map_err(serde::de::Error::custom) + serde_json_bytes::path::JsonPathInst::from_str(s).map_err(serde::de::Error::custom) } } diff --git a/apollo-router/src/plugins/demand_control/mod.rs b/apollo-router/src/plugins/demand_control/mod.rs index fc36115b2e..57400ca40c 100644 --- a/apollo-router/src/plugins/demand_control/mod.rs +++ b/apollo-router/src/plugins/demand_control/mod.rs @@ -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 { @@ -51,6 +52,7 @@ impl Default for CostContext { estimated: 0.0, actual: 0.0, result: "COST_OK", + strategy: "COST_STRATEGY_UNKNOWN", } } } diff --git a/apollo-router/src/plugins/demand_control/strategy/static_estimated.rs b/apollo-router/src/plugins/demand_control/strategy/static_estimated.rs index 6e7447d6b4..41de6926b4 100644 --- a/apollo-router/src/plugins/demand_control/strategy/static_estimated.rs +++ b/apollo-router/src/plugins/demand_control/strategy/static_estimated.rs @@ -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::(); + cost_result.strategy = "static_estimated"; cost_result.estimated = cost; if cost > self.max { Err( diff --git a/apollo-router/src/plugins/telemetry/config_new/cost/mod.rs b/apollo-router/src/plugins/telemetry/config_new/cost/mod.rs index 02e20da6a8..43eb31948a 100644 --- a/apollo-router/src/plugins/telemetry/config_new/cost/mod.rs +++ b/apollo-router/src/plugins/telemetry/config_new/cost/mod.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use opentelemetry::metrics::MeterProvider; +use opentelemetry_api::Key; use opentelemetry_api::KeyValue; use parking_lot::Mutex; use schemars::JsonSchema; @@ -10,6 +11,7 @@ use tower::BoxError; use super::instruments::Increment; use crate::metrics; use crate::plugins::demand_control::CostContext; +use crate::plugins::telemetry::config::AttributeValue; use crate::plugins::telemetry::config_new::attributes::SupergraphAttributes; use crate::plugins::telemetry::config_new::conditions::Condition; use crate::plugins::telemetry::config_new::extendable::Extendable; @@ -24,6 +26,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"; @@ -271,6 +282,29 @@ pub(crate) enum CostValue { Result, } +pub(crate) fn add_cost_attributes(context: &Context, custom_attributes: &mut Vec) { + context.extensions().with_lock(|c| { + if let Some(cost) = c.get::().cloned() { + custom_attributes.push(KeyValue::new( + APOLLO_PRIVATE_COST_ESTIMATED.clone(), + AttributeValue::F64(cost.estimated), + )); + custom_attributes.push(KeyValue::new( + APOLLO_PRIVATE_COST_ACTUAL.clone(), + AttributeValue::F64(cost.actual), + )); + 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()), + )); + } + }); +} + #[cfg(test)] mod test { use crate::context::OPERATION_NAME; diff --git a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/metrics.snap b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/metrics.snap index d4e20acb52..5d112315d7 100644 --- a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/metrics.snap +++ b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/metrics.snap @@ -12,6 +12,8 @@ info: attributes: my_attribute: request_method: true + graphql.operation.name: + operation_name: string --- - name: http.server.request.duration description: Duration of HTTP server requests. @@ -20,6 +22,7 @@ info: datapoints: - sum: 0.1 attributes: + graphql.operation.name: TestQuery http.request.method: GET http.response.status_code: 200 my_attribute: GET diff --git a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/router.yaml b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/router.yaml index a2b1c08b9c..7efc06671c 100644 --- a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/router.yaml +++ b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/router.yaml @@ -6,4 +6,6 @@ telemetry: http.server.request.duration: attributes: my_attribute: - request_method: true \ No newline at end of file + request_method: true + graphql.operation.name: + operation_name: string \ No newline at end of file diff --git a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/test.yaml b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/test.yaml index e3c8e55092..65b1964665 100644 --- a/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/test.yaml +++ b/apollo-router/src/plugins/telemetry/config_new/fixtures/router/http.server.request.duration_with_custom_attributes/test.yaml @@ -5,6 +5,9 @@ events: method: GET body: | hello + - context: + map: + operation_name: TestQuery - router_response: body: | hello diff --git a/apollo-router/src/plugins/telemetry/config_new/instruments.rs b/apollo-router/src/plugins/telemetry/config_new/instruments.rs index 7993a70eeb..2302bb44a6 100644 --- a/apollo-router/src/plugins/telemetry/config_new/instruments.rs +++ b/apollo-router/src/plugins/telemetry/config_new/instruments.rs @@ -1901,7 +1901,6 @@ mod tests { use apollo_compiler::ast::Name; use apollo_compiler::ast::NamedType; use apollo_compiler::executable::SelectionSet; - use apollo_compiler::execution::JsonMap; use http::HeaderMap; use http::HeaderName; use http::Method; @@ -1912,6 +1911,7 @@ mod tests { use schemars::gen::SchemaGenerator; use serde::Deserialize; use serde_json::json; + use serde_json_bytes::ByteString; use serde_json_bytes::Value; use super::*; @@ -1931,6 +1931,8 @@ mod tests { use crate::services::RouterResponse; use crate::Context; + type JsonMap = serde_json_bytes::Map; + #[derive(RustEmbed)] #[folder = "src/plugins/telemetry/config_new/fixtures"] struct Asset; diff --git a/apollo-router/src/plugins/telemetry/config_new/mod.rs b/apollo-router/src/plugins/telemetry/config_new/mod.rs index b66958db4f..dd719e9300 100644 --- a/apollo-router/src/plugins/telemetry/config_new/mod.rs +++ b/apollo-router/src/plugins/telemetry/config_new/mod.rs @@ -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; diff --git a/apollo-router/src/plugins/telemetry/config_new/selectors.rs b/apollo-router/src/plugins/telemetry/config_new/selectors.rs index 81aa3abbe2..4ac034ecbf 100644 --- a/apollo-router/src/plugins/telemetry/config_new/selectors.rs +++ b/apollo-router/src/plugins/telemetry/config_new/selectors.rs @@ -1,10 +1,9 @@ use access_json::JSONQuery; use derivative::Derivative; -use jsonpath_rust::JsonPathFinder; -use jsonpath_rust::JsonPathInst; use opentelemetry_api::Value; use schemars::JsonSchema; use serde::Deserialize; +use serde_json_bytes::path::JsonPathInst; use serde_json_bytes::ByteString; use sha2::Digest; @@ -141,6 +140,17 @@ pub(crate) enum RouterSelector { /// Optional default value. default: Option, }, + /// The operation name from the query. + OperationName { + /// The operation name from the query. + operation_name: OperationName, + #[serde(skip)] + #[allow(dead_code)] + /// Optional redaction pattern. + redact: Option, + /// Optional default value. + default: Option, + }, /// A value from baggage. Baggage { /// The name of the baggage item. @@ -618,6 +628,23 @@ impl Selector for RouterSelector { .as_ref() .and_then(|v| v.maybe_to_otel_value()) .or_else(|| default.maybe_to_otel_value()), + RouterSelector::OperationName { + operation_name, + default, + .. + } => { + let op_name = response.context.get(OPERATION_NAME).ok().flatten(); + match operation_name { + OperationName::String => op_name.or_else(|| default.clone()), + OperationName::Hash => op_name.or_else(|| default.clone()).map(|op_name| { + let mut hasher = sha2::Sha256::new(); + hasher.update(op_name.as_bytes()); + let result = hasher.finalize(); + hex::encode(result) + }), + } + .map(opentelemetry::Value::from) + } RouterSelector::Baggage { baggage, default, .. } => get_baggage(baggage).or_else(|| default.maybe_to_otel_value()), @@ -658,6 +685,23 @@ impl Selector for RouterSelector { .as_ref() .and_then(|v| v.maybe_to_otel_value()) .or_else(|| default.maybe_to_otel_value()), + RouterSelector::OperationName { + operation_name, + default, + .. + } => { + let op_name = ctx.get(OPERATION_NAME).ok().flatten(); + match operation_name { + OperationName::String => op_name.or_else(|| default.clone()), + OperationName::Hash => op_name.or_else(|| default.clone()).map(|op_name| { + let mut hasher = sha2::Sha256::new(); + hasher.update(op_name.as_bytes()); + let result = hasher.finalize(); + hex::encode(result) + }), + } + .map(opentelemetry::Value::from) + } _ => None, } } @@ -818,17 +862,7 @@ impl Selector for SupergraphSelector { default, .. } => if let Some(data) = &response.data { - let data: serde_json::Value = serde_json::to_value(data.clone()).ok()?; - let mut val = - JsonPathFinder::new(Box::new(data), Box::new(response_data.clone())).find(); - if let serde_json::Value::Array(array) = &mut val { - if array.len() == 1 { - val = array - .pop() - .expect("already checked the array had a length of 1; qed"); - } - } - + let val = response_data.find(data); val.maybe_to_otel_value() } else { None @@ -840,16 +874,8 @@ impl Selector for SupergraphSelector { .. } => { let errors = response.errors.clone(); - let data: serde_json::Value = serde_json::to_value(errors).ok()?; - let mut val = - JsonPathFinder::new(Box::new(data), Box::new(response_errors.clone())).find(); - if let serde_json::Value::Array(array) = &mut val { - if array.len() == 1 { - val = array - .pop() - .expect("already checked the array had a length of 1; qed"); - } - } + let data: serde_json_bytes::Value = serde_json_bytes::to_value(errors).ok()?; + let val = response_errors.find(&data); val.maybe_to_otel_value() } @@ -1088,17 +1114,7 @@ impl Selector for SubgraphSelector { default, .. } => if let Some(data) = &response.response.body().data { - let data: serde_json::Value = serde_json::to_value(data.clone()).ok()?; - let mut val = - JsonPathFinder::new(Box::new(data), Box::new(subgraph_response_data.clone())) - .find(); - if let serde_json::Value::Array(array) = &mut val { - if array.len() == 1 { - val = array - .pop() - .expect("already checked the array had a length of 1; qed"); - } - } + let val = subgraph_response_data.find(data); val.maybe_to_otel_value() } else { @@ -1111,17 +1127,9 @@ impl Selector for SubgraphSelector { .. } => { let errors = response.response.body().errors.clone(); - let data: serde_json::Value = serde_json::to_value(errors).ok()?; - let mut val = - JsonPathFinder::new(Box::new(data), Box::new(subgraph_response_error.clone())) - .find(); - if let serde_json::Value::Array(array) = &mut val { - if array.len() == 1 { - val = array - .pop() - .expect("already checked the array had a length of 1; qed"); - } - } + let data: serde_json_bytes::Value = serde_json_bytes::to_value(errors).ok()?; + + let val = subgraph_response_error.find(&data); val.maybe_to_otel_value() } @@ -1176,7 +1184,6 @@ mod test { use std::sync::Arc; use http::StatusCode; - use jsonpath_rust::JsonPathInst; use opentelemetry::baggage::BaggageExt; use opentelemetry::trace::SpanContext; use opentelemetry::trace::SpanId; @@ -1188,6 +1195,7 @@ mod test { use opentelemetry::KeyValue; use opentelemetry_api::StringValue; use serde_json::json; + use serde_json_bytes::path::JsonPathInst; use tower::BoxError; use tracing::span; use tracing::subscriber; @@ -2050,6 +2058,39 @@ mod test { ); } + #[test] + fn router_operation_name_string() { + let selector = RouterSelector::OperationName { + operation_name: OperationName::String, + redact: None, + default: Some("defaulted".to_string()), + }; + let context = crate::context::Context::new(); + assert_eq!( + selector.on_response( + &crate::services::RouterResponse::fake_builder() + .context(context.clone()) + .build() + .unwrap(), + ), + Some("defaulted".into()) + ); + let _ = context.insert(OPERATION_NAME, "topProducts".to_string()); + assert_eq!( + selector.on_response( + &crate::services::RouterResponse::fake_builder() + .context(context.clone()) + .build() + .unwrap(), + ), + Some("topProducts".into()) + ); + assert_eq!( + selector.on_error(&BoxError::from(String::from("my error")), &context), + Some("topProducts".into()) + ); + } + #[test] fn supergraph_env() { let selector = SupergraphSelector::Env { diff --git a/apollo-router/src/plugins/telemetry/config_new/spans.rs b/apollo-router/src/plugins/telemetry/config_new/spans.rs index 3304aecca6..090bb13073 100644 --- a/apollo-router/src/plugins/telemetry/config_new/spans.rs +++ b/apollo-router/src/plugins/telemetry/config_new/spans.rs @@ -111,13 +111,13 @@ mod test { use std::sync::Arc; use http::header::USER_AGENT; - use jsonpath_rust::JsonPathInst; use opentelemetry_semantic_conventions::trace::GRAPHQL_DOCUMENT; use opentelemetry_semantic_conventions::trace::HTTP_REQUEST_METHOD; use opentelemetry_semantic_conventions::trace::NETWORK_PROTOCOL_VERSION; use opentelemetry_semantic_conventions::trace::URL_PATH; use opentelemetry_semantic_conventions::trace::USER_AGENT_ORIGINAL; use parking_lot::Mutex; + use serde_json_bytes::path::JsonPathInst; use crate::context::CONTAINS_GRAPHQL_ERROR; use crate::graphql; diff --git a/apollo-router/src/plugins/telemetry/mod.rs b/apollo-router/src/plugins/telemetry/mod.rs index c980c333f8..d07c052a27 100644 --- a/apollo-router/src/plugins/telemetry/mod.rs +++ b/apollo-router/src/plugins/telemetry/mod.rs @@ -92,6 +92,7 @@ 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::add_cost_attributes; use crate::plugins::telemetry::config_new::graphql::GraphQLInstruments; use crate::plugins::telemetry::config_new::instruments::SupergraphInstruments; use crate::plugins::telemetry::dynamic_attribute::SpanDynAttribute; @@ -588,15 +589,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, SupergraphEvents, GraphQLInstruments), fut| { + move |(ctx, custom_instruments, mut custom_attributes, supergraph_events, custom_graphql_instruments): (Context, SupergraphInstruments, Vec, 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 = 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)); diff --git a/apollo-router/src/plugins/telemetry/tracing/apollo_telemetry.rs b/apollo-router/src/plugins/telemetry/tracing/apollo_telemetry.rs index a916e35986..578da298cf 100644 --- a/apollo-router/src/plugins/telemetry/tracing/apollo_telemetry.rs +++ b/apollo-router/src/plugins/telemetry/tracing/apollo_telemetry.rs @@ -55,6 +55,7 @@ use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_pla 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::Limits; use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::QueryPlanNode; use crate::plugins::telemetry::apollo_exporter::ApolloExporter; use crate::plugins::telemetry::apollo_otlp_exporter::ApolloOtlpExporter; @@ -96,6 +97,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"); @@ -110,7 +119,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, @@ -119,6 +128,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, @@ -261,6 +274,7 @@ enum TreeData { operation_signature: String, operation_name: String, variables_json: HashMap, + limits: Option, }, QueryPlanNode(QueryPlanNode), DeferPrimary(DeferNodePrimary), @@ -395,6 +409,7 @@ impl Exporter { operation_signature, operation_name, variables_json, + limits, } => { root_trace.field_execution_weight = self.field_execution_weight; root_trace.signature = operation_signature; @@ -402,6 +417,7 @@ impl Exporter { variables_json, operation_name, }); + root_trace.limits = limits; results.push(root_trace.clone()); } TreeData::Execution(operation_type) => { @@ -589,6 +605,7 @@ impl Exporter { .get(&APOLLO_PRIVATE_GRAPHQL_VARIABLES) .and_then(extract_json) .unwrap_or_default(), + limits: Some(extract_limits(span)), }); child_nodes } @@ -751,6 +768,7 @@ impl Exporter { .and_then(extract_string) .unwrap_or_default(), variables_json: HashMap::new(), + limits: None, }); child_nodes.push(TreeData::Execution( @@ -769,6 +787,36 @@ impl Exporter { } } +fn extract_limits(span: &LightSpanData) -> Limits { + Limits { + result: span + .attributes + .get(&APOLLO_PRIVATE_COST_RESULT) + .and_then(extract_string) + .unwrap_or_default(), + 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_f64) + .unwrap_or_default() as u64, + cost_actual: span + .attributes + .get(&APOLLO_PRIVATE_COST_ACTUAL) + .and_then(extract_f64) + .unwrap_or_default() as u64, + // TODO fill these out + depth: 0, + height: 0, + alias_count: 0, + root_field_count: 0, + } +} + fn extract_json(v: &Value) -> Option { extract_string(v) .map(|v| serde_json::from_str(&v)) @@ -821,6 +869,14 @@ pub(crate) fn extract_i64(v: &Value) -> Option { } } +pub(crate) fn extract_f64(v: &Value) -> Option { + if let Value::F64(v) = v { + Some(*v) + } else { + None + } +} + pub(crate) fn extract_ftv1_trace_with_error_count( v: &Value, error_config: &ErrorConfiguration, @@ -1136,14 +1192,18 @@ impl ChildNodes for Vec { #[cfg(test)] mod test { + use std::time::SystemTime; use opentelemetry::Value; + use opentelemetry_api::KeyValue; + use opentelemetry_api::trace::{SpanId, SpanKind, TraceId}; + use opentelemetry_sdk::trace::EvictedHashMap; use serde_json::json; use crate::plugins::telemetry::apollo::ErrorConfiguration; use crate::plugins::telemetry::apollo_exporter::proto::reports::Trace; use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_plan_node::{DeferNodePrimary, DeferredNode, ResponsePathElement}; use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::{QueryPlanNode, Node, Error}; use crate::plugins::telemetry::apollo_exporter::proto::reports::trace::query_plan_node::response_path_element::Id; - use crate::plugins::telemetry::tracing::apollo_telemetry::{extract_ftv1_trace, extract_ftv1_trace_with_error_count, extract_i64, extract_json, extract_path, extract_string, preprocess_errors, encode_ftv1_trace, ChildNodes, TreeData}; + use crate::plugins::telemetry::tracing::apollo_telemetry::{extract_ftv1_trace, extract_ftv1_trace_with_error_count, extract_i64, extract_json, extract_path, extract_string, preprocess_errors, encode_ftv1_trace, ChildNodes, TreeData, LightSpanData, APOLLO_PRIVATE_COST_RESULT, APOLLO_PRIVATE_COST_ESTIMATED, APOLLO_PRIVATE_COST_ACTUAL, APOLLO_PRIVATE_COST_STRATEGY, extract_limits}; fn elements(tree_data: Vec) -> Vec<&'static str> { let mut elements = Vec::new(); @@ -1484,4 +1544,38 @@ mod test { assert!(node.error.is_empty()); assert!(node.child[0].error.is_empty()); } + + #[test] + fn test_extract_limits() { + let mut span = LightSpanData { + trace_id: TraceId::from_u128(0), + span_id: SpanId::from_u64(1), + parent_span_id: SpanId::INVALID, + span_kind: SpanKind::Client, + name: Default::default(), + start_time: SystemTime::now(), + end_time: SystemTime::now(), + attributes: EvictedHashMap::new(10, 10), + status: Default::default(), + }; + + span.attributes.insert(KeyValue::new( + APOLLO_PRIVATE_COST_RESULT, + Value::String("OK".into()), + )); + span.attributes.insert(KeyValue::new( + APOLLO_PRIVATE_COST_ESTIMATED, + Value::F64(9.2), + )); + span.attributes + .insert(KeyValue::new(APOLLO_PRIVATE_COST_ACTUAL, Value::F64(6.9))); + span.attributes.insert(KeyValue::new( + APOLLO_PRIVATE_COST_STRATEGY, + Value::String("static_estimated".into()), + )); + let limits = extract_limits(&span); + assert_eq!(limits.result, "OK"); + assert_eq!(limits.cost_estimated, 9); + assert_eq!(limits.cost_actual, 6); + } } diff --git a/apollo-router/src/query_planner/dual_query_planner.rs b/apollo-router/src/query_planner/dual_query_planner.rs index 04c8502c78..9141b4f931 100644 --- a/apollo-router/src/query_planner/dual_query_planner.rs +++ b/apollo-router/src/query_planner/dual_query_planner.rs @@ -125,7 +125,7 @@ impl BothModeComparisonJob { if is_matched { tracing::debug!("JS and Rust query plans match{operation_desc}! 🎉"); } else { - tracing::warn!("JS v.s. Rust query plan mismatch{operation_desc}"); + tracing::debug!("JS v.s. Rust query plan mismatch{operation_desc}"); if let Some(formatted) = &js_plan.formatted_query_plan { tracing::debug!( "Diff of formatted plans:\n{}", diff --git a/apollo-router/tests/apollo_reports.rs b/apollo-router/tests/apollo_reports.rs index ba847ae4e1..e183f29dc8 100644 --- a/apollo-router/tests/apollo_reports.rs +++ b/apollo-router/tests/apollo_reports.rs @@ -54,6 +54,7 @@ async fn config( use_legacy_request_span: bool, batch: bool, reports: Arc>>, + demand_control: bool, ) -> (JoinHandle<()>, serde_json::Value) { std::env::set_var("APOLLO_KEY", "test"); std::env::set_var("APOLLO_GRAPH_REF", "test"); @@ -89,6 +90,10 @@ async fn config( Some(serde_json::Value::Bool(use_legacy_request_span)) }) .expect("Could not sub in endpoint"); + config = jsonpath_lib::replace_with(config, "$.preview_demand_control.enabled", &mut |_| { + Some(serde_json::Value::Bool(demand_control)) + }) + .expect("Could not sub in endpoint"); (task, config) } @@ -96,8 +101,9 @@ async fn get_router_service( reports: Arc>>, use_legacy_request_span: bool, mocked: bool, + demand_control: bool, ) -> (JoinHandle<()>, BoxCloneService) { - let (task, config) = config(use_legacy_request_span, false, reports).await; + let (task, config) = config(use_legacy_request_span, false, reports, demand_control).await; let builder = TestHarness::builder() .try_log_level("INFO") .configuration_json(config) @@ -121,8 +127,9 @@ async fn get_batch_router_service( reports: Arc>>, use_legacy_request_span: bool, mocked: bool, + demand_control: bool, ) -> (JoinHandle<()>, BoxCloneService) { - let (task, config) = config(use_legacy_request_span, true, reports).await; + let (task, config) = config(use_legacy_request_span, true, reports, demand_control).await; let builder = TestHarness::builder() .try_log_level("INFO") .configuration_json(config) @@ -211,6 +218,7 @@ async fn get_trace_report( reports: Arc>>, request: router::Request, use_legacy_request_span: bool, + demand_control: bool, ) -> Report { get_report( get_router_service, @@ -218,6 +226,7 @@ async fn get_trace_report( use_legacy_request_span, false, request, + demand_control, |r| { !r.traces_per_query .values() @@ -234,6 +243,7 @@ async fn get_batch_trace_report( reports: Arc>>, request: router::Request, use_legacy_request_span: bool, + demand_control: bool, ) -> Report { get_report( get_batch_router_service, @@ -241,6 +251,7 @@ async fn get_batch_trace_report( use_legacy_request_span, false, request, + demand_control, |r| { !r.traces_per_query .values() @@ -269,6 +280,7 @@ async fn get_metrics_report(reports: Arc>>, request: router::R false, false, request, + false, has_metrics, ) .await @@ -291,17 +303,19 @@ async fn get_metrics_report_mocked( false, true, request, + false, has_metrics, ) .await } async fn get_report bool + Send + Sync + Copy + 'static>( - service_fn: impl FnOnce(Arc>>, bool, bool) -> Fut, + service_fn: impl FnOnce(Arc>>, bool, bool, bool) -> Fut, reports: Arc>>, use_legacy_request_span: bool, mocked: bool, request: router::Request, + demand_control: bool, filter: T, ) -> Report where @@ -309,7 +323,13 @@ where { let _guard = TEST.lock().await; reports.lock().await.clear(); - let (task, mut service) = service_fn(reports.clone(), use_legacy_request_span, mocked).await; + let (task, mut service) = service_fn( + reports.clone(), + use_legacy_request_span, + mocked, + demand_control, + ) + .await; let response = service .ready() .await @@ -358,7 +378,7 @@ async fn get_batch_stats_report bool + Send + Sync + Copy + ' ) -> u64 { let _guard = TEST.lock().await; reports.lock().await.clear(); - let (task, mut service) = get_batch_router_service(reports.clone(), mocked, false).await; + let (task, mut service) = get_batch_router_service(reports.clone(), mocked, false, false).await; let response = service .ready() .await @@ -402,7 +422,7 @@ async fn non_defer() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -418,7 +438,7 @@ async fn test_condition_if() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -434,7 +454,7 @@ async fn test_condition_else() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -448,7 +468,7 @@ async fn test_trace_id() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -472,7 +492,8 @@ async fn test_batch_trace_id() { hyper::Body::from(result) }); let reports = Arc::new(Mutex::new(vec![])); - let report = get_batch_trace_report(reports, request.into(), use_legacy_request_span).await; + let report = + get_batch_trace_report(reports, request.into(), use_legacy_request_span, false).await; assert_report!(report); } } @@ -487,7 +508,7 @@ async fn test_client_name() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -502,7 +523,7 @@ async fn test_client_version() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -518,7 +539,7 @@ async fn test_send_header() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -544,7 +565,8 @@ async fn test_batch_send_header() { hyper::Body::from(result) }); let reports = Arc::new(Mutex::new(vec![])); - let report = get_batch_trace_report(reports, request.into(), use_legacy_request_span).await; + let report = + get_batch_trace_report(reports, request.into(), use_legacy_request_span, false).await; assert_report!(report); } } @@ -560,7 +582,7 @@ async fn test_send_variable_value() { .unwrap(); let req: router::Request = request.try_into().expect("could not convert request"); let reports = Arc::new(Mutex::new(vec![])); - let report = get_trace_report(reports, req, use_legacy_request_span).await; + let report = get_trace_report(reports, req, use_legacy_request_span, false).await; assert_report!(report); } } @@ -620,3 +642,42 @@ async fn test_stats_mocked() { }); }); } + +#[tokio::test(flavor = "multi_thread")] +async fn test_demand_control_trace() { + for use_legacy_request_span in [true, false] { + let request = supergraph::Request::fake_builder() + .query("query{topProducts{name reviews {author{name}} reviews{author{name}}}}") + .build() + .unwrap(); + let req: router::Request = request.try_into().expect("could not convert request"); + let reports = Arc::new(Mutex::new(vec![])); + let report = get_trace_report(reports, req, use_legacy_request_span, true).await; + assert_report!(report); + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_demand_control_trace_batched() { + for use_legacy_request_span in [true, false] { + let request = supergraph::Request::fake_builder() + .query("query{topProducts{name reviews {author{name}} reviews{author{name}}}}") + .build() + .unwrap() + .supergraph_request + .map(|req| { + // Modify the request so that it is a valid array of requests. + let mut json_bytes = serde_json::to_vec(&req).unwrap(); + let mut result = vec![b'[']; + result.append(&mut json_bytes.clone()); + result.push(b','); + result.append(&mut json_bytes); + result.push(b']'); + hyper::Body::from(result) + }); + let req: router::Request = request.into(); + let reports = Arc::new(Mutex::new(vec![])); + let report = get_batch_trace_report(reports, req, use_legacy_request_span, true).await; + assert_report!(report); + } +} diff --git a/apollo-router/tests/fixtures/apollo_reports.router.yaml b/apollo-router/tests/fixtures/apollo_reports.router.yaml index 846c40410d..a3cd9c571a 100644 --- a/apollo-router/tests/fixtures/apollo_reports.router.yaml +++ b/apollo-router/tests/fixtures/apollo_reports.router.yaml @@ -3,6 +3,13 @@ include_subgraph_errors: rhai: scripts: tests/fixtures main: test_callbacks.rhai +preview_demand_control: + mode: measure + enabled: false + strategy: + static_estimated: + max: 1500 + list_size: 10 telemetry: instrumentation: spans: diff --git a/apollo-router/tests/fixtures/apollo_reports_batch.router.yaml b/apollo-router/tests/fixtures/apollo_reports_batch.router.yaml index 29ad9c9630..5790a7aa65 100644 --- a/apollo-router/tests/fixtures/apollo_reports_batch.router.yaml +++ b/apollo-router/tests/fixtures/apollo_reports_batch.router.yaml @@ -6,6 +6,13 @@ rhai: main: test_callbacks.rhai include_subgraph_errors: all: true +preview_demand_control: + mode: measure + enabled: false + strategy: + static_estimated: + max: 1500 + list_size: 10 telemetry: exporters: tracing: diff --git a/apollo-router/tests/snapshots/apollo_reports__batch_send_header-2.snap b/apollo-router/tests/snapshots/apollo_reports__batch_send_header-2.snap index 15c2327c19..760e662f56 100644 --- a/apollo-router/tests/snapshots/apollo_reports__batch_send_header-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__batch_send_header-2.snap @@ -552,7 +552,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 - start_time: seconds: "[seconds]" nanos: "[nanos]" @@ -1092,7 +1100,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__batch_send_header.snap b/apollo-router/tests/snapshots/apollo_reports__batch_send_header.snap index 15c2327c19..760e662f56 100644 --- a/apollo-router/tests/snapshots/apollo_reports__batch_send_header.snap +++ b/apollo-router/tests/snapshots/apollo_reports__batch_send_header.snap @@ -552,7 +552,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 - start_time: seconds: "[seconds]" nanos: "[nanos]" @@ -1092,7 +1100,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__batch_trace_id-2.snap b/apollo-router/tests/snapshots/apollo_reports__batch_trace_id-2.snap index e152be5676..f7c1ad4188 100644 --- a/apollo-router/tests/snapshots/apollo_reports__batch_trace_id-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__batch_trace_id-2.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 - start_time: seconds: "[seconds]" nanos: "[nanos]" @@ -1086,7 +1094,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__batch_trace_id.snap b/apollo-router/tests/snapshots/apollo_reports__batch_trace_id.snap index e152be5676..f7c1ad4188 100644 --- a/apollo-router/tests/snapshots/apollo_reports__batch_trace_id.snap +++ b/apollo-router/tests/snapshots/apollo_reports__batch_trace_id.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 - start_time: seconds: "[seconds]" nanos: "[nanos]" @@ -1086,7 +1094,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__client_name-2.snap b/apollo-router/tests/snapshots/apollo_reports__client_name-2.snap index cdd69f128b..c05170f09e 100644 --- a/apollo-router/tests/snapshots/apollo_reports__client_name-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__client_name-2.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__client_name.snap b/apollo-router/tests/snapshots/apollo_reports__client_name.snap index cdd69f128b..c05170f09e 100644 --- a/apollo-router/tests/snapshots/apollo_reports__client_name.snap +++ b/apollo-router/tests/snapshots/apollo_reports__client_name.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__client_version-2.snap b/apollo-router/tests/snapshots/apollo_reports__client_version-2.snap index 3e0f375077..aecb5e78fe 100644 --- a/apollo-router/tests/snapshots/apollo_reports__client_version-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__client_version-2.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__client_version.snap b/apollo-router/tests/snapshots/apollo_reports__client_version.snap index 3e0f375077..aecb5e78fe 100644 --- a/apollo-router/tests/snapshots/apollo_reports__client_version.snap +++ b/apollo-router/tests/snapshots/apollo_reports__client_version.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__condition_else-2.snap b/apollo-router/tests/snapshots/apollo_reports__condition_else-2.snap index bb048564c8..1a3748a9c6 100644 --- a/apollo-router/tests/snapshots/apollo_reports__condition_else-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__condition_else-2.snap @@ -555,7 +555,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__condition_else.snap b/apollo-router/tests/snapshots/apollo_reports__condition_else.snap index bb048564c8..1a3748a9c6 100644 --- a/apollo-router/tests/snapshots/apollo_reports__condition_else.snap +++ b/apollo-router/tests/snapshots/apollo_reports__condition_else.snap @@ -555,7 +555,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__condition_if-2.snap b/apollo-router/tests/snapshots/apollo_reports__condition_if-2.snap index 2e45b53a67..a043c1c333 100644 --- a/apollo-router/tests/snapshots/apollo_reports__condition_if-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__condition_if-2.snap @@ -568,7 +568,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__condition_if.snap b/apollo-router/tests/snapshots/apollo_reports__condition_if.snap index 2e45b53a67..a043c1c333 100644 --- a/apollo-router/tests/snapshots/apollo_reports__condition_if.snap +++ b/apollo-router/tests/snapshots/apollo_reports__condition_if.snap @@ -568,7 +568,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__demand_control_trace-2.snap b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace-2.snap new file mode 100644 index 0000000000..3ab1b3fbfd --- /dev/null +++ b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace-2.snap @@ -0,0 +1,568 @@ +--- +source: apollo-router/tests/apollo_reports.rs +expression: report +--- +header: + graph_ref: test + hostname: "[hostname]" + agent_version: "[agent_version]" + service_version: "" + runtime_version: rust + uname: "[uname]" + executable_schema_id: "[executable_schema_id]" +traces_per_query: + "# -\n{topProducts{name reviews{author{name}}reviews{author{name}}}}": + trace: + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + stats_with_context: [] + referenced_fields_by_type: {} + query_metadata: ~ +end_time: "[end_time]" +operation_count: 0 +operation_count_by_type: [] +traces_pre_aggregated: true +extended_references_enabled: false diff --git a/apollo-router/tests/snapshots/apollo_reports__demand_control_trace.snap b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace.snap new file mode 100644 index 0000000000..3ab1b3fbfd --- /dev/null +++ b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace.snap @@ -0,0 +1,568 @@ +--- +source: apollo-router/tests/apollo_reports.rs +expression: report +--- +header: + graph_ref: test + hostname: "[hostname]" + agent_version: "[agent_version]" + service_version: "" + runtime_version: rust + uname: "[uname]" + executable_schema_id: "[executable_schema_id]" +traces_per_query: + "# -\n{topProducts{name reviews{author{name}}reviews{author{name}}}}": + trace: + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + stats_with_context: [] + referenced_fields_by_type: {} + query_metadata: ~ +end_time: "[end_time]" +operation_count: 0 +operation_count_by_type: [] +traces_pre_aggregated: true +extended_references_enabled: false diff --git a/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched-2.snap b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched-2.snap new file mode 100644 index 0000000000..f3b05b402a --- /dev/null +++ b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched-2.snap @@ -0,0 +1,1113 @@ +--- +source: apollo-router/tests/apollo_reports.rs +expression: report +--- +header: + graph_ref: test + hostname: "[hostname]" + agent_version: "[agent_version]" + service_version: "" + runtime_version: rust + uname: "[uname]" + executable_schema_id: "[executable_schema_id]" +traces_per_query: + "# -\n{topProducts{name reviews{author{name}}reviews{author{name}}}}": + trace: + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + stats_with_context: [] + referenced_fields_by_type: {} + query_metadata: ~ +end_time: "[end_time]" +operation_count: 0 +operation_count_by_type: [] +traces_pre_aggregated: true +extended_references_enabled: false diff --git a/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched.snap b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched.snap new file mode 100644 index 0000000000..f3b05b402a --- /dev/null +++ b/apollo-router/tests/snapshots/apollo_reports__demand_control_trace_batched.snap @@ -0,0 +1,1113 @@ +--- +source: apollo-router/tests/apollo_reports.rs +expression: report +--- +header: + graph_ref: test + hostname: "[hostname]" + agent_version: "[agent_version]" + service_version: "" + runtime_version: rust + uname: "[uname]" + executable_schema_id: "[executable_schema_id]" +traces_per_query: + "# -\n{topProducts{name reviews{author{name}}reviews{author{name}}}}": + trace: + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + - start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: + variables_json: {} + operation_name: "" + client_name: "" + client_version: "" + operation_type: query + operation_subtype: "" + http: + method: 4 + request_headers: {} + response_headers: + my_trace_id: "[my_trace_id]" + status_code: 0 + cache_policy: ~ + query_plan: + node: + Sequence: + nodes: + - node: + Fetch: + service_name: products + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[Product]" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String! + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: upc + - original_field_name: "" + type: String + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 2 + id: + ResponseName: topProducts + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + node: + node: + Fetch: + service_name: reviews + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 1 + id: + ResponseName: reviews + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 1 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "[Review]" + parent_type: Product + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: User + parent_type: Review + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: ID! + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: id + id: + ResponseName: author + id: + Index: 0 + id: + ResponseName: reviews + id: + Index: 2 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + - node: + Flatten: + response_path: + - id: + FieldName: topProducts + - id: + FieldName: reviews + - id: + FieldName: author + node: + node: + Fetch: + service_name: accounts + trace_parsing_failed: false + trace: + start_time: + seconds: "[seconds]" + nanos: "[nanos]" + end_time: + seconds: "[seconds]" + nanos: "[nanos]" + duration_ns: "[duration_ns]" + root: + original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: 0 + end_time: 0 + error: [] + child: + - original_field_name: "" + type: "[_Entity]!" + parent_type: Query + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 0 + - original_field_name: "" + type: "" + parent_type: "" + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: + - original_field_name: "" + type: String + parent_type: User + cache_policy: ~ + start_time: "[start_time]" + end_time: "[end_time]" + error: [] + child: [] + id: + ResponseName: name + id: + Index: 1 + id: + ResponseName: _entities + id: ~ + is_incomplete: false + signature: "" + unexecuted_operation_body: "" + unexecuted_operation_name: "" + details: ~ + client_name: "" + client_version: "" + operation_type: "" + operation_subtype: "" + http: ~ + cache_policy: ~ + query_plan: ~ + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: ~ + sent_time_offset: "[sent_time_offset]" + sent_time: + seconds: "[seconds]" + nanos: "[nanos]" + received_time: + seconds: "[seconds]" + nanos: "[nanos]" + full_query_cache_hit: false + persisted_query_hit: false + persisted_query_register: false + registered_operation: false + forbidden_operation: false + field_execution_weight: 1 + limits: + result: COST_OK + strategy: static_estimated + cost_estimated: 230 + cost_actual: 19 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 + stats_with_context: [] + referenced_fields_by_type: {} + query_metadata: ~ +end_time: "[end_time]" +operation_count: 0 +operation_count_by_type: [] +traces_pre_aggregated: true +extended_references_enabled: false diff --git a/apollo-router/tests/snapshots/apollo_reports__non_defer-2.snap b/apollo-router/tests/snapshots/apollo_reports__non_defer-2.snap index 16c6d72247..b36f7341ee 100644 --- a/apollo-router/tests/snapshots/apollo_reports__non_defer-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__non_defer-2.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__non_defer.snap b/apollo-router/tests/snapshots/apollo_reports__non_defer.snap index 16c6d72247..b36f7341ee 100644 --- a/apollo-router/tests/snapshots/apollo_reports__non_defer.snap +++ b/apollo-router/tests/snapshots/apollo_reports__non_defer.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__send_header-2.snap b/apollo-router/tests/snapshots/apollo_reports__send_header-2.snap index d4cc1e50f9..448af827a8 100644 --- a/apollo-router/tests/snapshots/apollo_reports__send_header-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__send_header-2.snap @@ -552,7 +552,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__send_header.snap b/apollo-router/tests/snapshots/apollo_reports__send_header.snap index d4cc1e50f9..448af827a8 100644 --- a/apollo-router/tests/snapshots/apollo_reports__send_header.snap +++ b/apollo-router/tests/snapshots/apollo_reports__send_header.snap @@ -552,7 +552,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__send_variable_value-2.snap b/apollo-router/tests/snapshots/apollo_reports__send_variable_value-2.snap index 9bd1bcf5c4..31c50d581c 100644 --- a/apollo-router/tests/snapshots/apollo_reports__send_variable_value-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__send_variable_value-2.snap @@ -551,7 +551,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__send_variable_value.snap b/apollo-router/tests/snapshots/apollo_reports__send_variable_value.snap index 9bd1bcf5c4..31c50d581c 100644 --- a/apollo-router/tests/snapshots/apollo_reports__send_variable_value.snap +++ b/apollo-router/tests/snapshots/apollo_reports__send_variable_value.snap @@ -551,7 +551,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__trace_id-2.snap b/apollo-router/tests/snapshots/apollo_reports__trace_id-2.snap index 16c6d72247..b36f7341ee 100644 --- a/apollo-router/tests/snapshots/apollo_reports__trace_id-2.snap +++ b/apollo-router/tests/snapshots/apollo_reports__trace_id-2.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/snapshots/apollo_reports__trace_id.snap b/apollo-router/tests/snapshots/apollo_reports__trace_id.snap index 16c6d72247..b36f7341ee 100644 --- a/apollo-router/tests/snapshots/apollo_reports__trace_id.snap +++ b/apollo-router/tests/snapshots/apollo_reports__trace_id.snap @@ -549,7 +549,15 @@ traces_per_query: registered_operation: false forbidden_operation: false field_execution_weight: 1 - limits: ~ + limits: + result: "" + strategy: "" + cost_estimated: 0 + cost_actual: 0 + depth: 0 + height: 0 + alias_count: 0 + root_field_count: 0 stats_with_context: [] referenced_fields_by_type: {} query_metadata: ~ diff --git a/apollo-router/tests/type_conditions.rs b/apollo-router/tests/type_conditions.rs index 8d3afbd206..aa109807d2 100644 --- a/apollo-router/tests/type_conditions.rs +++ b/apollo-router/tests/type_conditions.rs @@ -2,7 +2,6 @@ //! Please ensure that any tests added to this file use the tokio multi-threaded test executor. //! -use apollo_compiler::execution::JsonMap; use apollo_router::graphql::Request; use apollo_router::graphql::Response; use apollo_router::plugin::test::MockSubgraph; @@ -11,8 +10,12 @@ use apollo_router::MockedSubgraphs; use apollo_router::TestHarness; use serde::Deserialize; use serde_json::json; +use serde_json_bytes::ByteString; +use serde_json_bytes::Value; use tower::ServiceExt; +type JsonMap = serde_json_bytes::Map; + #[derive(Deserialize)] struct SubgraphMock { mocks: Vec, diff --git a/dockerfiles/tracing/docker-compose.datadog.yml b/dockerfiles/tracing/docker-compose.datadog.yml index f04ac66fa6..7fa6d3615b 100644 --- a/dockerfiles/tracing/docker-compose.datadog.yml +++ b/dockerfiles/tracing/docker-compose.datadog.yml @@ -3,7 +3,7 @@ services: apollo-router: container_name: apollo-router - image: ghcr.io/apollographql/router:v1.48.1 + image: ghcr.io/apollographql/router:v1.49.0-rc.1 volumes: - ./supergraph.graphql:/etc/config/supergraph.graphql - ./router/datadog.router.yaml:/etc/config/configuration.yaml diff --git a/dockerfiles/tracing/docker-compose.jaeger.yml b/dockerfiles/tracing/docker-compose.jaeger.yml index c111539476..d904a4e6de 100644 --- a/dockerfiles/tracing/docker-compose.jaeger.yml +++ b/dockerfiles/tracing/docker-compose.jaeger.yml @@ -4,7 +4,7 @@ services: apollo-router: container_name: apollo-router #build: ./router - image: ghcr.io/apollographql/router:v1.48.1 + image: ghcr.io/apollographql/router:v1.49.0-rc.1 volumes: - ./supergraph.graphql:/etc/config/supergraph.graphql - ./router/jaeger.router.yaml:/etc/config/configuration.yaml diff --git a/dockerfiles/tracing/docker-compose.zipkin.yml b/dockerfiles/tracing/docker-compose.zipkin.yml index 223c1ed6c4..9efe97f40b 100644 --- a/dockerfiles/tracing/docker-compose.zipkin.yml +++ b/dockerfiles/tracing/docker-compose.zipkin.yml @@ -4,7 +4,7 @@ services: apollo-router: container_name: apollo-router build: ./router - image: ghcr.io/apollographql/router:v1.48.1 + image: ghcr.io/apollographql/router:v1.49.0-rc.1 volumes: - ./supergraph.graphql:/etc/config/supergraph.graphql - ./router/zipkin.router.yaml:/etc/config/configuration.yaml diff --git a/docs/source/configuration/overview.mdx b/docs/source/configuration/overview.mdx index a14d850462..772d6e0f1c 100644 --- a/docs/source/configuration/overview.mdx +++ b/docs/source/configuration/overview.mdx @@ -578,6 +578,168 @@ The default value of `experimental_parallelism` is `1`. In practice, you should tune `experimental_parallelism` based on metrics and benchmarks gathered from your router. + + +### Enhanced operation signature normalization + + + + + +Apollo's legacy operation signature algorithm removes information about certain fields, such as input objects and aliases. +This removal means some operations may have the same normalized signature though they are distinct operations. + +Beginning in v1.49.0, the router supports enhanced operation signature normalization. +Enhanced normalization incorporates [input types](#input-types) and [aliases](#aliases) in signature generation. +It also includes other improvements that make it more likely that two operations that only vary slightly have the same signature. + +Configure enhanced operation signature normalization in `router.yaml` with the `telemetry.apollo.experimental_apollo_signature_normalization_algorithm` option: + +```yaml title="router.yaml" +telemetry: + apollo: + experimental_apollo_signature_normalization_algorithm: enhanced # Default is legacy +``` + +Once you enable this configuration, operations with enhanced signatures appear with different operation IDs than they did previously in GraphOS Studio. + +#### Input types + +Enhanced signatures include input object type shapes, while still redacting any actual values. +Legacy signatures [replace input object type with `{}`](/graphos/metrics/operation-signatures/#1-transform-in-line-argument-values). + +Given the following example operation: + +```graphql showLineNumbers=false +query InlineInputTypeQuery { + inputTypeQuery( + input: { + inputString: "foo", + inputInt: 42, + inputBoolean: null, + nestedType: { someFloat: 4.2 }, + enumInput: SOME_VALUE_1, + nestedTypeList: [ { someFloat: 4.2, someNullableFloat: null } ], + listInput: [1, 2, 3] + } + ) { + enumResponse + } +} +``` + +The legacy normalization algorithm generates the following signature: + +```graphql showLineNumbers=false +query InlineInputTypeQuery { + inputTypeQuery(input: {}) { + enumResponse + } +} +``` + +The enhanced normalization algorithm generates the following signature: + +```graphql {3-11} showLineNumbers=false +query InlineInputTypeQuery { + inputTypeQuery( + input: { + inputString: "", + inputInt: 0, + inputBoolean: null, + nestedType: {someFloat: 0}, + enumInput: SOME_VALUE_1, + nestedTypeList: [{someFloat: 0, someNullableFloat: null}], + listInput: [] + } + ) { + enumResponse + } +} +``` + +#### Aliases + +Enhanced signatures include any field aliases used in an operation. +Legacy signatures [remove aliases completely](/graphos/metrics/operation-signatures/#field-aliases), meaning the signature may be invalid if the same field was used with multiple aliases. + +Given the following example operation: + +```graphql showLineNumbers=false +query AliasedQuery { + noInputQuery { + interfaceAlias1: interfaceResponse { + sharedField + } + interfaceAlias2: interfaceResponse { + ... on InterfaceImplementation1 { + implementation1Field + } + ... on InterfaceImplementation2 { + implementation2Field + } + } + inputFieldAlias1: objectTypeWithInputField(boolInput: true) { + stringField + } + inputFieldAlias2: objectTypeWithInputField(boolInput: false) { + intField + } + } +} +``` + +The legacy normalization algorithm generates the following signature: + +```graphql showLineNumbers=false +query AliasedQuery { + noInputQuery { + interfaceResponse { + sharedField + } + interfaceResponse { + ... on InterfaceImplementation1 { + implementation1Field + } + ... on InterfaceImplementation2 { + implementation2Field + } + } + objectTypeWithInputField(boolInput: true) { + stringField + } + objectTypeWithInputField(boolInput: false) { + intField + } + } +} +``` + +The enhanced normalization algorithm generates the following signature: + +```graphql showLineNumbers=false +query AliasedQuery { + noInputQuery { + interfaceAlias1: interfaceResponse { + sharedField + } + interfaceAlias2: interfaceResponse { + ... on InterfaceImplementation1 { + implementation1Field + } + ... on InterfaceImplementation2 { + implementation2Field + } + } + inputFieldAlias1: objectTypeWithInputField(boolInput: true) { + stringField + } + inputFieldAlias2: objectTypeWithInputField(boolInput: false) { + intField + } + } +} +``` ### Safelisting with persisted queries diff --git a/docs/source/configuration/telemetry/instrumentation/selectors.mdx b/docs/source/configuration/telemetry/instrumentation/selectors.mdx index eff7447651..e09b306df9 100644 --- a/docs/source/configuration/telemetry/instrumentation/selectors.mdx +++ b/docs/source/configuration/telemetry/instrumentation/selectors.mdx @@ -32,7 +32,8 @@ The router service is the initial entrypoint for all requests. It is HTTP centri | Selector | Defaultable | Values | Description | |--------------------|-------------|-------------------------------------------|--------------------------------------| -| `trace_id` | Yes | `open_telemetry`\|`datadog` | The trace ID | +| `trace_id` | Yes | `open_telemetry`\|`datadog` | The trace ID | +| `operation_name` | Yes | `string`|`hash` | The operation name from the query | | `studio_operation_id` | Yes | `true`|`false` | The Apollo Studio operation id | | `request_header` | Yes | | The name of the request header | | `response_header` | Yes | | The name of a response header | diff --git a/examples/async-auth/rust/Cargo.toml b/examples/async-auth/rust/Cargo.toml index 70c615fc74..5749743aea 100644 --- a/examples/async-auth/rust/Cargo.toml +++ b/examples/async-auth/rust/Cargo.toml @@ -12,6 +12,6 @@ http = "0.2" schemars = { version = "0.8", features = ["url"] } serde = "1" serde_json = "1" -serde_json_bytes = "0.2" +serde_json_bytes.workspace = true tokio = { version = "1", features = ["full"] } tower = { version = "0.4", features = ["full"] } diff --git a/helm/chart/router/Chart.yaml b/helm/chart/router/Chart.yaml index ca518c7196..4d0bad4031 100644 --- a/helm/chart/router/Chart.yaml +++ b/helm/chart/router/Chart.yaml @@ -20,10 +20,10 @@ type: application # so it matches the shape of our release process and release automation. # By proxy of that decision, this version uses SemVer 2.0.0, though the prefix # of "v" is not included. -version: 1.48.1 +version: 1.49.0-rc.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v1.48.1" +appVersion: "v1.49.0-rc.1" diff --git a/helm/chart/router/README.md b/helm/chart/router/README.md index 75677ed3eb..ad9ccc1d21 100644 --- a/helm/chart/router/README.md +++ b/helm/chart/router/README.md @@ -2,7 +2,7 @@ [router](https://github.com/apollographql/router) Rust Graph Routing runtime for Apollo Federation -![Version: 1.48.1](https://img.shields.io/badge/Version-1.48.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.48.1](https://img.shields.io/badge/AppVersion-v1.48.1-informational?style=flat-square) +![Version: 1.49.0-rc.1](https://img.shields.io/badge/Version-1.49.0--rc.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.49.0-rc.1](https://img.shields.io/badge/AppVersion-v1.49.0--rc.1-informational?style=flat-square) ## Prerequisites @@ -11,7 +11,7 @@ ## Get Repo Info ```console -helm pull oci://ghcr.io/apollographql/helm-charts/router --version 1.48.1 +helm pull oci://ghcr.io/apollographql/helm-charts/router --version 1.49.0-rc.1 ``` ## Install Chart @@ -19,7 +19,7 @@ helm pull oci://ghcr.io/apollographql/helm-charts/router --version 1.48.1 **Important:** only helm3 is supported ```console -helm upgrade --install [RELEASE_NAME] oci://ghcr.io/apollographql/helm-charts/router --version 1.48.1 --values my-values.yaml +helm upgrade --install [RELEASE_NAME] oci://ghcr.io/apollographql/helm-charts/router --version 1.49.0-rc.1 --values my-values.yaml ``` _See [configuration](#configuration) below._ @@ -95,4 +95,4 @@ helm show values oci://ghcr.io/apollographql/helm-charts/router | virtualservice.enabled | bool | `false` | | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) +Autogenerated from chart metadata using [helm-docs v1.11.2](https://github.com/norwoodj/helm-docs/releases/v1.11.2) diff --git a/licenses.html b/licenses.html index d2aea988ab..228a27cd2a 100644 --- a/licenses.html +++ b/licenses.html @@ -44,13 +44,13 @@

Third Party Licenses

Overview of licenses:

    -
  • Apache License 2.0 (482)
  • -
  • MIT License (152)
  • -
  • BSD 3-Clause "New" or "Revised" License (12)
  • -
  • ISC License (11)
  • -
  • Elastic License 2.0 (6)
  • -
  • BSD 2-Clause "Simplified" License (3)
  • +
  • MIT License (90)
  • +
  • Apache License 2.0 (71)
  • +
  • BSD 3-Clause "New" or "Revised" License (10)
  • +
  • ISC License (7)
  • +
  • Elastic License 2.0 (3)
  • Mozilla Public License 2.0 (3)
  • +
  • BSD 2-Clause "Simplified" License (2)
  • Creative Commons Zero v1.0 Universal (2)
  • OpenSSL License (2)
  • Unicode License Agreement - Data Files and Software (2016) (1)
  • @@ -4653,6 +4653,204 @@

    Used by:

    of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + + +
  • +

    Apache License 2.0

    +

    Used by:

    + +
                                     Apache License
    +                           Version 2.0, January 2004
    +                        http://www.apache.org/licenses/
    +
    +   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    +
    +   1. Definitions.
    +
    +      "License" shall mean the terms and conditions for use, reproduction,
    +      and distribution as defined by Sections 1 through 9 of this document.
    +
    +      "Licensor" shall mean the copyright owner or entity authorized by
    +      the copyright owner that is granting the License.
    +
    +      "Legal Entity" shall mean the union of the acting entity and all
    +      other entities that control, are controlled by, or are under common
    +      control with that entity. For the purposes of this definition,
    +      "control" means (i) the power, direct or indirect, to cause the
    +      direction or management of such entity, whether by contract or
    +      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    +      outstanding shares, or (iii) beneficial ownership of such entity.
    +
    +      "You" (or "Your") shall mean an individual or Legal Entity
    +      exercising permissions granted by this License.
    +
    +      "Source" form shall mean the preferred form for making modifications,
    +      including but not limited to software source code, documentation
    +      source, and configuration files.
    +
    +      "Object" form shall mean any form resulting from mechanical
    +      transformation or translation of a Source form, including but
    +      not limited to compiled object code, generated documentation,
    +      and conversions to other media types.
    +
    +      "Work" shall mean the work of authorship, whether in Source or
    +      Object form, made available under the License, as indicated by a
    +      copyright notice that is included in or attached to the work
    +      (an example is provided in the Appendix below).
    +
    +      "Derivative Works" shall mean any work, whether in Source or Object
    +      form, that is based on (or derived from) the Work and for which the
    +      editorial revisions, annotations, elaborations, or other modifications
    +      represent, as a whole, an original work of authorship. For the purposes
    +      of this License, Derivative Works shall not include works that remain
    +      separable from, or merely link (or bind by name) to the interfaces of,
    +      the Work and Derivative Works thereof.
    +
    +      "Contribution" shall mean any work of authorship, including
    +      the original version of the Work and any modifications or additions
    +      to that Work or Derivative Works thereof, that is intentionally
    +      submitted to Licensor for inclusion in the Work by the copyright owner
    +      or by an individual or Legal Entity authorized to submit on behalf of
    +      the copyright owner. For the purposes of this definition, "submitted"
    +      means any form of electronic, verbal, or written communication sent
    +      to the Licensor or its representatives, including but not limited to
    +      communication on electronic mailing lists, source code control systems,
    +      and issue tracking systems that are managed by, or on behalf of, the
    +      Licensor for the purpose of discussing and improving the Work, but
    +      excluding communication that is conspicuously marked or otherwise
    +      designated in writing by the copyright owner as "Not a Contribution."
    +
    +      "Contributor" shall mean Licensor and any individual or Legal Entity
    +      on behalf of whom a Contribution has been received by Licensor and
    +      subsequently incorporated within the Work.
    +
    +   2. Grant of Copyright License. Subject to the terms and conditions of
    +      this License, each Contributor hereby grants to You a perpetual,
    +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    +      copyright license to reproduce, prepare Derivative Works of,
    +      publicly display, publicly perform, sublicense, and distribute the
    +      Work and such Derivative Works in Source or Object form.
    +
    +   3. Grant of Patent License. Subject to the terms and conditions of
    +      this License, each Contributor hereby grants to You a perpetual,
    +      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    +      (except as stated in this section) patent license to make, have made,
    +      use, offer to sell, sell, import, and otherwise transfer the Work,
    +      where such license applies only to those patent claims licensable
    +      by such Contributor that are necessarily infringed by their
    +      Contribution(s) alone or by combination of their Contribution(s)
    +      with the Work to which such Contribution(s) was submitted. If You
    +      institute patent litigation against any entity (including a
    +      cross-claim or counterclaim in a lawsuit) alleging that the Work
    +      or a Contribution incorporated within the Work constitutes direct
    +      or contributory patent infringement, then any patent licenses
    +      granted to You under this License for that Work shall terminate
    +      as of the date such litigation is filed.
    +
    +   4. Redistribution. You may reproduce and distribute copies of the
    +      Work or Derivative Works thereof in any medium, with or without
    +      modifications, and in Source or Object form, provided that You
    +      meet the following conditions:
    +
    +      (a) You must give any other recipients of the Work or
    +          Derivative Works a copy of this License; and
    +
    +      (b) You must cause any modified files to carry prominent notices
    +          stating that You changed the files; and
    +
    +      (c) You must retain, in the Source form of any Derivative Works
    +          that You distribute, all copyright, patent, trademark, and
    +          attribution notices from the Source form of the Work,
    +          excluding those notices that do not pertain to any part of
    +          the Derivative Works; and
    +
    +      (d) If the Work includes a "NOTICE" text file as part of its
    +          distribution, then any Derivative Works that You distribute must
    +          include a readable copy of the attribution notices contained
    +          within such NOTICE file, excluding those notices that do not
    +          pertain to any part of the Derivative Works, in at least one
    +          of the following places: within a NOTICE text file distributed
    +          as part of the Derivative Works; within the Source form or
    +          documentation, if provided along with the Derivative Works; or,
    +          within a display generated by the Derivative Works, if and
    +          wherever such third-party notices normally appear. The contents
    +          of the NOTICE file are for informational purposes only and
    +          do not modify the License. You may add Your own attribution
    +          notices within Derivative Works that You distribute, alongside
    +          or as an addendum to the NOTICE text from the Work, provided
    +          that such additional attribution notices cannot be construed
    +          as modifying the License.
    +
    +      You may add Your own copyright statement to Your modifications and
    +      may provide additional or different license terms and conditions
    +      for use, reproduction, or distribution of Your modifications, or
    +      for any such Derivative Works as a whole, provided Your use,
    +      reproduction, and distribution of the Work otherwise complies with
    +      the conditions stated in this License.
    +
    +   5. Submission of Contributions. Unless You explicitly state otherwise,
    +      any Contribution intentionally submitted for inclusion in the Work
    +      by You to the Licensor shall be under the terms and conditions of
    +      this License, without any additional terms or conditions.
    +      Notwithstanding the above, nothing herein shall supersede or modify
    +      the terms of any separate license agreement you may have executed
    +      with Licensor regarding such Contributions.
    +
    +   6. Trademarks. This License does not grant permission to use the trade
    +      names, trademarks, service marks, or product names of the Licensor,
    +      except as required for reasonable and customary use in describing the
    +      origin of the Work and reproducing the content of the NOTICE file.
    +
    +   7. Disclaimer of Warranty. Unless required by applicable law or
    +      agreed to in writing, Licensor provides the Work (and each
    +      Contributor provides its Contributions) on an "AS IS" BASIS,
    +      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    +      implied, including, without limitation, any warranties or conditions
    +      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    +      PARTICULAR PURPOSE. You are solely responsible for determining the
    +      appropriateness of using or redistributing the Work and assume any
    +      risks associated with Your exercise of permissions under this License.
    +
    +   8. Limitation of Liability. In no event and under no legal theory,
    +      whether in tort (including negligence), contract, or otherwise,
    +      unless required by applicable law (such as deliberate and grossly
    +      negligent acts) or agreed to in writing, shall any Contributor be
    +      liable to You for damages, including any direct, indirect, special,
    +      incidental, or consequential damages of any character arising as a
    +      result of this License or out of the use or inability to use the
    +      Work (including but not limited to damages for loss of goodwill,
    +      work stoppage, computer failure or malfunction, or any and all
    +      other commercial damages or losses), even if such Contributor
    +      has been advised of the possibility of such damages.
    +
    +   9. Accepting Warranty or Additional Liability. While redistributing
    +      the Work or Derivative Works thereof, You may choose to offer,
    +      and charge a fee for, acceptance of support, warranty, indemnity,
    +      or other liability obligations and/or rights consistent with this
    +      License. However, in accepting such obligations, You may act only
    +      on Your own behalf and on Your sole responsibility, not on behalf
    +      of any other Contributor, and only if You agree to indemnify,
    +      defend, and hold each Contributor harmless for any liability
    +      incurred by, or claims asserted against, such Contributor by reason
    +      of your accepting any such warranty or additional liability.
    +
    +   END OF TERMS AND CONDITIONS
    +
    +   Copyright 2019 Yoshua Wuyts
    +
    +   Licensed under the Apache License, Version 2.0 (the "License");
    +   you may not use this file except in compliance with the License.
    +   You may obtain a copy of the License at
    +
    +       http://www.apache.org/licenses/LICENSE-2.0
    +
    +   Unless required by applicable law or agreed to in writing, software
    +   distributed under the License is distributed on an "AS IS" BASIS,
    +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +   See the License for the specific language governing permissions and
    +   limitations under the License.
     
  • @@ -8424,13 +8622,26 @@

    Used by:

  • arbitrary
  • arc-swap
  • async-channel
  • +
  • async-channel
  • async-compression
  • +
  • async-executor
  • +
  • async-global-executor
  • +
  • async-io
  • +
  • async-io
  • +
  • async-lock
  • +
  • async-lock
  • +
  • async-process
  • +
  • async-signal
  • +
  • async-std
  • +
  • async-task
  • +
  • atomic-waker
  • autocfg
  • backtrace
  • base64
  • base64
  • bitflags
  • bitflags
  • +
  • blocking
  • bstr
  • bumpalo
  • bytes-utils
  • @@ -8453,6 +8664,9 @@

    Used by:

  • envmnt
  • equivalent
  • event-listener
  • +
  • event-listener
  • +
  • event-listener
  • +
  • event-listener-strategy
  • fastrand
  • fastrand
  • filetime
  • @@ -8463,6 +8677,7 @@

    Used by:

  • fraction
  • fsio
  • futures-lite
  • +
  • futures-lite
  • gimli
  • git2
  • group
  • @@ -8481,10 +8696,12 @@

    Used by:

  • indexmap
  • indexmap
  • inventory
  • +
  • io-lifetimes
  • ipconfig
  • itertools
  • itertools
  • itertools
  • +
  • itertools
  • jobserver
  • js-sys
  • lazy_static
  • @@ -8494,6 +8711,7 @@

    Used by:

  • libz-ng-sys
  • libz-sys
  • linux-raw-sys
  • +
  • linux-raw-sys
  • lock_api
  • log
  • maplit
  • @@ -8526,8 +8744,10 @@

    Used by:

  • pest_generator
  • pest_meta
  • petgraph
  • +
  • piper
  • pkg-config
  • platforms
  • +
  • polling
  • proc-macro2
  • prost
  • prost
  • @@ -8549,6 +8769,7 @@

    Used by:

  • rustc_version
  • rustc_version
  • rustix
  • +
  • rustix
  • rustls
  • rustls-native-certs
  • rustls-pemfile
  • @@ -8565,6 +8786,7 @@

    Used by:

  • similar
  • smallvec
  • socket2
  • +
  • socket2
  • stable_deref_trait
  • syn
  • syn
  • @@ -8588,6 +8810,7 @@

    Used by:

  • unicode-xid
  • url
  • uuid
  • +
  • value-bag
  • version_check
  • waker-fn
  • wasi
  • @@ -11092,6 +11315,7 @@

    Used by:

                                  Apache License
    @@ -11744,6 +11968,7 @@ 

    Used by:

    Apache License 2.0

    Used by:

      +
    • apollo-compiler
    • apollo-encoder
    • apollo-parser
    • apollo-smith
    • @@ -12397,12 +12622,12 @@

      Used by:

      Apache License 2.0

      Used by:

        -
      • apollo-compiler
      • curve25519-dalek-derive
      • deadpool-runtime
      • deno-proc-macro-rules
      • deno-proc-macro-rules-macros
      • dunce
      • +
      • gloo-timers
      • graphql-introspection-query
      • graphql_client
      • graphql_client_codegen
      • @@ -13039,6 +13264,7 @@

        BSD 3-Clause "New" or "Revised" Licens

        Used by:

        Copyright (c) <year> <owner>. 
         
        @@ -13583,7 +13809,6 @@ 

        ISC License

        Used by:

           Copyright 2015-2016 Brian Smith.
         
        @@ -13604,7 +13829,6 @@ 

        ISC License

        Used by:

        /* Copyright (c) 2015, Google Inc.
          *
        @@ -13710,6 +13934,7 @@ 

        ISC License

        Used by:

        ISC License:
        @@ -14029,7 +14254,6 @@ 

        MIT License

        Used by:

        Copyright (c) 2015-2016 the fiat-crypto authors (see
         https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
        @@ -15444,6 +15668,7 @@ 

        Used by:

      • jsonschema
      • lazy-regex-proc_macros
      • number_prefix
      • +
      • ring
      • serde_v8
      • v8
      • valuable
      • @@ -17122,7 +17347,6 @@

        OpenSSL License

        Used by:

        /* ====================================================================
          * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
        @@ -17177,6 +17401,62 @@ 

        Used by:

        * Hudson (tjh@cryptsoft.com). * */
        + +
      • +

        OpenSSL License

        +

        Used by:

        + +
        OpenSSL License
        +
        +Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved.
        +
        +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
        +
        +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
        +
        +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
        +
        +3. All advertising materials mentioning features or use of this software must display the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
        +
        +4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact openssl-core@openssl.org.
        +
        +5. Products derived from this software may not be called "OpenSSL" nor may "OpenSSL" appear in their names without prior written permission of the OpenSSL Project.
        +
        +6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/)"
        +
        +THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        +
        +This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com).
        +
        +
        +Original SSLeay License
        +
        +Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
        +
        +This package is an SSL implementation written by Eric Young (eay@cryptsoft.com). The implementation was written so as to conform with Netscapes SSL.
        +
        +This library is free for commercial and non-commercial use as long as the following conditions are aheared to. The following conditions apply to all code found in this distribution, be it the RC4, RSA, lhash, DES, etc., code; not just the SSL code. The SSL documentation included with this distribution is covered by the same copyright terms except that the holder is Tim Hudson (tjh@cryptsoft.com).
        +
        +Copyright remains Eric Young's, and as such any Copyright notices in the code are not to be removed. If this package is used in a product, Eric Young should be given attribution as the author of the parts of the library used. This can be in the form of a textual message at program startup or in documentation (online or textual) provided with the package.
        +
        +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
        +
        +1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer.
        +
        +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
        +
        +3. All advertising materials mentioning features or use of this software must display the following acknowledgement:
        +"This product includes cryptographic software written by Eric Young (eay@cryptsoft.com)"
        +The word 'cryptographic' can be left out if the rouines from the library being used are not cryptographic related :-).
        +
        +4. If you include any Windows specific code (or a derivative thereof) from the apps directory (application code) you must include an acknowledgement: "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
        +
        +THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        +
        +The licence and distribution terms for any publically available version or derivative of this code cannot be changed. i.e. this code cannot simply be copied and put under another distribution licence [including the GNU Public Licence.]
        +
      • Unicode License Agreement - Data Files and Software (2016)

        diff --git a/scripts/install.sh b/scripts/install.sh index 0a905d7fb7..9927578a75 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -11,7 +11,7 @@ BINARY_DOWNLOAD_PREFIX="https://github.com/apollographql/router/releases/downloa # Router version defined in apollo-router's Cargo.toml # Note: Change this line manually during the release steps. -PACKAGE_VERSION="v1.48.1" +PACKAGE_VERSION="v1.49.0-rc.1" download_binary() { downloader --check