@@ -45,8 +45,12 @@ import (
4545type SASLMechanism = sasl.Mechanism
4646
4747// TopicLogFieldFunc is a function that returns a zap.Field for a given topic.
48+ // Deprecated: use TopicLogFieldsFunc instead.
4849type TopicLogFieldFunc func (topic string ) zap.Field
4950
51+ // TopicLogFieldsFunc is a function that returns a list of zap.Field for a given topic.
52+ type TopicLogFieldsFunc func (topic string ) []zap.Field
53+
5054// CommonConfig defines common configuration for Kafka consumers, producers,
5155// and managers.
5256type CommonConfig struct {
@@ -150,16 +154,28 @@ type CommonConfig struct {
150154 // Defaults to the global one.
151155 MeterProvider metric.MeterProvider
152156
153- // TopicAttributeFunc can be used to create custom dimensions from a Kafka
157+ // TopicAttributeFunc can be used to create one custom dimension from a Kafka
154158 // topic for these metrics:
155159 // - producer.messages.count
156160 // - consumer.messages.fetched
161+ // Deprecated: Use TopicAttributesFunc instead.
157162 TopicAttributeFunc TopicAttributeFunc
158163
159- // TopicAttributeFunc can be used to create custom dimensions from a Kafka
160- // topic for log messages
164+ // TopicAttributesFunc can be used to create multiple custom dimensions from a Kafka
165+ // topic for these metrics:
166+ // - producer.messages.count
167+ // - consumer.messages.fetched
168+ TopicAttributesFunc TopicAttributesFunc
169+
170+ // TopicAttributeFunc can be used to create one custom dimension from a Kafka
171+ // topic for log messages.
172+ // Deprecated: use TopicLogFieldsFunc instead.
161173 TopicLogFieldFunc TopicLogFieldFunc
162174
175+ // TopicLogFieldsFunc can be used to create custom dimensions from a Kafka
176+ // // topic for log messages.
177+ TopicLogFieldsFunc TopicLogFieldsFunc
178+
163179 // MetadataMaxAge is the maximum age of metadata before it is refreshed.
164180 // The lower the value the more frequently new topics will be discovered.
165181 // If zero, the default value of 5 minutes is used.
@@ -198,23 +214,14 @@ func (cfg *CommonConfig) finalize() error {
198214 errs = append (errs , err )
199215 }
200216
201- // Wrap the cfg.TopicLogFieldFunc to ensure it never returns a field with
202- // an unknown type (like `zap.Field{}`).
203- if cfg .TopicLogFieldFunc != nil {
204- cfg .TopicLogFieldFunc = topicFieldFunc (cfg .TopicLogFieldFunc )
205- }
206- if cfg .TopicAttributeFunc == nil {
207- cfg .TopicAttributeFunc = func (topic string ) attribute.KeyValue {
208- return attribute.KeyValue {}
209- }
210- }
217+ cfg .TopicLogFieldsFunc = mergeTopicLogFieldsFunctions (cfg .TopicLogFieldFunc , cfg .TopicLogFieldsFunc )
218+ cfg .TopicAttributesFunc = mergeTopicAttributeFunctions (cfg .TopicAttributeFunc , cfg .TopicAttributesFunc )
211219
212220 return errors .Join (errs ... )
213221}
214222
215223// Merge the configs generated from env vars and/or files.
216224func (cfg * CommonConfig ) flatten (envCfg * envConfig , fileCfg * fileConfig ) error {
217-
218225 // Config file was set with env vars.
219226 if cfg .ConfigFile == "" {
220227 cfg .ConfigFile = envCfg .configFile
@@ -281,7 +288,24 @@ func (cfg *CommonConfig) meterProvider() metric.MeterProvider {
281288 return otel .GetMeterProvider ()
282289}
283290
284- func (cfg * CommonConfig ) newClient (topicAttributeFunc TopicAttributeFunc , additionalOpts ... kgo.Opt ) (* kgo.Client , error ) {
291+ type clientOptsFn func (opts * clientOpts )
292+
293+ type clientOpts struct {
294+ topicAttributesFunc TopicAttributesFunc
295+ }
296+
297+ func withTopicMultipleAttributeFunc (topicAttributesFunc TopicAttributesFunc ) func (clOpts * clientOpts ) {
298+ return func (clOpts * clientOpts ) {
299+ clOpts .topicAttributesFunc = topicAttributesFunc
300+ }
301+ }
302+
303+ func (cfg * CommonConfig ) newClientWithOpts (clientOptsFn []clientOptsFn , additionalOpts ... kgo.Opt ) (* kgo.Client , error ) {
304+ clOpts := & clientOpts {}
305+ for _ , opt := range clientOptsFn {
306+ opt (clOpts )
307+ }
308+
285309 opts := []kgo.Opt {
286310 kgo .WithLogger (kzap .New (cfg .Logger .Named ("kafka" ))),
287311 kgo .SeedBrokers (cfg .Brokers ... ),
@@ -304,8 +328,8 @@ func (cfg *CommonConfig) newClient(topicAttributeFunc TopicAttributeFunc, additi
304328 }
305329 opts = append (opts , additionalOpts ... )
306330 if ! cfg .DisableTelemetry {
307- metricHooks , err := newKgoHooks (cfg . meterProvider (),
308- cfg .Namespace , cfg .namespacePrefix (), topicAttributeFunc ,
331+ metricHooks , err := newKgoHooks (
332+ cfg .meterProvider (), cfg . Namespace , cfg .namespacePrefix (), clOpts . topicAttributesFunc ,
309333 )
310334 if err != nil {
311335 return nil , fmt .Errorf ("kafka: failed creating kgo metrics hooks: %w" , err )
@@ -359,6 +383,51 @@ func topicFieldFunc(f TopicLogFieldFunc) TopicLogFieldFunc {
359383 }
360384}
361385
386+ // mergeTopicLogFieldsFunctions merges the fields from TopicLogFieldFunc
387+ // and TopicLogFieldsFunc, and returns a new TopicLogFieldsFunc with all
388+ // log fields.
389+ func mergeTopicLogFieldsFunctions (single TopicLogFieldFunc , multiple TopicLogFieldsFunc ) TopicLogFieldsFunc {
390+ if single == nil {
391+ return multiple
392+ }
393+ if multiple == nil {
394+ return func (topic string ) []zap.Field {
395+ fn := topicFieldFunc (single )
396+ return []zap.Field {fn (topic )}
397+ }
398+ }
399+ return func (topic string ) []zap.Field {
400+ fields := multiple (topic )
401+ for i := range fields {
402+ if fields [i ].Type <= zapcore .UnknownType {
403+ fields [i ] = zap .Skip ()
404+ }
405+ }
406+ return append (fields , single (topic ))
407+ }
408+ }
409+
410+ // mergeTopicAttributeFunctions merges the attributes from TopicAttributeFunc
411+ // and TopicAttributesFunc, and returns a new TopicAttributesFunc with all
412+ // attributes.
413+ func mergeTopicAttributeFunctions (single TopicAttributeFunc , multiple TopicAttributesFunc ) TopicAttributesFunc {
414+ if single == nil {
415+ return multiple
416+ }
417+ if multiple == nil {
418+ return func (topic string ) []attribute.KeyValue {
419+ v := single (topic )
420+ if v == (attribute.KeyValue {}) {
421+ return nil
422+ }
423+ return []attribute.KeyValue {v }
424+ }
425+ }
426+ return func (topic string ) []attribute.KeyValue {
427+ return append (multiple (topic ), single (topic ))
428+ }
429+ }
430+
362431// newCertReloadingDialer returns a dialer that reloads the CA cert when the
363432// file mod time changes.
364433func newCertReloadingDialer (caPath , certPath , keyPath string ,
0 commit comments