Skip to content

feat(ktor): add Ktor client tracing instrumentation - #14090

Open
cj848 wants to merge 6 commits into
pinpoint-apm:masterfrom
cj848:feat/ktor-client-plugin
Open

feat(ktor): add Ktor client tracing instrumentation#14090
cj848 wants to merge 6 commits into
pinpoint-apm:masterfrom
cj848:feat/ktor-client-plugin

Conversation

@cj848

@cj848 cj848 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Add outbound-call tracing for Ktor HTTP client (io.ktor.client.plugins.HttpSend$DefaultSender.execute(...)) to the built-in ktor plugin.

  • Each client call emits a KTOR_CLIENT span event with propagation headers.
  • Each suspending call also emits a KTOR_CLIENT_INTERNAL async span event, completed when the suspending continuation resumes.
  • Retry attempts via HttpRequestRetry emit one span event per attempt (each retry is a distinct remote call).
  • Mirrors a custom plugin maintained outside this repo in production deployments. Disabled by default via -Dprofiler.ktor.client.enable=true.

Needs review

  • Service type codes: claims KTOR_CLIENT=1900 / KTOR_CLIENT_INTERNAL=1901 in type-provider.yml. Move them if upstream prefers a different slot.
  • Test coverage: 28 unit tests cover interceptors, adaptors, configuration, and scope semantics. Full agent-anchored integration (drive the jar through a real naver-pinpoint-agent tarball plus a suspended HttpRequestRetry continuation) is possible but needs the upstream IT harness; happy to add as a follow-up PR if desired.
  • Dependency on the Kotlin-coroutines plugin: same constraint as the existing ktor server plugin's SuspendFunctionGun pattern; let me know if you want it removed.

Open questions

  1. Should profiler.ktor.client.enable default flip to true once this lands?
  2. Want the Ktor client version compat range documented in README (validated against Ktor 3.5.1 clients in production)?

Refs: https://pinpoint-apm.github.io/pinpoint/plugindevguide.html

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@cj848
cj848 marked this pull request as ready for review August 2, 2026 11:16
@cj848
cj848 force-pushed the feat/ktor-client-plugin branch from 524bf27 to b39d612 Compare August 2, 2026 22:57
cj848 added 6 commits August 3, 2026 08:15
Instrument io.ktor.client.plugins.HttpSend$DefaultSender.execute for Ktor
client outbound calls. Each call produces a KTOR_CLIENT span event with
propagation headers, plus a KTOR_CLIENT_INTERNAL async span event completed
when the suspending continuation resumes. Retry attempts via HttpRequestRetry
emit one span event per attempt.

The behaviour mirrors a custom plugin maintained outside this repo in
production deployments. Disabled by default via
-Dprofiler.ktor.client.enable=true.
Adds KTOR_CLIENT=1900 and KTOR_CLIENT_INTERNAL=1901 to KtorConstants so the
client interceptor can label span events with its own ServiceType instead of
re-using the shared OK_HTTP_CLIENT slot.
Declares KTOR_CLIENT (1900, recordStatistics) and KTOR_CLIENT_INTERNAL
(1901, matcher on http.status.code annotation 46) so the agent
TraceMetadataProviderLoader registers both types at boot.
The client transform targets io.ktor.client.plugins.HttpSend$DefaultSender
and io.ktor.client.request.HttpRequestBuilder, so the ktor client core
artifact is needed at provided scope alongside the existing server deps.
kotlinx-coroutines-core-jvm moves to provided too because
SuspendFunctionGunInterceptor constructs a CoroutineScope receiver.
Adds profiler.ktor.client.enable / .param / .mark.error to the README so
operators know the outbound tracing is opt-in.
- KtorPluginConfigTest: client flag defaults / overrides
- KtorClientHeaderAdaptorTest: set/get/contains round-trip
- KtorClientRequestAdaptorTest: destinationId, URL, IPv6, empty-host
- KtorClientCoroutineSuspendedMarkerTest: Kotlin suspension marker
- KtorClientContinuationConstructorInterceptorTest: pending holder attach/skip
- KtorClientContinuationInterceptorTest: resume / suspend / error / accessor cleanup
- KtorClientParentTraceStateTest: finish-once semantics + close-on-record-failure
- KtorClientTraceAccessorTest: set/get round-trip
- KtorClientTraceStorageTest: ThreadLocal isolation

Skipped KtorClientSendInterceptor and KtorClientTraceHolder — they need a
real Pinpoint agent registry (ServiceTypeProvider) which is only booted in
an agent runtime; an integration that drives the real naver-pinpoint-agent
tarball plus a suspended HttpRequestRetry continuation is a follow-up if
upstream wants one.
@cj848
cj848 force-pushed the feat/ktor-client-plugin branch from b39d612 to 14c0192 Compare August 2, 2026 23:18
@sonarqubecloud

sonarqubecloud Bot commented Aug 2, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants