Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add selector for router service in custom telemetry #5392

Merged
merged 4 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -141,6 +141,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 @@ -618,6 +629,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 @@ -658,6 +686,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 @@ -2050,6 +2095,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 |
bnjjj marked this conversation as resolved.
Show resolved Hide resolved
| `request_header` | Yes | | The name of the request header |
| `response_header` | Yes | | The name of a response header |
Expand Down
Loading