Skip to content

Commit 9743b81

Browse files
committed
Change UsageReporting to enum
1 parent 097c583 commit 9743b81

File tree

6 files changed

+176
-135
lines changed

6 files changed

+176
-135
lines changed

apollo-router/src/apollo_studio_interop/mod.rs

+99-47
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use sha2::Digest;
3232

3333
use crate::json_ext::Object;
3434
use crate::json_ext::Value as JsonValue;
35+
use crate::plugins::telemetry::apollo_exporter::proto::reports::QueryMetadata;
3536
use crate::plugins::telemetry::config::ApolloSignatureNormalizationAlgorithm;
3637
use crate::spec::Fragments;
3738
use crate::spec::Query;
@@ -162,35 +163,50 @@ impl AddAssign<ReferencedEnums> for AggregatedExtendedReferenceStats {
162163
}
163164
}
164165

165-
/// UsageReporting fields, that will be used to send stats to uplink/studio
166166
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, Default)]
167167
#[serde(rename_all = "camelCase")]
168-
pub(crate) struct UsageReporting {
168+
pub(crate) struct UsageReportingOperationDetails {
169169
/// The operation name, or None if there is no operation name
170170
operation_name: Option<String>,
171171
/// The normalized operation signature, or None if there is no valid signature
172172
operation_signature: Option<String>,
173-
/// The error key to use for the stats report, or None if there is no error
174-
error_key: Option<String>,
175-
/// The persisted query ID used to request this operation, or None if the query was not requested via PQ ID
176-
pq_id: Option<String>,
177173
/// a list of all types and fields referenced in the query
178174
#[serde(default)]
179-
pub(crate) referenced_fields_by_type: HashMap<String, ReferencedFieldsForType>,
175+
referenced_fields_by_type: HashMap<String, ReferencedFieldsForType>,
176+
}
177+
178+
/// UsageReporting fields, that will be used to send stats to uplink/studio
179+
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
180+
#[serde(rename_all = "camelCase")]
181+
pub(crate) enum UsageReporting {
182+
Operation(UsageReportingOperationDetails),
183+
PersistedQuery {
184+
operation_details: UsageReportingOperationDetails,
185+
persisted_query_id: String,
186+
},
187+
Error(String),
180188
}
181189

182190
impl UsageReporting {
183191
pub(crate) fn for_error(error_key: String) -> UsageReporting {
184-
UsageReporting {
185-
error_key: Some(error_key),
186-
..Default::default()
187-
}
192+
UsageReporting::Error(error_key)
188193
}
189194

190-
pub(crate) fn with_pq_id(&self, pq_id: Option<String>) -> UsageReporting {
191-
UsageReporting {
192-
pq_id,
193-
..self.clone()
195+
pub(crate) fn with_pq_id(&self, maybe_pq_id: Option<String>) -> UsageReporting {
196+
match self {
197+
UsageReporting::Operation(op_details)
198+
| UsageReporting::PersistedQuery {
199+
operation_details: op_details,
200+
..
201+
} => match maybe_pq_id {
202+
Some(pq_id) => UsageReporting::PersistedQuery {
203+
operation_details: op_details.clone(),
204+
persisted_query_id: pq_id,
205+
},
206+
None => UsageReporting::Operation(op_details.clone()),
207+
},
208+
// PQ ID has no effect on errors
209+
UsageReporting::Error { .. } => self.clone(),
194210
}
195211
}
196212

@@ -203,52 +219,90 @@ impl UsageReporting {
203219
/// Note that this combination of operation name and signature is sometimes referred to in code as
204220
/// "operation signature" even though it also contains the operation name as the first line.
205221
pub(crate) fn get_stats_report_key(&self) -> String {
206-
if let Some(error_key) = &self.error_key {
207-
format!("## {}\n", error_key)
208-
} else if let Some(persisted_query_id) = &self.pq_id {
209-
format!("pq# {}", persisted_query_id)
210-
} else {
211-
let stats_report_key_op_name =
212-
self.operation_name.as_deref().unwrap_or("-").to_string();
213-
format!(
214-
"# {}\n{}",
215-
stats_report_key_op_name,
216-
self.get_operation_signature()
217-
)
222+
match self {
223+
UsageReporting::Operation(operation_details) => {
224+
let stats_report_key_op_name = operation_details
225+
.operation_name
226+
.as_deref()
227+
.unwrap_or("-")
228+
.to_string();
229+
format!(
230+
"# {}\n{}",
231+
stats_report_key_op_name,
232+
self.get_operation_signature(),
233+
)
234+
}
235+
UsageReporting::PersistedQuery {
236+
persisted_query_id, ..
237+
} => {
238+
format!("pq# {}", persisted_query_id)
239+
}
240+
UsageReporting::Error(error_key) => format!("## {}\n", error_key),
218241
}
219242
}
220243

221244
pub(crate) fn get_operation_signature(&self) -> String {
222-
self.operation_signature
223-
.as_deref()
224-
.unwrap_or("")
225-
.to_string()
245+
match self {
246+
UsageReporting::Operation(operation_details)
247+
| UsageReporting::PersistedQuery {
248+
operation_details, ..
249+
} => operation_details
250+
.operation_signature
251+
.clone()
252+
.unwrap_or("".to_string()),
253+
UsageReporting::Error { .. } => "".to_string(),
254+
}
226255
}
227256

228257
pub(crate) fn get_operation_id(&self) -> String {
229-
let sig_to_hash = match &self.error_key {
230-
Some(err_key) => format!("# # {}\n", err_key),
231-
None => self.get_stats_report_key(),
258+
let string_to_hash = match self {
259+
UsageReporting::Operation { .. } | UsageReporting::PersistedQuery { .. } => {
260+
self.get_stats_report_key()
261+
}
262+
UsageReporting::Error(error_key) => format!("# # {}\n", error_key),
232263
};
233264

234265
let mut hasher = sha1::Sha1::new();
235-
hasher.update(sig_to_hash.as_bytes());
266+
hasher.update(string_to_hash.as_bytes());
236267
let result = hasher.finalize();
237268
hex::encode(result)
238269
}
239270

240271
pub(crate) fn get_operation_name(&self) -> String {
241-
if let Some(op_name) = &self.operation_name {
242-
op_name.clone()
243-
} else if let Some(err_key) = &self.error_key {
244-
format!("# {}", err_key)
245-
} else {
246-
"".to_string()
272+
match self {
273+
UsageReporting::Operation(operation_details)
274+
| UsageReporting::PersistedQuery {
275+
operation_details, ..
276+
} => operation_details
277+
.operation_name
278+
.clone()
279+
.unwrap_or("".to_string()),
280+
UsageReporting::Error(error_key) => format!("# {}", error_key),
247281
}
248282
}
249283

250-
pub(crate) fn is_error(&self) -> bool {
251-
self.error_key.is_some()
284+
pub(crate) fn get_referenced_fields(&self) -> HashMap<String, ReferencedFieldsForType> {
285+
match self {
286+
UsageReporting::Operation(operation_details)
287+
| UsageReporting::PersistedQuery {
288+
operation_details, ..
289+
} => operation_details.referenced_fields_by_type.clone(),
290+
UsageReporting::Error { .. } => HashMap::default(),
291+
}
292+
}
293+
294+
pub(crate) fn get_query_metadata(&self) -> Option<QueryMetadata> {
295+
match self {
296+
UsageReporting::PersistedQuery {
297+
persisted_query_id, ..
298+
} => Some(QueryMetadata {
299+
name: self.get_operation_name(),
300+
signature: self.get_operation_signature(),
301+
pq_id: persisted_query_id.clone(),
302+
}),
303+
// For now we only want to populate query metadata for PQ operations
304+
_ => None,
305+
}
252306
}
253307
}
254308

@@ -440,13 +494,11 @@ struct UsageGenerator<'a> {
440494

441495
impl UsageGenerator<'_> {
442496
fn generate_usage_reporting(&mut self) -> UsageReporting {
443-
UsageReporting {
497+
UsageReporting::Operation(UsageReportingOperationDetails {
444498
operation_name: self.get_operation_name(),
445499
operation_signature: self.generate_normalized_signature(),
446-
error_key: None,
447-
pq_id: None,
448500
referenced_fields_by_type: self.generate_apollo_reporting_refs(),
449-
}
501+
})
450502
}
451503

452504
fn get_operation_name(&self) -> Option<String> {

apollo-router/src/apollo_studio_interop/tests.rs

+37-42
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,11 @@ async fn test_enums_from_response_fragments() {
303303

304304
#[test]
305305
fn apollo_operation_id_hash() {
306-
let usage_reporting = UsageReporting {
306+
let usage_reporting = UsageReporting::Operation(UsageReportingOperationDetails {
307307
operation_name: Some("IgnitionMeQuery".to_string()),
308308
operation_signature: Some("query IgnitionMeQuery{me{id}}".to_string()),
309-
error_key: None,
310-
pq_id: None,
311309
referenced_fields_by_type: HashMap::new(),
312-
};
310+
});
313311

314312
assert_eq!(
315313
"d1554552698157b05c2a462827fb4367a4548ee5",
@@ -323,57 +321,56 @@ fn apollo_operation_id_hash() {
323321
fn apollo_error_operation_id_hash() {
324322
assert_eq!(
325323
"ea4f152696abedca148b016d72df48842b713697",
326-
UsageReporting::for_error("GraphQLValidationFailure".into()).get_operation_id()
324+
UsageReporting::Error("GraphQLValidationFailure".into()).get_operation_id()
327325
);
328326
assert_eq!(
329327
"3f410834f13153f401ffe73f7e454aa500d10bf7",
330-
UsageReporting::for_error("GraphQLParseFailure".into()).get_operation_id()
328+
UsageReporting::Error("GraphQLParseFailure".into()).get_operation_id()
331329
);
332330
assert_eq!(
333331
"7486043da2085fed407d942508a572ef88dc8120",
334-
UsageReporting::for_error("GraphQLUnknownOperationName".into()).get_operation_id()
332+
UsageReporting::Error("GraphQLUnknownOperationName".into()).get_operation_id()
335333
);
336334
}
337335

338336
#[test]
339337
fn test_get_stats_report_key() {
340-
let usage_reporting_for_errors = UsageReporting::for_error("GraphQLParseFailure".into());
338+
let usage_reporting_for_errors = UsageReporting::Error("GraphQLParseFailure".into());
341339
assert_eq!(
342340
"## GraphQLParseFailure\n",
343341
usage_reporting_for_errors.get_stats_report_key()
344342
);
345343

346-
let usage_reporting_for_pq = UsageReporting {
347-
operation_name: Some("SomeQuery".into()),
348-
operation_signature: Some("query SomeQuery{thing{id}}".into()),
349-
error_key: None,
350-
pq_id: Some("SomePqId".into()),
351-
referenced_fields_by_type: HashMap::new(),
344+
let usage_reporting_for_pq = UsageReporting::PersistedQuery {
345+
operation_details: UsageReportingOperationDetails {
346+
operation_name: Some("SomeQuery".into()),
347+
operation_signature: Some("query SomeQuery{thing{id}}".into()),
348+
referenced_fields_by_type: HashMap::new(),
349+
},
350+
persisted_query_id: "SomePqId".into(),
352351
};
353352
assert_eq!(
354353
"pq# SomePqId",
355354
usage_reporting_for_pq.get_stats_report_key()
356355
);
357356

358-
let usage_reporting_for_named_operation = UsageReporting {
359-
operation_name: Some("SomeQuery".into()),
360-
operation_signature: Some("query SomeQuery{thing{id}}".into()),
361-
error_key: None,
362-
pq_id: None,
363-
referenced_fields_by_type: HashMap::new(),
364-
};
357+
let usage_reporting_for_named_operation =
358+
UsageReporting::Operation(UsageReportingOperationDetails {
359+
operation_name: Some("SomeQuery".into()),
360+
operation_signature: Some("query SomeQuery{thing{id}}".into()),
361+
referenced_fields_by_type: HashMap::new(),
362+
});
365363
assert_eq!(
366364
"# SomeQuery\nquery SomeQuery{thing{id}}",
367365
usage_reporting_for_named_operation.get_stats_report_key()
368366
);
369367

370-
let usage_reporting_for_unnamed_operation = UsageReporting {
371-
operation_name: None,
372-
operation_signature: Some("query{thing{id}}".into()),
373-
error_key: None,
374-
pq_id: None,
375-
referenced_fields_by_type: HashMap::new(),
376-
};
368+
let usage_reporting_for_unnamed_operation =
369+
UsageReporting::Operation(UsageReportingOperationDetails {
370+
operation_name: None,
371+
operation_signature: Some("query{thing{id}}".into()),
372+
referenced_fields_by_type: HashMap::new(),
373+
});
377374
assert_eq!(
378375
"# -\nquery{thing{id}}",
379376
usage_reporting_for_unnamed_operation.get_stats_report_key()
@@ -388,25 +385,23 @@ fn test_get_operation_name() {
388385
usage_reporting_for_errors.get_operation_name()
389386
);
390387

391-
let usage_reporting_for_named_operation = UsageReporting {
392-
operation_name: Some("SomeQuery".into()),
393-
operation_signature: Some("query SomeQuery{thing{id}}".into()),
394-
error_key: None,
395-
pq_id: None,
396-
referenced_fields_by_type: HashMap::new(),
397-
};
388+
let usage_reporting_for_named_operation =
389+
UsageReporting::Operation(UsageReportingOperationDetails {
390+
operation_name: Some("SomeQuery".into()),
391+
operation_signature: Some("query SomeQuery{thing{id}}".into()),
392+
referenced_fields_by_type: HashMap::new(),
393+
});
398394
assert_eq!(
399395
"SomeQuery",
400396
usage_reporting_for_named_operation.get_operation_name()
401397
);
402398

403-
let usage_reporting_for_unnamed_operation = UsageReporting {
404-
operation_name: None,
405-
operation_signature: Some("query{thing{id}}".into()),
406-
error_key: None,
407-
pq_id: None,
408-
referenced_fields_by_type: HashMap::new(),
409-
};
399+
let usage_reporting_for_unnamed_operation =
400+
UsageReporting::Operation(UsageReportingOperationDetails {
401+
operation_name: None,
402+
operation_signature: Some("query{thing{id}}".into()),
403+
referenced_fields_by_type: HashMap::new(),
404+
});
410405
assert_eq!(
411406
"",
412407
usage_reporting_for_unnamed_operation.get_operation_name()

apollo-router/src/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ impl QueryPlannerError {
434434
pub(crate) fn usage_reporting(&self) -> Option<UsageReporting> {
435435
match self {
436436
QueryPlannerError::SpecError(e) => {
437-
Some(UsageReporting::for_error(e.get_error_key().to_string()))
437+
Some(UsageReporting::Error(e.get_error_key().to_string()))
438438
}
439439
_ => None,
440440
}

0 commit comments

Comments
 (0)