@@ -25,6 +25,7 @@ import (
2525 "go.opentelemetry.io/collector/config/configopaque"
2626 "go.opentelemetry.io/collector/config/configoptional"
2727 "go.opentelemetry.io/collector/config/configtls"
28+ "go.opentelemetry.io/collector/confmap"
2829)
2930
3031const (
@@ -94,7 +95,8 @@ type ClientConfig struct {
9495 // with the first middleware becoming the outermost handler.
9596 Middlewares []configmiddleware.Config `mapstructure:"middlewares,omitempty"`
9697
97- // Keepalive configuration.
98+ // Keepalive configuration. When set, it takes precedence over the
99+ // deprecated flat fields below.
98100 Keepalive configoptional.Optional [KeepaliveClientConfig ] `mapstructure:"keepalive,omitempty"`
99101
100102 // Deprecated: use Keepalive.IdleConnTimeout instead.
@@ -103,8 +105,12 @@ type ClientConfig struct {
103105 MaxIdleConns int `mapstructure:"max_idle_conns,omitempty"`
104106 // Deprecated: use Keepalive.MaxIdleConnsPerHost instead.
105107 MaxIdleConnsPerHost int `mapstructure:"max_idle_conns_per_host,omitempty"`
106- // Deprecated: set Keepalive to None to disable keep-alives.
108+ // Deprecated: set 'keepalive::enabled' to false to disable keep-alives.
107109 DisableKeepAlives bool `mapstructure:"disable_keep_alives,omitempty"`
110+
111+ // deprecationWarnings records use of deprecated fields observed while
112+ // unmarshaling; ToClient logs them, as no logger is available here.
113+ deprecationWarnings []string
108114}
109115
110116// CookiesConfig defines the configuration of the HTTP client regarding cookies served by the server.
@@ -138,6 +144,10 @@ func NewDefaultClientConfig() ClientConfig {
138144 defaultTransport := http .DefaultTransport .(* http.Transport )
139145
140146 return ClientConfig {
147+ // The deprecated flat fields keep carrying the defaults so that
148+ // configurations and code which still use them behave as before.
149+ MaxIdleConns : defaultTransport .MaxIdleConns ,
150+ IdleConnTimeout : defaultTransport .IdleConnTimeout ,
141151 Keepalive : configoptional .Default (KeepaliveClientConfig {
142152 MaxIdleConns : defaultTransport .MaxIdleConns ,
143153 IdleConnTimeout : defaultTransport .IdleConnTimeout ,
@@ -146,22 +156,70 @@ func NewDefaultClientConfig() ClientConfig {
146156 }
147157}
148158
159+ var _ confmap.Unmarshaler = (* ClientConfig )(nil )
160+
161+ // Unmarshal implements confmap.Unmarshaler. It rejects configurations mixing the
162+ // deprecated keepalive fields with the 'keepalive' section and records deprecation
163+ // warnings for ToClient to log. Only keys present in the configuration count:
164+ // values set programmatically (e.g. by a component's default config) are neither
165+ // deprecated usage nor a conflict.
166+ func (cc * ClientConfig ) Unmarshal (conf * confmap.Conf ) error {
167+ prevKeepalive := cc .Keepalive
168+ // Read before unmarshaling: decoding the Optional consumes the 'enabled' key.
169+ keepaliveDisabled := conf .Get ("keepalive::enabled" ) == false
170+
171+ // WithIgnoreUnused is needed because ClientConfig is commonly squash-embedded
172+ // into component configs, in which case conf also holds the parent's sibling fields.
173+ if err := conf .Unmarshal (cc , confmap .WithIgnoreUnused ()); err != nil {
174+ return err
175+ }
176+
177+ // A null 'keepalive' key carries no settings, but decodes as an enabled
178+ // section. Marshaling produces it for an unset Keepalive, so treat it as
179+ // unset to keep marshaled configurations loadable.
180+ keepaliveSet := conf .IsSet ("keepalive" ) && conf .Get ("keepalive" ) != nil
181+ if ! keepaliveSet {
182+ cc .Keepalive = prevKeepalive
183+ }
184+
185+ // Values which match the field's zero value are no-ops in the legacy logic,
186+ // so they neither conflict with the 'keepalive' section nor deserve a warning.
187+ var deprecated []string
188+ if conf .IsSet ("idle_conn_timeout" ) && cc .IdleConnTimeout != 0 {
189+ deprecated = append (deprecated , "'idle_conn_timeout' is deprecated; use 'keepalive::idle_conn_timeout' instead" )
190+ }
191+ if conf .IsSet ("max_idle_conns" ) && cc .MaxIdleConns != 0 {
192+ deprecated = append (deprecated , "'max_idle_conns' is deprecated; use 'keepalive::max_idle_conns' instead" )
193+ }
194+ if conf .IsSet ("max_idle_conns_per_host" ) && cc .MaxIdleConnsPerHost != 0 {
195+ deprecated = append (deprecated , "'max_idle_conns_per_host' is deprecated; use 'keepalive::max_idle_conns_per_host' instead" )
196+ }
197+ if conf .IsSet ("disable_keep_alives" ) && cc .DisableKeepAlives {
198+ deprecated = append (deprecated , "'disable_keep_alives' is deprecated; set 'keepalive::enabled' to false to disable keep-alives" )
199+ }
200+ if keepaliveSet && len (deprecated ) > 0 {
201+ return errors .New ("confighttp.ClientConfig: cannot use deprecated keepalive fields (idle_conn_timeout, max_idle_conns, max_idle_conns_per_host, disable_keep_alives) alongside the 'keepalive' section; migrate to the 'keepalive' section" )
202+ }
203+ cc .deprecationWarnings = deprecated
204+
205+ // 'keepalive::enabled: false' leaves the Optional without a value, which is
206+ // indistinguishable from an unset section; carry the intent in the flat
207+ // field, which the resolution in ToClient falls back to.
208+ if keepaliveDisabled {
209+ cc .DisableKeepAlives = true
210+ }
211+ return nil
212+ }
213+
149214func (cc * ClientConfig ) Validate () error {
150215 if cc .Compression .IsCompressed () {
151216 if err := cc .Compression .ValidateParams (cc .CompressionParams ); err != nil {
152217 return err
153218 }
154219 }
155- if cc .Keepalive .HasValue () && cc .hasDeprecatedKeepaliveFields () {
156- return errors .New ("confighttp.ClientConfig: cannot use deprecated keepalive fields (idle_conn_timeout, max_idle_conns, max_idle_conns_per_host, disable_keep_alives) alongside the 'keepalive' section; migrate to the 'keepalive' section" )
157- }
158220 return nil
159221}
160222
161- func (cc * ClientConfig ) hasDeprecatedKeepaliveFields () bool {
162- return cc .DisableKeepAlives || cc .IdleConnTimeout != 0 || cc .MaxIdleConns != 0 || cc .MaxIdleConnsPerHost != 0
163- }
164-
165223// ToClientOption is an option to change the behavior of the HTTP client
166224// returned by ClientConfig.ToClient().
167225// There are currently no available options.
@@ -175,17 +233,8 @@ type ToClientOption interface {
175233// the `extensions` argument should be the output of `host.GetExtensions()`.
176234// It may also be `nil` in tests where no such extension is expected to be used.
177235func (cc * ClientConfig ) ToClient (ctx context.Context , extensions map [component.ID ]component.Component , settings component.TelemetrySettings , _ ... ToClientOption ) (* http.Client , error ) {
178- if cc .DisableKeepAlives {
179- settings .Logger .Warn ("'disable_keep_alives' is deprecated; set keepalive to null (keepalive: null) to disable keep-alives" )
180- }
181- if cc .IdleConnTimeout != 0 {
182- settings .Logger .Warn ("'idle_conn_timeout' is deprecated; use 'keepalive.idle_conn_timeout' instead" )
183- }
184- if cc .MaxIdleConns != 0 {
185- settings .Logger .Warn ("'max_idle_conns' is deprecated; use 'keepalive.max_idle_conns' instead" )
186- }
187- if cc .MaxIdleConnsPerHost != 0 {
188- settings .Logger .Warn ("'max_idle_conns_per_host' is deprecated; use 'keepalive.max_idle_conns_per_host' instead" )
236+ for _ , warning := range cc .deprecationWarnings {
237+ settings .Logger .Warn (warning )
189238 }
190239
191240 tlsCfg , err := cc .TLS .LoadTLSConfig (ctx )
@@ -203,27 +252,18 @@ func (cc *ClientConfig) ToClient(ctx context.Context, extensions map[component.I
203252 transport .WriteBufferSize = cc .WriteBufferSize
204253 }
205254
206- // Convert deprecated fields into the canonical Keepalive optional so the
207- // application logic below only has to deal with one struct.
208- if cc .DisableKeepAlives {
209- cc .Keepalive = configoptional .None [KeepaliveClientConfig ]()
210- } else if cc .hasDeprecatedKeepaliveFields () {
211- cc .Keepalive = configoptional .Some (KeepaliveClientConfig {
212- IdleConnTimeout : cc .IdleConnTimeout ,
213- MaxIdleConns : cc .MaxIdleConns ,
214- MaxIdleConnsPerHost : cc .MaxIdleConnsPerHost ,
215- })
216- }
217-
218- if cc .Keepalive .IsNone () {
219- transport .DisableKeepAlives = true
220- } else {
221- kaCfg := cc .Keepalive .GetOrInsertDefault ()
255+ if kaCfg := cc .Keepalive .Get (); kaCfg != nil {
222256 transport .MaxIdleConns = kaCfg .MaxIdleConns
223257 transport .MaxIdleConnsPerHost = kaCfg .MaxIdleConnsPerHost
224258 transport .IdleConnTimeout = kaCfg .IdleConnTimeout
259+ } else {
260+ // The 'keepalive' section is not in use; apply the deprecated flat
261+ // fields exactly as the code before the section's introduction did.
262+ transport .DisableKeepAlives = cc .DisableKeepAlives
263+ transport .MaxIdleConns = cc .MaxIdleConns
264+ transport .MaxIdleConnsPerHost = cc .MaxIdleConnsPerHost
265+ transport .IdleConnTimeout = cc .IdleConnTimeout
225266 }
226- // else Default: transport.Clone() already carries the right defaults (MaxIdleConns=100, IdleConnTimeout=90s).
227267 transport .MaxConnsPerHost = cc .MaxConnsPerHost
228268 transport .ForceAttemptHTTP2 = cc .ForceAttemptHTTP2
229269 // Setting the Proxy URL
0 commit comments