Skip to content

Commit 33215dc

Browse files
committed
Use a combination of Unmarshal and ToClient/Server
1 parent 2f59992 commit 33215dc

8 files changed

Lines changed: 424 additions & 203 deletions

File tree

.chloggen/feat_confighttp_config-optional.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ subtext: |
2020
- `idle_conn_timeout` -> `keepalive::idle_conn_timeout`
2121
- `max_idle_conns` -> `keepalive::max_idle_conns`
2222
- `max_idle_conns_per_host` -> `keepalive::max_idle_conns_per_host`
23-
- `disable_keep_alives` -> omit the `keepalive` section entirely
23+
- `disable_keep_alives: true` -> `keepalive::enabled: false`
2424
The following server configuration fields are deprecated in favor of the `keepalive` section:
2525
- `idle_timeout` -> `keepalive::idle_timeout`
26-
- `keep_alives_enabled: false` -> omit the `keepalive` section entirely
27-
A deprecation warning is emitted on the first `ToClient`/`ToServer` call when deprecated fields
28-
are present. Using deprecated fields together with the new `keepalive` section is an error.
26+
- `keep_alives_enabled: false` -> `keepalive::enabled: false`
27+
Deprecated fields set in the configuration keep working exactly as before and produce a
28+
deprecation warning when the client or server is created. Setting deprecated fields together
29+
with the new `keepalive` section is an error.
2930
3031
# Optional: The change log or logs in which this entry should be included.
3132
# e.g. '[user]' or '[user, api]'

config/confighttp/client.go

Lines changed: 77 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3031
const (
@@ -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+
149214
func (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.
177235
func (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

Comments
 (0)