Open Telemetry Support for KTOR#5497
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds native OpenTelemetry support for Ktor: new server and client plugins with public APIs, JVM implementations, tests, and READMEs; registers two new Gradle subprojects and OpenTelemetry dependency entries; updates an IDE VCS mapping. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
Actionable comments posted: 4
🧹 Nitpick comments (2)
.idea/vcs.xml (1)
27-27: IDE configuration change unrelated to PR objectives.This change to the VCS directory mapping appears to be an automatic IntelliJ IDEA update and is unrelated to the OpenTelemetry feature being added. Both
$PROJECT_DIR$and an empty string are functionally equivalent. Consider excluding this file from the PR to keep the changeset focused on the OpenTelemetry integration.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.idea/vcs.xml at line 27, Remove the unrelated IDE VCS mapping update by reverting the change to the <mapping> entry (the mapping directory="" vcs="Git" line) so the file no longer contains the empty-directory mapping; either discard the local .idea/vcs.xml change from the commit or restore the original mapping value (e.g., $PROJECT_DIR$) and ensure .idea/vcs.xml is excluded from the PR going forward (add to .gitignore or use git restore --staged/checkout to unstage the file) so only OpenTelemetry-related changes remain.ktor-server/ktor-server-plugins/ktor-server-opentelemetry/jvm/src/io/ktor/server/plugins/opentelemetry/OpenTelemetry.kt (1)
348-351: Exception recording may be bypassed when StatusPages handles errors.When StatusPages is installed and handles an exception, it does not rethrow, so
CallFailedwon't fire andtrace.throwablewon't be set. The span will still be ended correctly inResponseSentwith the appropriate status code, butrecordExceptionwon't capture the original exception details.This is consistent with how other Ktor observability plugins behave. If full exception capture is required even with StatusPages, users would need to manually record exceptions in their StatusPages handlers. Consider documenting this behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ktor-server/ktor-server-plugins/ktor-server-opentelemetry/jvm/src/io/ktor/server/plugins/opentelemetry/OpenTelemetry.kt` around lines 348 - 351, The current on(CallFailed) handler sets call.attributes.getOrNull(traceKey)?.throwable and rethrows, but when StatusPages intercepts and does not rethrow CallFailed won't fire and trace.throwable won't be set; update the documentation for the OpenTelemetry plugin explaining this behavior (mention on(CallFailed) and traceKey/trace.throwable) and instruct users to explicitly call recordException or set call.attributes[traceKey].throwable from their StatusPages handlers if they need exceptions captured; include a short note that ResponseSent still ends the span and records status codes but not the original exception when StatusPages suppresses it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 227-236: The exception path in the catch block ends the span but
never records the requestDuration metric; update the catch in OpenTelemetry.kt
(the catch handling span.recordException and span.end) to calculate the elapsed
time using the same start timestamp used on the success path (e.g., startTime or
startTimeNs) and call requestDuration.record with the computed duration and the
same attributes/tags used for successful requests so failed requests are
included in the histogram; do this before span.end so the metric and span share
the same timing/attributes.
In `@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md`:
- Line 53: The example documents capturing sensitive headers via
captureRequestHeaders("Authorization", "X-Api-Key"); update it to avoid
capturing credentials by removing "Authorization" (and any other auth tokens)
and instead show non-sensitive correlation headers such as "X-Request-ID" or
"Correlation-Id"; modify the README example that calls captureRequestHeaders to
only list safe headers and add a brief comment or note that Authorization and
API keys must not be exported to telemetry.
- Line 91: The README link to the server plugin is using a too-short relative
path ("../../ktor-server/ktor-server-plugins/ktor-server-opentelemetry"); update
that link to go up one more directory so it points to
"../../../ktor-server/ktor-server-plugins/ktor-server-opentelemetry" from
README.md in ktor-client-plugins/ktor-client-opentelemetry so the cross-module
link resolves correctly.
In `@ktor-server/ktor-server-plugins/ktor-server-opentelemetry/README.md`:
- Line 107: The README currently links the client plugin using the markdown link
text "[ktor-client-opentelemetry]" pointing to
"../../ktor-client/ktor-client-plugins/ktor-client-opentelemetry", which breaks
navigation; update that href to the correct relative path from this module's
README to the ktor-client-opentelemetry README (or use an
absolute/monorepo-rooted path) so the link resolves correctly, then verify the
link works in rendered docs; the target reference to change is the markdown link
[ktor-client-opentelemetry](../../ktor-client/ktor-client-plugins/ktor-client-opentelemetry).
---
Nitpick comments:
In @.idea/vcs.xml:
- Line 27: Remove the unrelated IDE VCS mapping update by reverting the change
to the <mapping> entry (the mapping directory="" vcs="Git" line) so the file no
longer contains the empty-directory mapping; either discard the local
.idea/vcs.xml change from the commit or restore the original mapping value
(e.g., $PROJECT_DIR$) and ensure .idea/vcs.xml is excluded from the PR going
forward (add to .gitignore or use git restore --staged/checkout to unstage the
file) so only OpenTelemetry-related changes remain.
In
`@ktor-server/ktor-server-plugins/ktor-server-opentelemetry/jvm/src/io/ktor/server/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 348-351: The current on(CallFailed) handler sets
call.attributes.getOrNull(traceKey)?.throwable and rethrows, but when
StatusPages intercepts and does not rethrow CallFailed won't fire and
trace.throwable won't be set; update the documentation for the OpenTelemetry
plugin explaining this behavior (mention on(CallFailed) and
traceKey/trace.throwable) and instruct users to explicitly call recordException
or set call.attributes[traceKey].throwable from their StatusPages handlers if
they need exceptions captured; include a short note that ResponseSent still ends
the span and records status codes but not the original exception when
StatusPages suppresses it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 509eec03-ae22-4108-b3b9-94a9f189c13e
📒 Files selected for processing (15)
.idea/vcs.xmlgradle/libs.versions.tomlktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.mdktor-client/ktor-client-plugins/ktor-client-opentelemetry/api/ktor-client-opentelemetry.apiktor-client/ktor-client-plugins/ktor-client-opentelemetry/api/ktor-client-opentelemetry.klib.apiktor-client/ktor-client-plugins/ktor-client-opentelemetry/build.gradle.ktsktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.ktktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/test/io/ktor/client/plugins/opentelemetry/OpenTelemetryTest.ktktor-server/ktor-server-plugins/ktor-server-opentelemetry/README.mdktor-server/ktor-server-plugins/ktor-server-opentelemetry/api/ktor-server-opentelemetry.apiktor-server/ktor-server-plugins/ktor-server-opentelemetry/api/ktor-server-opentelemetry.klib.apiktor-server/ktor-server-plugins/ktor-server-opentelemetry/build.gradle.ktsktor-server/ktor-server-plugins/ktor-server-opentelemetry/jvm/src/io/ktor/server/plugins/opentelemetry/OpenTelemetry.ktktor-server/ktor-server-plugins/ktor-server-opentelemetry/jvm/test/io/ktor/server/plugins/opentelemetry/OpenTelemetryTest.ktsettings.gradle.kts
...gins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
Show resolved
Hide resolved
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md
Outdated
Show resolved
Hide resolved
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md
Outdated
Show resolved
Hide resolved
ktor-server/ktor-server-plugins/ktor-server-opentelemetry/README.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 116-119: RequestBuilderHeadersSetter currently uses
carrier?.header(key, value) which appends values; change the TextMapSetter.set
implementation to replace existing header values by calling
carrier?.headers?.set(key, value) (targeting HttpRequestBuilder.headers.set) so
trace headers (e.g., "traceparent"/"tracestate") are overwritten rather than
appended when builders are reused.
- Around line 193-246: The catch block for execute(request) currently treats all
Throwables the same and loses HTTP response details when a ResponseException is
thrown (expectSuccess=true); update the catch to detect
io.ktor.client.plugins.ResponseException (or cast when cause is that type),
extract call.response.status.value and call.response.headers.getAll(headerName)
for the same responseHeaders loop, set span attributes
"http.response.status_code" and "http.response.header.<name>" and apply the same
StatusCode.ERROR + error.type logic used for statusCode>=400 before ending the
span and recording requestDuration; ensure requestDuration attributes include
http.response.status_code when available and preserve existing behavior for
non-ResponseException throwables.
In `@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md`:
- Around line 117-120: Update the trace diagram code fence to include a language
tag (use "text") so markdownlint MD040 is satisfied; locate the diagram block
containing "[Server] GET /api/users/{id} └── [Client] HTTP GET → user-service"
in README.md and change the opening triple-backtick to ```text to keep the
README lint-clean.
- Around line 85-91: Update the README section "Trace context injection" to
clarify that headers are injected only for requests that are actually traced and
that pass the plugin's request filter; explicitly state that when the filter
predicate rejects a request the implementation returns before calling
propagator.inject(...), so headers like traceparent/tracestate are added only to
outgoing requests with active trace context (i.e., traced requests handled by
the plugin) and not literally every outgoing request.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5417fe0a-c7b0-446a-8434-d4a91e40940d
📒 Files selected for processing (3)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.mdktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.ktktor-server/ktor-server-plugins/ktor-server-opentelemetry/README.md
...gins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
Show resolved
Hide resolved
...gins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
Show resolved
Hide resolved
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
♻️ Duplicate comments (1)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md (1)
117-120:⚠️ Potential issue | 🟡 MinorAdd a language tag to the trace diagram code fence.
The fenced block is still missing a language identifier (
MD040). Usetextto keep markdownlint clean.Suggested fix
-``` +```text [Server] GET /api/users/{id} └── [Client] HTTP GET → user-service</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.mdaround
lines 117 - 120, The fenced code block showing the trace diagram (the lines
starting with "[Server] GET /api/users/{id}" and "└── [Client] HTTP GET →
user-service") is missing a language tag; update the opening code fence fromtotext so the block becomestext ...to satisfy markdownlint MD040
and keep the diagram rendered as plain text.</details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md:
- Around line 117-120: The fenced code block showing the trace diagram (the
lines starting with "[Server] GET /api/users/{id}" and "└── [Client] HTTP GET →
user-service") is missing a language tag; update the opening code fence fromtotext so the block becomestext ...to satisfy markdownlint MD040
and keep the diagram rendered as plain text.</details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Path: .coderabbit.yaml **Review profile**: CHILL **Plan**: Pro **Run ID**: `32728fc6-814d-4c66-babf-d303bb28b9d7` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 8faf86cf0fde2914c347a39783b84cf4c5c054a1 and a2a4d3fceaccdebf0dca4b24cc684adc597fcedf. </details> <details> <summary>📒 Files selected for processing (1)</summary> * `ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
♻️ Duplicate comments (1)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt (1)
258-266:⚠️ Potential issue | 🟡 MinorDuration metric missing
http.response.status_codewhen available fromResponseException.When a
ResponseExceptionprovides a status code (e.g., 4xx/5xx withexpectSuccess = true), the error-path duration metric omitshttp.response.status_code, unlike the success path. This inconsistency affects metric cardinality and makes it harder to aggregate request duration by status code across both successful and failed requests.🔧 Proposed fix to include status code when available
val durationSeconds = (System.nanoTime() - startTime) / 1_000_000_000.0 - requestDuration.record( - durationSeconds, - OtelAttributes.builder() - .put("http.request.method", request.method.value) - .put("server.address", request.url.host) - .put("error.type", cause::class.qualifiedName ?: "unknown") - .build() - ) + val metricsBuilder = OtelAttributes.builder() + .put("http.request.method", request.method.value) + .put("server.address", request.url.host) + .put("error.type", cause::class.qualifiedName ?: "unknown") + if (statusCode != null) { + metricsBuilder.put("http.response.status_code", statusCode.toLong()) + } + requestDuration.record(durationSeconds, metricsBuilder.build())🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt` around lines 258 - 266, The error-path records requestDuration without the response status; update the block that builds OtelAttributes (in the requestDuration.record call) to detect when cause is a ResponseException and, if so, add "http.response.status_code" with the response status value to the attributes; use a safe cast (cause as? ResponseException) to read response.status.value and include it in the OtelAttributes.builder() exactly like the success path so metrics include status_code for failed requests as well.
🧹 Nitpick comments (1)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt (1)
234-255: Redundanterror.typeattribute setting.Lines 234-237 set
error.typeunconditionally, but it's immediately overwritten at either line 240 (whenstatusCode != null) or lines 251-254 (whenstatusCode == null). The initial assignment is unnecessary.♻️ Proposed simplification
span.recordException(cause) span.setStatus(StatusCode.ERROR, cause.message ?: "") - span.setAttribute( - OtelAttributeKey.stringKey("error.type"), - cause::class.qualifiedName ?: "unknown" - ) if (statusCode != null) { span.setAttribute(OtelAttributeKey.longKey("http.response.status_code"), statusCode.toLong()) span.setAttribute(OtelAttributeKey.stringKey("error.type"), statusCode.toString()) for (headerName in responseHeaders) { val values = response.headers.getAll(headerName) if (!values.isNullOrEmpty()) { span.setAttribute( OtelAttributeKey.stringArrayKey("http.response.header.$headerName"), values ) } } } else { span.setAttribute( OtelAttributeKey.stringKey("error.type"), cause::class.qualifiedName ?: "unknown" ) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt` around lines 234 - 255, Remove the redundant unconditional span.setAttribute call that sets "error.type" before the statusCode check: the initial assignment (using cause::class.qualifiedName ?: "unknown") is overwritten by the branch that sets "error.type" to statusCode.toString() when statusCode != null or the same cause-based value in the else branch; keep the "error.type" assignments only inside the two branches (the statusCode branch and the else branch) and eliminate the prior unconditional call around span/OtelAttributeKey.stringKey("error.type") to avoid duplicate writes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 258-266: The error-path records requestDuration without the
response status; update the block that builds OtelAttributes (in the
requestDuration.record call) to detect when cause is a ResponseException and, if
so, add "http.response.status_code" with the response status value to the
attributes; use a safe cast (cause as? ResponseException) to read
response.status.value and include it in the OtelAttributes.builder() exactly
like the success path so metrics include status_code for failed requests as
well.
---
Nitpick comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 234-255: Remove the redundant unconditional span.setAttribute call
that sets "error.type" before the statusCode check: the initial assignment
(using cause::class.qualifiedName ?: "unknown") is overwritten by the branch
that sets "error.type" to statusCode.toString() when statusCode != null or the
same cause-based value in the else branch; keep the "error.type" assignments
only inside the two branches (the statusCode branch and the else branch) and
eliminate the prior unconditional call around
span/OtelAttributeKey.stringKey("error.type") to avoid duplicate writes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b6a1963e-8949-4343-8ef5-ae366f7400ad
📒 Files selected for processing (2)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.mdktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
✅ Files skipped from review due to trivial changes (1)
- ktor-client/ktor-client-plugins/ktor-client-opentelemetry/README.md
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt (1)
258-265:⚠️ Potential issue | 🟠 MajorKeep
ResponseExceptionfailures queryable by status in the duration metric.The span now records
http.response.status_code, but this histogram branch still only getserror.type = ResponseException. ForexpectSuccess = true, that makes 4xx/5xx requests disappear from status-basedhttp.client.request.durationbreakdowns.🔧 Suggested fix
requestDuration.record( durationSeconds, OtelAttributes.builder() .put("http.request.method", request.method.value) .put("server.address", request.url.host) - .put("error.type", cause::class.qualifiedName ?: "unknown") + .apply { + if (response != null) { + val statusCode = response.status.value + put("http.response.status_code", statusCode.toLong()) + put("error.type", statusCode.toString()) + } else { + put("error.type", cause::class.qualifiedName ?: "unknown") + } + } .build() )#!/bin/bash # Inspect the current ResponseException catch path and the validators that throw it. sed -n '228,266p' \ ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt rg -n -C2 'ResponseException|ClientRequestException|ServerResponseException' \ ktor-client/ktor-client-core/common/src/io/ktor/client/plugins/DefaultResponseValidation.kt🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt` around lines 258 - 265, The duration metric branch currently sets error.type to the caught exception class (e.g., ResponseException) which hides response status for expectSuccess paths; update the catch/record logic in OpenTelemetry.kt where requestDuration.record(...) is called to detect ResponseException subclasses (ClientRequestException, ServerResponseException) and instead set/also include "http.response.status_code" (from the ResponseException.response.status.value) in the OtelAttributes builder while preserving error.type when non-ResponseException errors occur, so status-based breakdowns include 4xx/5xx values; change the attribute population in the requestDuration.record call and the surrounding exception handling that references ResponseException, ClientRequestException, and ServerResponseException accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 229-243: The code incorrectly guards on statusCode but then
dereferences response; change the null-check to guard on response != null (or
check response first and then read response.status.value into statusCode inside
that block) so that when you iterate responseHeaders and access response.headers
you have a non-null Response; update the condition around the block that sets
the http.response.status_code and loops response.headers (referencing response,
statusCode, responseHeaders, span.setAttribute, OtelAttributeKey) to ensure
response is non-null before use.
---
Duplicate comments:
In
`@ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt`:
- Around line 258-265: The duration metric branch currently sets error.type to
the caught exception class (e.g., ResponseException) which hides response status
for expectSuccess paths; update the catch/record logic in OpenTelemetry.kt where
requestDuration.record(...) is called to detect ResponseException subclasses
(ClientRequestException, ServerResponseException) and instead set/also include
"http.response.status_code" (from the ResponseException.response.status.value)
in the OtelAttributes builder while preserving error.type when
non-ResponseException errors occur, so status-based breakdowns include 4xx/5xx
values; change the attribute population in the requestDuration.record call and
the surrounding exception handling that references ResponseException,
ClientRequestException, and ServerResponseException accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8f27084d-8b1d-4a2d-9092-affc41832b3b
📒 Files selected for processing (1)
ktor-client/ktor-client-plugins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
...gins/ktor-client-opentelemetry/jvm/src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt
Show resolved
Hide resolved
…src/io/ktor/client/plugins/opentelemetry/OpenTelemetry.kt Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ME.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ME.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ME.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ME.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…dant variable and streamline status code extraction.
4840a1c to
d5aa626
Compare
Add native OpenTelemetry integration for server and client
Summary
ktor-server-opentelemetryandktor-client-opentelemetrymodules providing first-class OpenTelemetry distributed tracing, metrics, and context propagation - filling the gap alongside existing Micrometer and Dropwizard integrations.Motivation
Ktor has Micrometer and Dropwizard metrics plugins, but no native OpenTelemetry support. OpenTelemetry is the industry-standard, vendor-neutral observability framework for distributed tracing, metrics, and logging. Users currently must rely on the external
opentelemetry-java-instrumentationagent or manually instrument their applications. A native plugin provides a better developer experience with Ktor-idiomatic configuration, proper coroutine context propagation, and route-aware span naming.Usage
Key design decisions
ktor-server-metrics-micrometersince the OpenTelemetry Java SDK is JVM-onlyio.opentelemetry.api.OpenTelemetryinstance or individualTracerProvider/MeterProvider/TextMapPropagatorcomponentsThreadContextElementto propagate the OTELContextacross coroutine dispatches, soContext.current()works correctly inside handlers and client spans automatically become children of server spanshttp.request.method,url.path,http.route,http.server.request.duration, etc.)MicrometerMetricsplugin pattern (Metricshook,ResponseSent,CallFailed,RoutingRoot.RoutingCallStarted)Modules added
ktor-server-opentelemetryktor-server/ktor-server-plugins/ktor-server-opentelemetry/ktorbuild.project.server-pluginktor-client-opentelemetryktor-client/ktor-client-plugins/ktor-client-opentelemetry/ktorbuild.project.client-pluginDependencies added
io.opentelemetry:opentelemetry-api:1.54.0(API dependency for both modules)io.opentelemetry:opentelemetry-sdk:1.54.0(test only)io.opentelemetry:opentelemetry-sdk-testing:1.54.0(test only)