Skip to content

Commit

Permalink
add selector for router service in custom telemetry (#5392)
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
  • Loading branch information
bnjjj authored Jun 14, 2024
1 parent 5de98ef commit e15d0d9
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 2 deletions.
18 changes: 18 additions & 0 deletions .changesets/feat_bnjjj_add_operation_name_router_selector.md
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ telemetry:
http.server.request.duration:
attributes:
my_attribute:
request_method: true
request_method: true
graphql.operation.name:
operation_name: string
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ events:
method: GET
body: |
hello
- context:
map:
operation_name: TestQuery
- router_response:
body: |
hello
Expand Down
78 changes: 78 additions & 0 deletions apollo-router/src/plugins/telemetry/config_new/selectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ pub(crate) enum RouterSelector {
/// Optional default value.
default: Option<AttributeValue>,
},
/// 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<String>,
/// Optional default value.
default: Option<String>,
},
/// A value from baggage.
Baggage {
/// The name of the baggage item.
Expand Down Expand Up @@ -617,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()),
Expand Down Expand Up @@ -657,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,
}
}
Expand Down Expand Up @@ -2013,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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down

0 comments on commit e15d0d9

Please sign in to comment.