-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[Draft] Document OpenTelemetry integration #2001
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
base: main
Are you sure you want to change the base?
Conversation
Add comprehensive documentation for integrating OpenTelemetry with FastMCP: - New integration guide at docs/integrations/opentelemetry.mdx - Covers logging integration with LoggingHandler - Demonstrates span creation via custom middleware - Includes production OTLP export configuration - Provides complete working example Also update related docs: - Add OpenTelemetry reference in middleware.mdx - Add tip about OpenTelemetry in logging.mdx - Register doc in docs.json under new Observability section Example code: - examples/opentelemetry_example.py with working weather server Closes #1998 Co-authored-by: William Easton <[email protected]>
chrisguidry
left a comment
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.
I'm wondering why we wouldn't just bake the instrumentation directly into FastMCP and enable it by default? It's not harmful to have the no-op/non-recording spans if you're not exporting them anywhere. There may be a very slight performance effect, but I think it's pretty minimal. Worst case, we could give people an option to disable it if they didn't want OTEL.
| # Set up tracing | ||
| trace_provider = TracerProvider(resource=resource) | ||
| trace_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter())) | ||
| trace.set_tracer_provider(trace_provider) | ||
|
|
||
| # Set up logging | ||
| logger_provider = LoggerProvider(resource=resource) | ||
| logger_provider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogExporter())) | ||
| set_logger_provider(logger_provider) | ||
|
|
||
| # Attach OpenTelemetry to FastMCP's logger | ||
| fastmcp_logger = get_logger("my_server") | ||
| fastmcp_logger.addHandler(LoggingHandler(logger_provider=logger_provider)) |
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.
I think this approach would be considered "manual" instrumentation, which is always an option, but wouldn't most folks want something like the "Zero Code" version: https://opentelemetry.io/docs/zero-code/python/
I think we should at least point folks to this as the default, and then we can explain in more detail the manual approach.
I do think there are some additional envvars or CLI switches required to get logging setup with the zero code approach.
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.
Can you explain this a little more? What we would have to do to give folks the zero code experience?
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.
Oh sure! The OTEL libraries (at least for Python, but I think for most languages) make a pretty strong distinction between producing telemetry (opentelemetry-api) and exporting it (opentelemetry-sdk) and they offer these zero-code approaches where you are essentially wrapping your entrypoint with opentelemetry-instrument (in Python) so that your code doesn't need to set up any exporters. Their canonical example looks like this:
opentelemetry-instrument \
--traces_exporter console,otlp \
--metrics_exporter console \
--service_name your-service-name \
--exporter_otlp_endpoint 0.0.0.0:4317 \
python myapp.pyWhat would happen here is that your myapp.py might be using opentelemetry-api to make spans and metrics, and then when you run the program this way, the spans get exported to whichever ones you've configured there on the CLI. This example is very similar in spirit to what you laid out here, setting up OTLP exporters and attaching them to the providers, it's just handled by opentelemetry-instrument.
So my proposal is just to point people to that link for how they'd run their fastmcp servers by, say, wrapping them like:
opentelemetry-instrument \
--traces_exporter console,otlp \
--metrics_exporter console \
--service_name my-mcp-server \
--exporter_otlp_endpoint 0.0.0.0:4317 \
fastmcp run mymcpserver.py
docs/integrations/opentelemetry.mdx
Outdated
|
|
||
| ### Basic Tracing Middleware | ||
|
|
||
| Create a middleware that emits spans for all MCP requests: |
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.
Couldn't we just ship this middleware with FastMCP? I'd argue it should be on by default, even.
|
@chrisguidry I had Claude generate this, I was mostly going to stick with logging for now I thought the problem with emitting spans was going to be that we don't have a way to accept or propagate the trace id through MCP calls so the spans would all be uncorrelated I'd be very happy to do more if we thought it was useful and sensible |
Yep, that's a great call, and I think it might need to be pushed lower into the base SDK? I would make an argument that even without trace propagation, there's still some value because you'd see all of the things your MCP server called out to, even if each tool call was a separate trace. Also, as soon as the community figures out client-side trace propagation, it would all "just work" (LOL). Didn't mean to block your efforts to get great documentation in for sure! |
I'm ok adding it to our client and server as experimental until the lower level sdk gets it together, would that be interesting for you? |
|
I found this PR when trying to add otel instrumentation to a FastMCP server. I notice no mention of this package: Would that package not be recommended? Is that something you'd add to FastMCP itself? |
|
Update: I brought in the middleware from your PR and got it working with two OTel-compliant platforms. I also added in StarletteMiddleware on the FastMCP's Starlette app instance, for route-level tracing too. I think it'd be great if this was added to FastMCP itself. |
|
@pamelafox im not sure using middleware makes the most sense here but im glad it worked for your use-case |
|
/marvin let's update the PR to bake the instrumentation right in |
|
Claude finished @strawgate's task —— View job Baking OpenTelemetry instrumentation into FastMCP ✓Successfully integrated OpenTelemetry instrumentation directly into FastMCP core! Completed Tasks
What Was ImplementedBuilt-in OpenTelemetry Middleware (
Optional Dependency:
Updated Documentation:
Tests:
UsageUsers can now simply add the middleware: from fastmcp import FastMCP
from fastmcp.server.middleware.opentelemetry import OpenTelemetryMiddleware
mcp = FastMCP("My Server")
mcp.add_middleware(OpenTelemetryMiddleware())If OpenTelemetry isn't installed, the middleware safely becomes a no-op. To enable full instrumentation: pip install fastmcp[opentelemetry]All validation checks pass ✓ |
WalkthroughThis PR adds OpenTelemetry observability to the docs, examples, and server middleware. It inserts an "Observability" group under Integrations in Pre-merge checks and finishing touches❌ Failed checks (2 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 2
♻️ Duplicate comments (1)
examples/opentelemetry_example.py (1)
121-213: Example tools and error handling are appropriate as a “happy path” demoThe three tools (
get_weather,get_forecast,convert_temperature) demonstrate logging at different levels and basic validation without overcomplicating control flow. The explicit error messages and simpleValueErrorusage are fine here, and I’d ignore Ruff’s stylistic TRY*** suggestions for this educational example.No changes needed from my side.
Based on learnings, keeping this as a clear happy‑path example without extra defensive layers is preferable.
Also applies to: 220-234
🧹 Nitpick comments (1)
docs/integrations/opentelemetry.mdx (1)
21-112: Surface zero-code instrumentation as the recommended starting point and clarify logging API stabilityTwo important additions to strengthen this guide:
Lead with
opentelemetry-instrumentas the default approach
The official OpenTelemetry Python documentation promotesopentelemetry-instrumentas the zero-code instrumentation path. Add a brief section before "Logging Integration" that explains this is the recommended way to get started, then clarify that the rest of this page covers manual/fine-grained programmatic setup for cases where you need custom configuration. Include a link to OpenTelemetry's zero-code Python guide. This helps readers quickly find the simplest path without having to read the entire manual setup.Add forward-compatibility note for logging APIs
The official OpenTelemetry Python documentation explicitly states the Logs API and SDK are still under active development. Add a note near the logging setup code (e.g., under "Basic Setup" or at the start of "Logging Integration") stating: "OpenTelemetry's Python Logs API is currently under development. If import paths change in future versions, refer to the official OpenTelemetry Python logs documentation." This prevents the guide from becoming stale as the logging signal stabilizes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
docs/docs.json(1 hunks)docs/integrations/opentelemetry.mdx(1 hunks)docs/servers/logging.mdx(1 hunks)docs/servers/middleware.mdx(1 hunks)examples/opentelemetry_example.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
docs/**/*.mdx
📄 CodeRabbit inference engine (docs/.cursor/rules/mintlify.mdc)
docs/**/*.mdx: Use clear, direct language appropriate for technical audiences
Write in second person ('you') for instructions and procedures in MDX documentation
Use active voice over passive voice in MDX technical documentation
Employ present tense for current states and future tense for outcomes in MDX documentation
Maintain consistent terminology throughout all MDX documentation
Keep sentences concise while providing necessary context in MDX documentation
Use parallel structure in lists, headings, and procedures in MDX documentation
Lead with the most important information using inverted pyramid structure in MDX documentation
Use progressive disclosure in MDX documentation: present basic concepts before advanced ones
Break complex procedures into numbered steps in MDX documentation
Include prerequisites and context before instructions in MDX documentation
Provide expected outcomes for each major step in MDX documentation
End sections with next steps or related information in MDX documentation
Use descriptive, keyword-rich headings for navigation and SEO in MDX documentation
Focus on user goals and outcomes rather than system features in MDX documentation
Anticipate common questions and address them proactively in MDX documentation
Include troubleshooting for likely failure points in MDX documentation
Provide multiple pathways (beginner vs advanced) but offer an opinionated path to avoid overwhelming users in MDX documentation
Always include complete, runnable code examples that users can copy and execute in MDX documentation
Show proper error handling and edge case management in MDX code examples
Use realistic data instead of placeholder values in MDX code examples
Include expected outputs and results for verification in MDX code examples
Test all code examples thoroughly before publishing in MDX documentation
Specify language and include filename when relevant in MDX code examples
Add explanatory comments for complex logic in MDX code examples
Document all API...
Files:
docs/servers/logging.mdxdocs/integrations/opentelemetry.mdxdocs/servers/middleware.mdx
🧠 Learnings (1)
📚 Learning: 2025-11-03T17:36:13.363Z
Learnt from: jlowin
Repo: jlowin/fastmcp PR: 2355
File: docs/clients/client.mdx:226-246
Timestamp: 2025-11-03T17:36:13.363Z
Learning: In FastMCP documentation, prefer showing the happy path in onboarding examples without over-explaining edge cases or adding defensive checks, as this reduces cognitive burden for new users learning the API.
Applied to files:
docs/integrations/opentelemetry.mdx
🧬 Code graph analysis (1)
examples/opentelemetry_example.py (2)
src/fastmcp/server/middleware/middleware.py (2)
Middleware(80-208)MiddlewareContext(48-64)src/fastmcp/utilities/logging.py (1)
get_logger(14-26)
🪛 Ruff (0.14.7)
examples/opentelemetry_example.py
92-92: Consider moving this statement to an else block
(TRY300)
164-164: Avoid specifying long messages outside the exception class
(TRY003)
198-198: Avoid specifying long messages outside the exception class
(TRY003)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (3)
docs/servers/logging.mdx (1)
10-14: OpenTelemetry cross-link in logging docs looks goodThe added sentence clearly routes readers from client logging to the broader OpenTelemetry observability guide and matches the new
/integrations/opentelemetrypath. No changes needed.docs/servers/middleware.mdx (1)
596-600: Logging middleware Tip cleanly surfaces OpenTelemetry for productionThe new intro sentence and Tip succinctly explain what the logging middleware does and point production users to the OpenTelemetry guide. This is consistent with the rest of the middleware docs and the new Observability section.
docs/docs.json (1)
216-222: Observability navigation group is well-placed and consistentAdding an “Observability” group with
integrations/opentelemetryunder Integrations makes the new guide discoverable and matches the page path. No issues here.
| ```python | ||
| from fastmcp.server.middleware.timing import TimingMiddleware | ||
| from fastmcp.server.middleware.logging import LoggingMiddleware | ||
|
|
||
| # Order matters: error handling first, then tracing, then logging | ||
| mcp.add_middleware(ErrorHandlingMiddleware()) | ||
| mcp.add_middleware(OpenTelemetryMiddleware()) # Your custom middleware | ||
| mcp.add_middleware(TimingMiddleware()) # Built-in timing | ||
| mcp.add_middleware(LoggingMiddleware()) # Built-in logging | ||
| ``` |
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.
Import for ErrorHandlingMiddleware missing in integration example
In the “Integration with FastMCP Middleware” example, you call ErrorHandlingMiddleware() but only import TimingMiddleware and LoggingMiddleware. As written, that snippet won’t run.
I’d suggest adding the import to keep the example copy‑pasteable:
-from fastmcp.server.middleware.timing import TimingMiddleware
-from fastmcp.server.middleware.logging import LoggingMiddleware
+from fastmcp.server.middleware.timing import TimingMiddleware
+from fastmcp.server.middleware.logging import LoggingMiddleware
+from fastmcp.server.middleware.error_handling import ErrorHandlingMiddleware📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```python | |
| from fastmcp.server.middleware.timing import TimingMiddleware | |
| from fastmcp.server.middleware.logging import LoggingMiddleware | |
| # Order matters: error handling first, then tracing, then logging | |
| mcp.add_middleware(ErrorHandlingMiddleware()) | |
| mcp.add_middleware(OpenTelemetryMiddleware()) # Your custom middleware | |
| mcp.add_middleware(TimingMiddleware()) # Built-in timing | |
| mcp.add_middleware(LoggingMiddleware()) # Built-in logging | |
| ``` | |
| from fastmcp.server.middleware.timing import TimingMiddleware | |
| from fastmcp.server.middleware.logging import LoggingMiddleware | |
| from fastmcp.server.middleware.error_handling import ErrorHandlingMiddleware | |
| # Order matters: error handling first, then tracing, then logging | |
| mcp.add_middleware(ErrorHandlingMiddleware()) | |
| mcp.add_middleware(OpenTelemetryMiddleware()) # Your custom middleware | |
| mcp.add_middleware(TimingMiddleware()) # Built-in timing | |
| mcp.add_middleware(LoggingMiddleware()) # Built-in logging |
🤖 Prompt for AI Agents
In docs/integrations/opentelemetry.mdx around lines 491 to 500 the example uses
ErrorHandlingMiddleware() but does not import it; add an import for
ErrorHandlingMiddleware alongside the other middleware imports at the top of the
snippet (e.g., from fastmcp.server.middleware.error import
ErrorHandlingMiddleware) so the example is copy-paste runnable.
| # Define service metadata | ||
| resource = Resource( | ||
| attributes={ | ||
| "service.name": "fastmcp-weather-server", | ||
| "service.version": "1.0.0", | ||
| "deployment.environment": "development", | ||
| } | ||
| ) | ||
|
|
||
| # Configure tracing | ||
| trace_provider = TracerProvider(resource=resource) | ||
| trace_provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter())) | ||
| trace.set_tracer_provider(trace_provider) | ||
|
|
||
| # Configure logging | ||
| logger_provider = LoggerProvider(resource=resource) | ||
| logger_provider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogExporter())) | ||
| set_logger_provider(logger_provider) | ||
|
|
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.
🧩 Analysis chain
🏁 Script executed:
# Find the FastMCP logging utilities and check for logging configuration
find . -name "*.py" -type f | head -20Repository: jlowin/fastmcp
Length of output: 995
🏁 Script executed:
# Search for logging configuration patterns
rg -n "basicConfig|setLevel|get_logger" --type=py | head -30Repository: jlowin/fastmcp
Length of output: 2532
🏁 Script executed:
# Look at the opentelemetry_example.py file directly
fd "opentelemetry_example.py" -type fRepository: jlowin/fastmcp
Length of output: 228
🏁 Script executed:
# Read the logging utilities to understand get_logger implementation
cat -n src/fastmcp/utilities/logging.pyRepository: jlowin/fastmcp
Length of output: 8842
🏁 Script executed:
# Read the opentelemetry_example.py file
cat -n examples/opentelemetry_example.pyRepository: jlowin/fastmcp
Length of output: 9292
Set logger level so INFO logs reach OpenTelemetry
The OTEL logging pipeline and LoggingHandler wiring look solid, but get_logger("weather") doesn't set a level here. Python's default effective level is WARNING, so your many logger.info(...) calls won't reach the OTEL handler.
Add logger.setLevel(logging.INFO) before attaching the handler:
+import logging
...
logger = get_logger("weather")
+logger.setLevel(logging.INFO)
logger.addHandler(LoggingHandler(logger_provider=logger_provider))Also applies to: 110-113
🤖 Prompt for AI Agents
In examples/opentelemetry_example.py around lines 40-58 (and also apply same
change at 110-113), the logger created with get_logger("weather") does not have
an explicit level so INFO messages are blocked by the default WARNING level; set
the logger's level to logging.INFO (i.e., call logger.setLevel(logging.INFO))
before attaching any OpenTelemetry LoggingHandler so INFO logs are emitted to
the OTEL pipeline, and repeat the same change where the logger is created at
lines 110-113.
- Create OpenTelemetryMiddleware with automatic span creation for all MCP operations - Add opentelemetry as optional dependency (pip install fastmcp[opentelemetry]) - Gracefully degrades to no-op when OpenTelemetry not installed - Configuration options for privacy (include_arguments) and performance (max_argument_length) - Update documentation to reflect built-in support - Update example to use built-in middleware - Add comprehensive tests Co-authored-by: William Easton <[email protected]>
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.
Actionable comments posted: 0
♻️ Duplicate comments (1)
examples/opentelemetry_example.py (1)
65-67: Set logger level to ensure INFO logs reach OpenTelemetry.Without an explicit level, Python's default effective level is WARNING, so the
logger.info(...)calls in the tool functions won't reach the OpenTelemetry handler. Addlogger.setLevel(logging.INFO)after getting the logger.+import logging + # Attach OpenTelemetry to FastMCP's logger logger = get_logger("weather") +logger.setLevel(logging.INFO) logger.addHandler(LoggingHandler(logger_provider=logger_provider))
🧹 Nitpick comments (3)
src/fastmcp/server/middleware/opentelemetry.py (3)
126-137: Consider more specific return type annotation.The return type
dictcould be more specific asdict[str, Any]for better type checking.- def _create_span_attributes(self, context: MiddlewareContext, **extra: Any) -> dict: + def _create_span_attributes(self, context: MiddlewareContext, **extra: Any) -> dict[str, Any]:
139-141: Type annotations could be more specific to match base class.The base
Middlewareclass uses specific types likeMiddlewareContext[mt.CallToolRequestParams]andCallNext[mt.CallToolRequestParams, ToolResult]. WhileAnyworks, matching the base class signatures would improve type safety.
185-187: Remove unnecessary f-string prefix.The span name
f"resource.read"contains no placeholders, so thefprefix is extraneous.with self.tracer.start_as_current_span( # type: ignore[union-attr] - f"resource.read", attributes=span_attributes + "resource.read", attributes=span_attributes ) as span:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
pyproject.tomlis excluded by none and included by nonetests/server/middleware/test_opentelemetry_middleware.pyis excluded by none and included by noneuv.lockis excluded by!**/*.lockand included by none
📒 Files selected for processing (3)
docs/integrations/opentelemetry.mdx(1 hunks)examples/opentelemetry_example.py(1 hunks)src/fastmcp/server/middleware/opentelemetry.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
docs/**/*.mdx
📄 CodeRabbit inference engine (docs/.cursor/rules/mintlify.mdc)
docs/**/*.mdx: Use clear, direct language appropriate for technical audiences
Write in second person ('you') for instructions and procedures in MDX documentation
Use active voice over passive voice in MDX technical documentation
Employ present tense for current states and future tense for outcomes in MDX documentation
Maintain consistent terminology throughout all MDX documentation
Keep sentences concise while providing necessary context in MDX documentation
Use parallel structure in lists, headings, and procedures in MDX documentation
Lead with the most important information using inverted pyramid structure in MDX documentation
Use progressive disclosure in MDX documentation: present basic concepts before advanced ones
Break complex procedures into numbered steps in MDX documentation
Include prerequisites and context before instructions in MDX documentation
Provide expected outcomes for each major step in MDX documentation
End sections with next steps or related information in MDX documentation
Use descriptive, keyword-rich headings for navigation and SEO in MDX documentation
Focus on user goals and outcomes rather than system features in MDX documentation
Anticipate common questions and address them proactively in MDX documentation
Include troubleshooting for likely failure points in MDX documentation
Provide multiple pathways (beginner vs advanced) but offer an opinionated path to avoid overwhelming users in MDX documentation
Always include complete, runnable code examples that users can copy and execute in MDX documentation
Show proper error handling and edge case management in MDX code examples
Use realistic data instead of placeholder values in MDX code examples
Include expected outputs and results for verification in MDX code examples
Test all code examples thoroughly before publishing in MDX documentation
Specify language and include filename when relevant in MDX code examples
Add explanatory comments for complex logic in MDX code examples
Document all API...
Files:
docs/integrations/opentelemetry.mdx
src/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.py: Python source code must be version ≥3.10 with full type annotations
Prioritize readable, understandable code - clarity over cleverness; avoid obfuscated or confusing patterns even if they're shorter
Never use bareexceptin code - be specific with exception types
Files:
src/fastmcp/server/middleware/opentelemetry.py
🧠 Learnings (2)
📚 Learning: 2025-11-03T17:36:13.363Z
Learnt from: jlowin
Repo: jlowin/fastmcp PR: 2355
File: docs/clients/client.mdx:226-246
Timestamp: 2025-11-03T17:36:13.363Z
Learning: In FastMCP documentation, prefer showing the happy path in onboarding examples without over-explaining edge cases or adding defensive checks, as this reduces cognitive burden for new users learning the API.
Applied to files:
docs/integrations/opentelemetry.mdx
📚 Learning: 2025-11-26T21:52:08.947Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: docs/.cursor/rules/mintlify.mdc:0-0
Timestamp: 2025-11-26T21:52:08.947Z
Learning: Applies to docs/**/*.mdx : Always include realistic error handling in code examples in MDX documentation
Applied to files:
docs/integrations/opentelemetry.mdx
🧬 Code graph analysis (1)
src/fastmcp/server/middleware/opentelemetry.py (1)
src/fastmcp/server/middleware/middleware.py (3)
CallNext(43-44)Middleware(80-208)MiddlewareContext(48-64)
🪛 Ruff (0.14.7)
examples/opentelemetry_example.py
119-119: Avoid specifying long messages outside the exception class
(TRY003)
153-153: Avoid specifying long messages outside the exception class
(TRY003)
src/fastmcp/server/middleware/opentelemetry.py
164-164: Consider moving this statement to an else block
(TRY300)
186-186: f-string without any placeholders
Remove extraneous f prefix
(F541)
191-191: Consider moving this statement to an else block
(TRY300)
221-221: Consider moving this statement to an else block
(TRY300)
243-243: Consider moving this statement to an else block
(TRY300)
265-265: Consider moving this statement to an else block
(TRY300)
287-287: Consider moving this statement to an else block
(TRY300)
309-309: Consider moving this statement to an else block
(TRY300)
🔇 Additional comments (14)
docs/integrations/opentelemetry.mdx (7)
1-5: LGTM!Frontmatter is correctly structured with required
titleanddescriptionfields, plus an appropriate icon.
21-57: LGTM!The Quick Start section provides a clear, minimal example showing the happy path. The graceful degradation note and installation options are well-documented.
154-199: LGTM!The middleware configuration options and traced operations are well-documented and align with the implementation in
opentelemetry.py.
412-427: LGTM!The middleware integration example correctly imports only the middleware that is used. The execution order explanation is helpful for understanding the observability pipeline.
234-286: LGTM!The complete example demonstrates a production-ready setup combining logging and tracing with realistic tool implementation.
387-406: LGTM!The security guidance with the redaction example is practical and demonstrates a clear pattern for avoiding sensitive data in traces.
70-72: This review comment is unnecessary. The documentation already contains a clear stability warning in a<Note>component (line 50-56) that explicitly states: "Tracing and metrics are stable, while logging is in active development." This note appears immediately before the Logging Integration section and adequately informs users that the logging API is under active development and subject to change. The underscore-prefixed imports are the correct and documented approach for using OpenTelemetry Python logging at this time.Likely an incorrect or invalid review comment.
src/fastmcp/server/middleware/opentelemetry.py (2)
42-49: LGTM!The optional dependency handling is well-implemented - catches
ImportErrorspecifically and sets a module-level flag for graceful degradation.
227-313: LGTM!All list operation handlers follow a consistent pattern with proper span lifecycle management, attribute recording, and exception handling.
examples/opentelemetry_example.py (5)
39-56: LGTM!The OpenTelemetry configuration follows best practices with batch processors and proper resource attributes for service identification.
77-101: LGTM!The
get_weathertool demonstrates proper logging integration with the OpenTelemetry pipeline using realistic mock data.
104-133: LGTM!The
get_forecasttool demonstrates input validation with appropriate error handling and logging at multiple levels (INFO for normal operations, WARNING for invalid input).
136-168: LGTM!The
convert_temperaturetool demonstrates comprehensive logging at different levels (DEBUG, INFO, ERROR) and proper input validation with unit conversion logic.
175-189: LGTM!The main block provides helpful context for users running the example, with clear guidance about production deployment.
Add comprehensive documentation for integrating OpenTelemetry with FastMCP for distributed tracing and observability.
Changes
docs/integrations/opentelemetry.mdxexamples/opentelemetry_example.pyCloses #1998
Generated with Claude Code