Skip to content

Conversation

@carsonip
Copy link
Contributor

@carsonip carsonip commented Feb 11, 2026

Description

Validate franz-go configuration options early in Config.Validate

Affects exporter/kafka, receiver/kafka, receiver/kafkametrics

Link to tracking issue

Testing

Documentation

@carsonip carsonip changed the title [internal/kafka] Validate franz-go config in Config.Validate [internal/kafka] Validate franz-go configuration options early in Config.Validate Feb 11, 2026
carsonip and others added 2 commits February 11, 2026 16:14
Extract securityOpts helper from commonOpts and include TLS/SASL/Kerberos
options in kgo.ValidateOpts calls, using context.Background(). Add test
certificate files to kafkareceiver testdata.

Co-authored-by: Cursor <[email protected]>
// converting config values to kgo options and calling kgo.ValidateOpts.
func ValidateClientConfigOpts(cfg configkafka.ClientConfig) error {
opts := clientConfigOpts(cfg)
secOpts, err := securityOpts(context.Background(), cfg)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

[to reviewer] had to use context.Background because tlsConfig.LoadTLSConfig takes a ctx but it isn't available in config validate code path.

CAFile: "ca.pem",
CertFile: "cert.pem",
KeyFile: "key.pem",
CAFile: "testdata/ca.pem",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

[to reviewer] it was referencing non-existent tls files. This is now fixed by copying files into testdata and referencing them here.

Copy link
Member

Choose a reason for hiding this comment

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

That's ok for me 👍

Thanks for taking it. I was wondering if it does not make sense to dynamically generate certs at the test start, but for config test, maybe it does not take the effort 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer these to be dynamically generated within tests if possible, since if someone was to blindly scan the project and see static keys embedded they may panic.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds early validation of franz-go (franz-go/kgo) configuration by performing option validation during Config.Validate() for Kafka components, improving feedback on misconfiguration before runtime.

Changes:

  • Introduces internal/kafka.Validate{Client,Producer,Consumer}ConfigOpts helpers that translate configs to kgo.Opt and validate them.
  • Hooks the new validation into Config.Validate() for exporter/kafka, receiver/kafka, and receiver/kafkametrics.
  • Updates kafkareceiver testdata/config and adds TLS fixture PEM files to support TLS validation in tests.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/kafka/franz_client.go Refactors franz-go option construction and adds exported validation helpers using kgo.ValidateOpts.
exporter/kafkaexporter/config.go Validates producer/client franz-go options during exporter config validation.
receiver/kafkareceiver/config.go Validates consumer/client franz-go options per configured signal during receiver config validation.
receiver/kafkametricsreceiver/config.go Adds config validation that checks franz-go client options early.
receiver/kafkareceiver/config_test.go Adjusts expectations and test cases to account for TLS file paths and default client/consumer configs.
receiver/kafkareceiver/testdata/config.yaml Updates TLS paths to point at new testdata PEM files.
receiver/kafkareceiver/testdata/ca.pem Adds CA certificate fixture for TLS tests.
receiver/kafkareceiver/testdata/cert.pem Adds client certificate fixture for TLS tests.
receiver/kafkareceiver/testdata/key.pem Adds private key fixture for TLS tests.
.chloggen/kafka-validate-opts-*.yaml Adds changelog entries for the affected Kafka components.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 191 to 197
// Validate franz-go options for each configured signal. Deprecated
// Topic/ExcludeTopic fields are already migrated by Unmarshal.
for _, sig := range []*TopicEncodingConfig{&c.Logs, &c.Metrics, &c.Traces, &c.Profiles} {
if len(sig.Topics) == 0 {
continue
}
if err := kafka.ValidateConsumerConfigOpts(c.ClientConfig, c.ConsumerConfig, sig.Topics, sig.ExcludeTopics); err != nil {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

Config.Validate currently calls ValidateConsumerConfigOpts once per configured signal; that helper loads/parses TLS material via LoadTLSConfig each time. With the default config this can happen up to 4 times and repeats identical work. Consider validating the client/consumer/security options once (or caching the computed security opts) and only varying the topic-related opts per signal to avoid repeated file I/O and cert parsing during startup validation.

Suggested change
// Validate franz-go options for each configured signal. Deprecated
// Topic/ExcludeTopic fields are already migrated by Unmarshal.
for _, sig := range []*TopicEncodingConfig{&c.Logs, &c.Metrics, &c.Traces, &c.Profiles} {
if len(sig.Topics) == 0 {
continue
}
if err := kafka.ValidateConsumerConfigOpts(c.ClientConfig, c.ConsumerConfig, sig.Topics, sig.ExcludeTopics); err != nil {
// Validate franz-go options. Deprecated Topic/ExcludeTopic fields are already migrated by Unmarshal.
var allTopics []string
var allExcludeTopics []string
for _, sig := range []*TopicEncodingConfig{&c.Logs, &c.Metrics, &c.Traces, &c.Profiles} {
if len(sig.Topics) == 0 {
continue
}
allTopics = append(allTopics, sig.Topics...)
allExcludeTopics = append(allExcludeTopics, sig.ExcludeTopics...)
}
if len(allTopics) > 0 {
if err := kafka.ValidateConsumerConfigOpts(c.ClientConfig, c.ConsumerConfig, allTopics, allExcludeTopics); err != nil {

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

don't think we can avoid this nicely. When the component starts up and invokes NewClient, it will parse TLS files per signal anyway.

Comment on lines 392 to 416
// ValidateClientConfigOpts validates the configkafka.ClientConfig by
// converting config values to kgo options and calling kgo.ValidateOpts.
func ValidateClientConfigOpts(cfg configkafka.ClientConfig) error {
opts := clientConfigOpts(cfg)
secOpts, err := securityOpts(context.Background(), cfg)
if err != nil {
return err
}
opts = append(opts, secOpts...)
return kgo.ValidateOpts(opts...)
}

// ValidateProducerConfigOpts validates the configkafka.ClientConfig and
// configkafka.ProducerConfig by converting config values to kgo options
// and calling kgo.ValidateOpts.
func ValidateProducerConfigOpts(clientCfg configkafka.ClientConfig, producerCfg configkafka.ProducerConfig, timeout time.Duration) error {
opts := clientConfigOpts(clientCfg)
secOpts, err := securityOpts(context.Background(), clientCfg)
if err != nil {
return err
}
opts = append(opts, secOpts...)
opts = append(opts, producerConfigOpts(producerCfg)...)
opts = append(opts, kgo.ProduceRequestTimeout(timeout))
return kgo.ValidateOpts(opts...)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The new Validate*ConfigOpts helpers return raw errors from securityOpts / kgo.ValidateOpts. Those errors can be fairly low-level and may not mention which config section they came from. Consider wrapping returned errors with a short prefix (e.g., "invalid client config options" / "invalid producer config options" / "invalid consumer config options") to make Config.Validate() failures clearer for users.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

@carsonip carsonip Feb 11, 2026

Choose a reason for hiding this comment

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

consumer / producer config vs client config isn't a user-facing concept, don't think we need to tell between them in error message.

Add testdata entries and test cases to each component's TestLoadConfig
to verify that kgo.ValidateOpts catches invalid configurations early.

Co-authored-by: Cursor <[email protected]>
@paulojmdias
Copy link
Member

paulojmdias commented Feb 11, 2026

go.mod/go.sum deps changes detected, please run "make gotidy" and commit the changes in this PR.

PTAL into the CI error above 🙏

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants