Skip to content

feat(dsm): add kafka_cluster_id to Sarama integrations#4560

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 35 commits into
mainfrom
rob.carlan/sarama-cluster-id-v2
Mar 26, 2026
Merged

feat(dsm): add kafka_cluster_id to Sarama integrations#4560
gh-worker-dd-mergequeue-cf854d[bot] merged 35 commits into
mainfrom
rob.carlan/sarama-cluster-id-v2

Conversation

@robcarlan-datadog

@robcarlan-datadog robcarlan-datadog commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • This follows practically the same pattern as the confluent-kafka-go and kafka-go PRs. However, this integration requires the user to supply the bootstrap servers explicitly in order to obtain the cluster id.
  • Adds WithBrokers option to both IBM/sarama and Shopify/sarama integrations that fetches the Kafka cluster ID via a metadata request and includes it in DSM payloads (DSM only)
  • Tested manually and via unit / integration tests.

robcarlan-datadog and others added 29 commits February 26, 2026 12:11
Plumb Kafka cluster ID through the DSM pipeline so that offsets and
checkpoints from different clusters are distinguishable. For
confluent-kafka-go, the cluster ID is fetched automatically via the
AdminClient API; other Kafka libraries pass empty string for now and
will be wired in follow-up PRs.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add cluster ID as a span tag on produce and consume spans, add ext
constant MessagingKafkaClusterID, and add integration test verifying
cluster ID flows into spans, DSM pathway hashes, and backlog tags.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Auto-fetched cluster ID from the Kafka admin API is now prepended to
options so that user-provided WithClusterID takes precedence. Also fix
TestConsumerFunctional pathway hash to account for auto-fetched cluster
ID in integration test environments.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The TestConsumerFunctional test was computing expected pathway hashes
without the kafka_cluster_id tag, but the production code now includes
it after auto-fetching from the broker.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Avoid repeated admin API calls to fetch cluster ID when creating
multiple consumers/producers to the same Kafka cluster. The cache
is shared between v1 and v2 packages via kafkatrace.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Remove the public WithClusterID option function which was only used
internally and for testing. Set cluster ID directly on the tracer after
wrapping instead. Also reduce cluster ID fetch timeout from 10s to 2s.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Move cluster ID fetching to a background goroutine so it doesn't block
Consumer/Producer creation. Protect the clusterID field with a RWMutex
for safe concurrent access.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Move cluster ID goroutine lifecycle into the Tracer via
FetchClusterIDAsync/WaitForClusterID. Close() waits for the goroutine
to prevent use-after-free of the librdkafka handle. Tests call
WaitForClusterID before producing/consuming to ensure deterministic
pathway hashes.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… TrackKafkaProduceOffsetWithCluster params

FetchClusterIDAsync now accepts a cancellable context so Close() can
signal the fetch to stop early rather than blocking unconditionally.
Also reorders TrackKafkaProduceOffsetWithCluster params to match the
Kafka hierarchy: cluster, topic, partition, offset.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…formatting

Move cluster param to first position to match hierarchy (cluster, group,
topic, partition, offset). Fix struct field alignment in Tracer.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Cluster ID should always be available when running against a real Kafka
broker. Make assertions strict instead of conditionally skipping.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Deduplicate the admin client cluster ID fetch logic shared between
fetchClusterIDFromConsumer and fetchClusterIDFromProducer.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…tting

Replace separate CancelClusterIDFetch + WaitForClusterID calls in Close
with a single StopClusterIDFetch method. Fix gofmt struct alignment.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Remove the FetchClusterIDAsync/StopClusterIDFetch/WaitForClusterID
abstraction on the Tracer. Instead, use a standalone admin client
(kafka.NewAdminClient) so the goroutine has no shared state with the
consumer/producer and needs no coordination on Close(). Also remove
the cluster ID cache (clusterIDFromConfigOrFetch, cluster_id_cache.go).

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…cluster ID

NewAdminClient does not strip go.* prefixed keys (unlike NewConsumer/
NewProducer), causing errors like "No such configuration property:
go.delivery.reports". Filter them out before creating the admin client,
preserving all auth/TLS/SASL config.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
#4531)

## Summary

- Replace standalone goroutine fields
(`clusterIDCancel`/`clusterIDDone`) with a `closeAsync []func()` slice
on both `Consumer` and `Producer`
- Extract `startClusterIDFetch` helper that launches the cluster ID
fetch goroutine and returns a cancel+wait closure — context cancellation
unblocks the `ClusterID` call immediately on `Close()`
- Switch from standalone `kafka.NewAdminClient` to derived
`kafka.NewAdminClientFromConsumer`/`NewAdminClientFromProducer` —
eliminates `go.*` config key filtering
- Apply identical changes to both `kafka/` (v1) and `kafka.v2/` (v2)
- Port missing test coverage to v1: add
`TestConsumerFunctionalWithClusterID` and assert
`ext.MessagingKafkaClusterID` span tag in `TestConsumerFunctional`

To merge in #4470 to fix CI leak
The consumer's WrapConsumer was unconditionally spawning a goroutine to
fetch the Kafka cluster ID, even when data streams monitoring is
disabled. The producer's WrapProducer had the fetch outside the
DSMEnabled() block in the v2 variant. Wrap both consumer and producer
cluster ID fetches in DSMEnabled() guards across both kafka v1 and v2
packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@github-actions github-actions Bot added the apm:ecosystem contrib/* related feature requests or bugs label Mar 18, 2026
@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from 805e4ce to c5ceb7d Compare March 18, 2026 19:52
@datadog-prod-us1-3

This comment has been minimized.

@codecov

codecov Bot commented Mar 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.81%. Comparing base (6ae9763) to head (f302fba).
⚠️ Report is 104 commits behind head on main.

Additional details and impacted files

see 277 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from c5ceb7d to ff33172 Compare March 18, 2026 19:59
@pr-commenter

pr-commenter Bot commented Mar 18, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-03-26 16:36:21

Comparing candidate commit f302fba in PR branch rob.carlan/sarama-cluster-id-v2 with baseline commit 6ae9763 in branch main.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 216 metrics, 8 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from ff33172 to 40703b2 Compare March 18, 2026 20:17
Add kafka_cluster_id support to both IBM/sarama and Shopify/sarama,
matching the pattern from the confluent-kafka-go integration (PR #4470):

- cfg.ClusterID() / cfg.SetClusterID() with sync.RWMutex for thread-safe
  access from the message path and the background fetch goroutine
- closeAsync []func() on wrapped producers for cancelling in-flight
  fetches on Close()
- startClusterIDFetch launches a background goroutine that connects to a
  broker, sends a MetadataRequest v4, and calls cfg.SetClusterID()
- WithBrokers(addrs) option provides broker addresses (required because
  sarama's producer/consumer interfaces don't expose broker info)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from 40703b2 to 2111f07 Compare March 18, 2026 21:53
Base automatically changed from rob.carlan/dsm-kafka-cluster-id to main March 19, 2026 23:38
@robcarlan-datadog
robcarlan-datadog marked this pull request as ready for review March 20, 2026 03:57
@robcarlan-datadog
robcarlan-datadog requested review from a team as code owners March 20, 2026 03:57
@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from 0ee430e to bf40326 Compare March 20, 2026 17:21
@robcarlan-datadog
robcarlan-datadog force-pushed the rob.carlan/sarama-cluster-id-v2 branch from bf40326 to 1afc785 Compare March 20, 2026 17:26

@genesor genesor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. We need to be able to tell customer that this cluster ID is not available OOTB for Sarama integration for now.

An improvement we could make in a later PR @robcarlan-datadog would be to provide new public funcs for this we'd use to grab the brokers. We could also look into leveraging orchestrion to this somehow inside the sarama packages.

@rarguelloF rarguelloF left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, approving with a small nit

Comment thread contrib/Shopify/sarama/sarama.go Outdated
Comment thread contrib/IBM/sarama/producer.go Outdated
Comment thread contrib/IBM/sarama/consumer_group.go Outdated
Comment thread contrib/IBM/sarama/consumer.go Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apm:ecosystem contrib/* related feature requests or bugs mergequeue-status: done

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants