Skip to content

Commit 6cc999b

Browse files
authored
feat: add support of operationCountByType for apollo studio (#2979)
add support of operationCountByType for apollo studio --------- Signed-off-by: Benjamin Coenen <[email protected]>
1 parent de4b1f2 commit 6cc999b

27 files changed

+241
-42
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Add support of operationCountByType for apollo studio ([PR #2979](https://github.com/apollographql/router/pull/2979))
2+
3+
Add more details about the operation type for apollo studio usage reporting.
4+
5+
By [@bnjjj](https://github.com/bnjjj) in https://github.com/apollographql/router/pull/2979

apollo-router/src/plugins/telemetry/apollo.rs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Configuration for apollo telemetry.
22
// This entire file is license key functionality
33
use std::collections::HashMap;
4+
use std::fmt::Display;
45
use std::num::NonZeroUsize;
56
use std::ops::AddAssign;
67
use std::time::SystemTime;
@@ -9,6 +10,7 @@ use derivative::Derivative;
910
use http::header::HeaderName;
1011
use itertools::Itertools;
1112
use schemars::JsonSchema;
13+
use serde::ser::SerializeMap;
1214
use serde::Deserialize;
1315
use serde::Serialize;
1416
use url::Url;
@@ -25,6 +27,7 @@ use crate::plugins::telemetry::apollo_exporter::proto::reports::StatsContext;
2527
use crate::plugins::telemetry::apollo_exporter::proto::reports::Trace;
2628
use crate::plugins::telemetry::config::SamplerOption;
2729
use crate::plugins::telemetry::tracing::BatchProcessorConfig;
30+
use crate::query_planner::OperationKind;
2831
use crate::services::apollo_graph_reference;
2932
use crate::services::apollo_key;
3033

@@ -209,9 +212,71 @@ pub(crate) enum SingleReport {
209212
#[derive(Default, Debug, Serialize)]
210213
pub(crate) struct Report {
211214
pub(crate) traces_per_query: HashMap<String, TracesAndStats>,
215+
#[serde(serialize_with = "serialize_operation_count_by_type")]
216+
pub(crate) operation_count_by_type:
217+
HashMap<(OperationKind, Option<OperationSubType>), OperationCountByType>,
218+
}
219+
220+
#[derive(Default, Debug, Serialize, PartialEq, Eq, Hash)]
221+
pub(crate) struct OperationCountByType {
222+
pub(crate) r#type: OperationKind,
223+
pub(crate) subtype: Option<OperationSubType>,
212224
pub(crate) operation_count: u64,
213225
}
214226

227+
#[derive(Debug, Serialize, PartialEq, Eq, Hash, Clone, Copy)]
228+
#[serde(rename_all = "kebab-case")]
229+
pub(crate) enum OperationSubType {
230+
// TODO
231+
}
232+
233+
impl OperationSubType {
234+
pub(crate) const fn as_str(&self) -> &'static str {
235+
""
236+
}
237+
}
238+
239+
impl Display for OperationSubType {
240+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241+
write!(f, "")
242+
}
243+
}
244+
245+
impl From<OperationCountByType>
246+
for crate::plugins::telemetry::apollo_exporter::proto::reports::report::OperationCountByType
247+
{
248+
fn from(value: OperationCountByType) -> Self {
249+
Self {
250+
r#type: value.r#type.as_apollo_operation_type().to_string(),
251+
subtype: value.subtype.map(|s| s.to_string()).unwrap_or_default(),
252+
operation_count: value.operation_count,
253+
}
254+
}
255+
}
256+
257+
fn serialize_operation_count_by_type<S>(
258+
elt: &HashMap<(OperationKind, Option<OperationSubType>), OperationCountByType>,
259+
serializer: S,
260+
) -> Result<S::Ok, S::Error>
261+
where
262+
S: serde::Serializer,
263+
{
264+
let mut map_ser = serializer.serialize_map(Some(elt.len()))?;
265+
for ((op_type, op_subtype), v) in elt {
266+
map_ser.serialize_entry(
267+
&format!(
268+
"{}{}",
269+
op_type.as_apollo_operation_type(),
270+
op_subtype
271+
.map(|o| "/".to_owned() + o.as_str())
272+
.unwrap_or_default()
273+
),
274+
v,
275+
)?;
276+
}
277+
map_ser.end()
278+
}
279+
215280
impl Report {
216281
#[cfg(test)]
217282
pub(crate) fn new(reports: Vec<SingleStatsReport>) -> Report {
@@ -229,7 +294,11 @@ impl Report {
229294
let mut report = crate::plugins::telemetry::apollo_exporter::proto::reports::Report {
230295
header: Some(header),
231296
end_time: Some(SystemTime::now().into()),
232-
operation_count: self.operation_count,
297+
operation_count_by_type: self
298+
.operation_count_by_type
299+
.into_values()
300+
.map(|op| op.into())
301+
.collect(),
233302
traces_pre_aggregated: true,
234303
..Default::default()
235304
};
@@ -269,7 +338,18 @@ impl AddAssign<SingleStatsReport> for Report {
269338
*self.traces_per_query.entry(k).or_default() += v;
270339
}
271340

272-
self.operation_count += report.operation_count;
341+
if let Some(operation_count_by_type) = report.operation_count_by_type {
342+
let key = (
343+
operation_count_by_type.r#type,
344+
operation_count_by_type.subtype,
345+
);
346+
self.operation_count_by_type
347+
.entry(key)
348+
.and_modify(|e| {
349+
e.operation_count += 1;
350+
})
351+
.or_insert(operation_count_by_type);
352+
}
273353
}
274354
}
275355

apollo-router/src/plugins/telemetry/apollo_exporter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl ApolloExporter {
164164

165165
pub(crate) async fn submit_report(&self, report: Report) -> Result<(), ApolloExportError> {
166166
// We may be sending traces but with no operation count
167-
if report.operation_count == 0 && report.traces_per_query.is_empty() {
167+
if report.operation_count_by_type.is_empty() && report.traces_per_query.is_empty() {
168168
return Ok(());
169169
}
170170
tracing::debug!("submitting report: {:?}", report);

apollo-router/src/plugins/telemetry/metrics/apollo/snapshots/apollo_router__plugins__telemetry__metrics__apollo__studio__test__aggregation.snap

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,5 +1302,11 @@ expression: aggregated_metrics
13021302
}
13031303
}
13041304
},
1305-
"operation_count": 2
1305+
"operation_count_by_type": {
1306+
"query": {
1307+
"type": "query",
1308+
"subtype": null,
1309+
"operation_count": 2
1310+
}
1311+
}
13061312
}

apollo-router/src/plugins/telemetry/metrics/apollo/studio.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ use serde::Serialize;
66
use uuid::Uuid;
77

88
use super::duration_histogram::DurationHistogram;
9+
use crate::plugins::telemetry::apollo::OperationCountByType;
910
use crate::plugins::telemetry::apollo_exporter::proto::reports::ReferencedFieldsForType;
1011
use crate::plugins::telemetry::apollo_exporter::proto::reports::StatsContext;
1112

1213
#[derive(Default, Debug, Serialize)]
1314
pub(crate) struct SingleStatsReport {
1415
pub(crate) request_id: Uuid,
1516
pub(crate) stats: HashMap<String, SingleStats>,
16-
pub(crate) operation_count: u64,
17+
pub(crate) operation_count_by_type: Option<OperationCountByType>,
1718
}
1819

1920
#[derive(Default, Debug, Serialize)]
@@ -269,6 +270,7 @@ mod test {
269270

270271
use super::*;
271272
use crate::plugins::telemetry::apollo::Report;
273+
use crate::query_planner::OperationKind;
272274

273275
#[test]
274276
fn test_aggregation() {
@@ -317,7 +319,12 @@ mod test {
317319

318320
SingleStatsReport {
319321
request_id: Uuid::default(),
320-
operation_count: count.inc_u64(),
322+
operation_count_by_type: OperationCountByType {
323+
r#type: OperationKind::Query,
324+
subtype: None,
325+
operation_count: count.inc_u64(),
326+
}
327+
.into(),
321328
stats: HashMap::from([(
322329
stats_report_key.to_string(),
323330
SingleStats {

apollo-router/src/plugins/telemetry/metrics/snapshots/apollo_router__plugins__telemetry__metrics__apollo__test__apollo_metrics_exclude.snap

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ expression: results
66
{
77
"request_id": "[REDACTED]",
88
"stats": {},
9-
"operation_count": 1
9+
"operation_count_by_type": {
10+
"type": "query",
11+
"subtype": null,
12+
"operation_count": 1
13+
}
1014
}
1115
]

apollo-router/src/plugins/telemetry/metrics/snapshots/apollo_router__plugins__telemetry__metrics__apollo__test__apollo_metrics_multiple_operations.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ expression: results
1111
"context": {
1212
"client_name": "test_client",
1313
"client_version": "1.0-test",
14-
"operation_type": "",
14+
"operation_type": "query",
1515
"operation_subtype": ""
1616
},
1717
"query_latency_stats": {
@@ -39,6 +39,6 @@ expression: results
3939
"referenced_fields_by_type": {}
4040
}
4141
},
42-
"operation_count": 0
42+
"operation_count_by_type": null
4343
}
4444
]

apollo-router/src/plugins/telemetry/metrics/snapshots/apollo_router__plugins__telemetry__metrics__apollo__test__apollo_metrics_parse_failure.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ expression: results
1111
"context": {
1212
"client_name": "test_client",
1313
"client_version": "1.0-test",
14-
"operation_type": "",
14+
"operation_type": "query",
1515
"operation_subtype": ""
1616
},
1717
"query_latency_stats": {
@@ -39,6 +39,6 @@ expression: results
3939
"referenced_fields_by_type": {}
4040
}
4141
},
42-
"operation_count": 0
42+
"operation_count_by_type": null
4343
}
4444
]

apollo-router/src/plugins/telemetry/metrics/snapshots/apollo_router__plugins__telemetry__metrics__apollo__test__apollo_metrics_single_operation.snap

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ expression: results
1111
"context": {
1212
"client_name": "test_client",
1313
"client_version": "1.0-test",
14-
"operation_type": "",
14+
"operation_type": "query",
1515
"operation_subtype": ""
1616
},
1717
"query_latency_stats": {
@@ -52,6 +52,10 @@ expression: results
5252
}
5353
}
5454
},
55-
"operation_count": 1
55+
"operation_count_by_type": {
56+
"type": "query",
57+
"subtype": null,
58+
"operation_count": 1
59+
}
5660
}
5761
]

apollo-router/src/plugins/telemetry/metrics/snapshots/apollo_router__plugins__telemetry__metrics__apollo__test__apollo_metrics_unknown_operation.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ expression: results
1111
"context": {
1212
"client_name": "test_client",
1313
"client_version": "1.0-test",
14-
"operation_type": "",
14+
"operation_type": "query",
1515
"operation_subtype": ""
1616
},
1717
"query_latency_stats": {
@@ -39,6 +39,6 @@ expression: results
3939
"referenced_fields_by_type": {}
4040
}
4141
},
42-
"operation_count": 0
42+
"operation_count_by_type": null
4343
}
4444
]

0 commit comments

Comments
 (0)