-
Notifications
You must be signed in to change notification settings - Fork 46
Telemetry: Trace operations and auth #375
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
Changes from 7 commits
5fda361
fd25362
f98215c
df98289
212f244
db4bbe6
5a845cd
7a14f9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ### Telemetry: Trace operations and auth - @swcollard PR #375 | ||
|
|
||
| * Adds traces for the MCP server generating Tools from Operations and performing authorization | ||
| * Includes the HTTP status code to the top level HTTP trace |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,7 @@ use super::RawOperation; | |
| const OPERATION_DOCUMENT_EXTENSION: &str = "graphql"; | ||
|
|
||
| /// The source of the operations exposed as MCP tools | ||
| #[derive(Clone)] | ||
| #[derive(Clone, Debug)] | ||
| pub enum OperationSource { | ||
| /// GraphQL document files | ||
| Files(Vec<PathBuf>), | ||
|
|
@@ -38,6 +38,7 @@ pub enum OperationSource { | |
| } | ||
|
|
||
| impl OperationSource { | ||
| #[tracing::instrument] | ||
|
||
| pub async fn into_stream(self) -> impl Stream<Item = Event> { | ||
| match self { | ||
| OperationSource::Files(paths) => Self::stream_file_changes(paths).boxed(), | ||
|
|
@@ -73,6 +74,7 @@ impl OperationSource { | |
| } | ||
| } | ||
|
|
||
| #[tracing::instrument] | ||
| fn stream_file_changes(paths: Vec<PathBuf>) -> impl Stream<Item = Event> { | ||
| let path_count = paths.len(); | ||
| let state = Arc::new(Mutex::new(HashMap::<PathBuf, Vec<RawOperation>>::new())); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -193,15 +193,27 @@ impl Starting { | |
| //start OpenTelemetry trace on incoming request | ||
| .layer(OtelAxumLayer::default()) | ||
| // Add tower-http tracing layer for additional HTTP-level tracing | ||
| .layer(TraceLayer::new_for_http().make_span_with( | ||
| |request: &axum::http::Request<_>| { | ||
| tracing::info_span!( | ||
| "mcp_server", | ||
| method = %request.method(), | ||
| uri = %request.uri(), | ||
| ) | ||
| }, | ||
| )); | ||
| .layer( | ||
| TraceLayer::new_for_http() | ||
| .make_span_with(|request: &axum::http::Request<_>| { | ||
| tracing::info_span!( | ||
| "mcp_server", | ||
| method = %request.method(), | ||
| uri = %request.uri(), | ||
| status = tracing::field::Empty, | ||
DaleSeo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
| }) | ||
| .on_response( | ||
| |response: &axum::http::Response<_>, | ||
| _latency: std::time::Duration, | ||
| span: &tracing::Span| { | ||
| span.record( | ||
| "status", | ||
| tracing::field::display(response.status()), | ||
| ); | ||
| }, | ||
| ), | ||
| ); | ||
|
|
||
| // Add health check endpoint if configured | ||
| if let Some(health_check) = health_check.filter(|h| h.config().enabled) { | ||
|
|
@@ -297,3 +309,49 @@ async fn health_endpoint( | |
|
|
||
| Ok((status_code, Json(json!(health)))) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use http::HeaderMap; | ||
| use url::Url; | ||
|
|
||
| use crate::health::HealthCheckConfig; | ||
|
|
||
| use super::*; | ||
|
|
||
| #[tokio::test] | ||
| async fn start_basic_server() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| let starting = Starting { | ||
| config: Config { | ||
| transport: Transport::StreamableHttp { | ||
| auth: None, | ||
| address: "127.0.0.1".parse().unwrap(), | ||
| port: 7799, | ||
| stateful_mode: false, | ||
| }, | ||
| endpoint: Url::parse("http://localhost:4000").expect("valid url"), | ||
| mutation_mode: MutationMode::All, | ||
| execute_introspection: true, | ||
| headers: HeaderMap::new(), | ||
| validate_introspection: true, | ||
| introspect_introspection: true, | ||
| search_introspection: true, | ||
| introspect_minify: false, | ||
| search_minify: false, | ||
| explorer_graph_ref: None, | ||
| custom_scalar_map: None, | ||
| disable_type_description: false, | ||
| disable_schema_description: false, | ||
| disable_auth_token_passthrough: false, | ||
| search_leaf_depth: 5, | ||
| index_memory_bytes: 1024 * 1024 * 1024, | ||
| health_check: HealthCheckConfig::default(), | ||
| }, | ||
| schema: Schema::parse_and_validate("type Query { hello: String }", "test.graphql") | ||
| .expect("Valid schema"), | ||
| operations: vec![], | ||
| }; | ||
| let running = starting.start(); | ||
| assert!(running.await.is_ok()); | ||
| } | ||
| } | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! 👍