Avoid public APIs with internal params in custom Options (#11054)

Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
This commit is contained in:
Bogdan Drutu 2024-09-17 13:08:41 -07:00 committed by GitHub
parent d5215c559a
commit 8027d80aef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 211 additions and 91 deletions

View File

@ -0,0 +1,20 @@
# Use this changelog template to create an entry for release notes.
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
component: options
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Avoid using private types in public APIs and also protect options to be implemented outside this module.
# One or more tracking issues or pull requests related to the change
issues: [11054]
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [api]

View File

@ -381,25 +381,33 @@ type toServerOptions struct {
// ToServerOption is an option to change the behavior of the HTTP server
// returned by ServerConfig.ToServer().
type ToServerOption func(opts *toServerOptions)
type ToServerOption interface {
apply(*toServerOptions)
}
type toServerOptionFunc func(*toServerOptions)
func (of toServerOptionFunc) apply(e *toServerOptions) {
of(e)
}
// WithErrorHandler overrides the HTTP error handler that gets invoked
// when there is a failure inside httpContentDecompressor.
func WithErrorHandler(e func(w http.ResponseWriter, r *http.Request, errorMsg string, statusCode int)) ToServerOption {
return func(opts *toServerOptions) {
return toServerOptionFunc(func(opts *toServerOptions) {
opts.errHandler = e
}
})
}
// WithDecoder provides support for additional decoders to be configured
// by the caller.
func WithDecoder(key string, dec func(body io.ReadCloser) (io.ReadCloser, error)) ToServerOption {
return func(opts *toServerOptions) {
return toServerOptionFunc(func(opts *toServerOptions) {
if opts.decoders == nil {
opts.decoders = map[string]func(body io.ReadCloser) (io.ReadCloser, error){}
}
opts.decoders[key] = dec
}
})
}
// ToServer creates an http.Server from settings object.
@ -408,7 +416,7 @@ func (hss *ServerConfig) ToServer(_ context.Context, host component.Host, settin
serverOpts := &toServerOptions{}
for _, o := range opts {
o(serverOpts)
o.apply(serverOpts)
}
if hss.MaxRequestBodySize <= 0 {

View File

@ -112,21 +112,29 @@ type retrievedSettings struct {
}
// RetrievedOption options to customize Retrieved values.
type RetrievedOption func(*retrievedSettings)
type RetrievedOption interface {
apply(*retrievedSettings)
}
type retrievedOptionFunc func(*retrievedSettings)
func (of retrievedOptionFunc) apply(e *retrievedSettings) {
of(e)
}
// WithRetrievedClose overrides the default Retrieved.Close function.
// The default Retrieved.Close function does nothing and always returns nil.
func WithRetrievedClose(closeFunc CloseFunc) RetrievedOption {
return func(settings *retrievedSettings) {
return retrievedOptionFunc(func(settings *retrievedSettings) {
settings.closeFunc = closeFunc
}
})
}
func withStringRepresentation(stringRepresentation string) RetrievedOption {
return func(settings *retrievedSettings) {
return retrievedOptionFunc(func(settings *retrievedSettings) {
settings.stringRepresentation = stringRepresentation
settings.isSetString = true
}
})
}
// NewRetrievedFromYAML returns a new Retrieved instance that contains the deserialized data from the yaml bytes.
@ -162,7 +170,7 @@ func NewRetrieved(rawConf any, opts ...RetrievedOption) (*Retrieved, error) {
}
set := retrievedSettings{}
for _, opt := range opts {
opt(&set)
opt.apply(&set)
}
return &Retrieved{
rawConf: rawConf,

View File

@ -20,7 +20,7 @@ type Option = internal.Option
// WithCapabilities overrides the default GetCapabilities function for a processor.
// The default GetCapabilities function returns mutable capabilities.
func WithCapabilities(capabilities Capabilities) Option {
return func(o *internal.BaseImpl) {
return internal.OptionFunc(func(o *internal.BaseImpl) {
o.Cap = capabilities
}
})
}

View File

@ -22,7 +22,15 @@ type BaseImpl struct {
}
// Option to construct new consumers.
type Option func(*BaseImpl)
type Option interface {
apply(*BaseImpl)
}
type OptionFunc func(*BaseImpl)
func (of OptionFunc) apply(e *BaseImpl) {
of(e)
}
// Capabilities returns the capabilities of the component
func (bs BaseImpl) Capabilities() Capabilities {
@ -35,7 +43,7 @@ func NewBaseImpl(options ...Option) *BaseImpl {
}
for _, op := range options {
op(bs)
op.apply(bs)
}
return bs

View File

@ -44,53 +44,61 @@ func (b *baseRequestSender) setNextSender(nextSender requestSender) {
type obsrepSenderFactory func(obsrep *obsReport) requestSender
// Option apply changes to baseExporter.
type Option func(*baseExporter) error
type Option interface {
apply(*baseExporter) error
}
type optionFunc func(*baseExporter) error
func (of optionFunc) apply(e *baseExporter) error {
return of(e)
}
// WithStart overrides the default Start function for an exporter.
// The default start function does nothing and always returns nil.
func WithStart(start component.StartFunc) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.StartFunc = start
return nil
}
})
}
// WithShutdown overrides the default Shutdown function for an exporter.
// The default shutdown function does nothing and always returns nil.
func WithShutdown(shutdown component.ShutdownFunc) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.ShutdownFunc = shutdown
return nil
}
})
}
// WithTimeout overrides the default TimeoutConfig for an exporter.
// The default TimeoutConfig is 5 seconds.
// WithTimeout overrides the default TimeoutSettings for an exporter.
// The default TimeoutSettings is 5 seconds.
func WithTimeout(timeoutConfig TimeoutConfig) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.timeoutSender.cfg = timeoutConfig
return nil
}
})
}
// WithRetry overrides the default configretry.BackOffConfig for an exporter.
// The default configretry.BackOffConfig is to disable retries.
func WithRetry(config configretry.BackOffConfig) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
if !config.Enabled {
o.exportFailureMessage += " Try enabling retry_on_failure config option to retry on retryable errors."
return nil
}
o.retrySender = newRetrySender(config, o.set)
return nil
}
})
}
// WithQueue overrides the default QueueConfig for an exporter.
// The default QueueConfig is to disable queueing.
// This option cannot be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter.
func WithQueue(config QueueConfig) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
if o.marshaler == nil || o.unmarshaler == nil {
return fmt.Errorf("WithQueue option is not available for the new request exporters, use WithRequestQueue instead")
}
@ -112,7 +120,7 @@ func WithQueue(config QueueConfig) Option {
})
o.queueSender = newQueueSender(q, o.set, config.NumConsumers, o.exportFailureMessage, o.obsrep)
return nil
}
})
}
// WithRequestQueue enables queueing for an exporter.
@ -120,7 +128,7 @@ func WithQueue(config QueueConfig) Option {
// Experimental: This API is at the early stage of development and may change without backward compatibility
// until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved.
func WithRequestQueue(cfg exporterqueue.Config, queueFactory exporterqueue.Factory[Request]) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
if o.marshaler != nil || o.unmarshaler != nil {
return fmt.Errorf("WithRequestQueue option must be used with the new request exporters only, use WithQueue instead")
}
@ -131,25 +139,33 @@ func WithRequestQueue(cfg exporterqueue.Config, queueFactory exporterqueue.Facto
o.queueCfg = cfg
o.queueFactory = queueFactory
return nil
}
})
}
// WithCapabilities overrides the default Capabilities() function for a Consumer.
// The default is non-mutable data.
// TODO: Verify if we can change the default to be mutable as we do for processors.
func WithCapabilities(capabilities consumer.Capabilities) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.consumerOptions = append(o.consumerOptions, consumer.WithCapabilities(capabilities))
return nil
}
})
}
// BatcherOption apply changes to batcher sender.
type BatcherOption func(*batchSender) error
type BatcherOption interface {
apply(*batchSender) error
}
type batcherOptionFunc func(*batchSender) error
func (of batcherOptionFunc) apply(e *batchSender) error {
return of(e)
}
// WithRequestBatchFuncs sets the functions for merging and splitting batches for an exporter built for custom request types.
func WithRequestBatchFuncs(mf exporterbatcher.BatchMergeFunc[Request], msf exporterbatcher.BatchMergeSplitFunc[Request]) BatcherOption {
return func(bs *batchSender) error {
return batcherOptionFunc(func(bs *batchSender) error {
if mf == nil || msf == nil {
return fmt.Errorf("WithRequestBatchFuncs must be provided with non-nil functions")
}
@ -159,7 +175,7 @@ func WithRequestBatchFuncs(mf exporterbatcher.BatchMergeFunc[Request], msf expor
bs.mergeFunc = mf
bs.mergeSplitFunc = msf
return nil
}
})
}
// WithBatcher enables batching for an exporter based on custom request types.
@ -168,39 +184,51 @@ func WithRequestBatchFuncs(mf exporterbatcher.BatchMergeFunc[Request], msf expor
// This API is at the early stage of development and may change without backward compatibility
// until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved.
func WithBatcher(cfg exporterbatcher.Config, opts ...BatcherOption) Option {
return func(o *baseExporter) error {
o.batcherCfg = cfg
o.batcherOpts = opts
return optionFunc(func(o *baseExporter) error {
if !cfg.Enabled {
return nil
}
bs := newBatchSender(cfg, o.set, o.batchMergeFunc, o.batchMergeSplitfunc)
for _, opt := range opts {
if err := opt.apply(bs); err != nil {
return err
}
}
if bs.mergeFunc == nil || bs.mergeSplitFunc == nil {
return fmt.Errorf("WithRequestBatchFuncs must be provided for the batcher applied to the request-based exporters")
}
o.batchSender = bs
return nil
}
})
}
// withMarshaler is used to set the request marshaler for the new exporter helper.
// It must be provided as the first option when creating a new exporter helper.
func withMarshaler(marshaler exporterqueue.Marshaler[Request]) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.marshaler = marshaler
return nil
}
})
}
// withUnmarshaler is used to set the request unmarshaler for the new exporter helper.
// It must be provided as the first option when creating a new exporter helper.
func withUnmarshaler(unmarshaler exporterqueue.Unmarshaler[Request]) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.unmarshaler = unmarshaler
return nil
}
})
}
// withBatchFuncs is used to set the functions for merging and splitting batches for OLTP-based exporters.
// It must be provided as the first option when creating a new exporter helper.
func withBatchFuncs(mf exporterbatcher.BatchMergeFunc[Request], msf exporterbatcher.BatchMergeSplitFunc[Request]) Option {
return func(o *baseExporter) error {
return optionFunc(func(o *baseExporter) error {
o.batchMergeFunc = mf
o.batchMergeSplitfunc = msf
return nil
}
})
}
// baseExporter contains common fields between different exporter types.
@ -259,7 +287,7 @@ func newBaseExporter(set exporter.Settings, signal component.DataType, osf obsre
}
for _, op := range options {
err = multierr.Append(err, op(be))
err = multierr.Append(err, op.apply(be))
}
if err != nil {
return nil, err
@ -268,7 +296,7 @@ func newBaseExporter(set exporter.Settings, signal component.DataType, osf obsre
if be.batcherCfg.Enabled {
bs := newBatchSender(be.batcherCfg, be.set, be.batchMergeFunc, be.batchMergeSplitfunc)
for _, opt := range be.batcherOpts {
err = multierr.Append(err, opt(bs))
err = multierr.Append(err, opt.apply(bs))
}
if bs.mergeFunc == nil || bs.mergeSplitFunc == nil {
err = multierr.Append(err, fmt.Errorf("WithRequestBatchFuncs must be provided for the batcher applied to the request-based exporters"))
@ -283,7 +311,7 @@ func newBaseExporter(set exporter.Settings, signal component.DataType, osf obsre
}
be.queueSender = newQueueSender(be.queueFactory(context.Background(), set, be.queueCfg), be.set, be.queueCfg.NumConsumers, be.exportFailureMessage, be.obsrep)
for _, op := range options {
err = multierr.Append(err, op(be))
err = multierr.Append(err, op.apply(be))
}
}

View File

@ -26,7 +26,15 @@ type Client interface {
}
// ClientOption represents the possible options for NewClient.
type ClientOption func(*defaultClient)
type ClientOption interface {
apply(*defaultClient)
}
type clientOptionFunc func(*defaultClient)
func (of clientOptionFunc) apply(e *defaultClient) {
of(e)
}
// ClientRoundTripperFunc specifies the function that returns a RoundTripper that can be used to authenticate HTTP requests.
type ClientRoundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error)
@ -58,33 +66,33 @@ type defaultClient struct {
// WithClientStart overrides the default `Start` function for a component.Component.
// The default always returns nil.
func WithClientStart(startFunc component.StartFunc) ClientOption {
return func(o *defaultClient) {
return clientOptionFunc(func(o *defaultClient) {
o.StartFunc = startFunc
}
})
}
// WithClientShutdown overrides the default `Shutdown` function for a component.Component.
// The default always returns nil.
func WithClientShutdown(shutdownFunc component.ShutdownFunc) ClientOption {
return func(o *defaultClient) {
return clientOptionFunc(func(o *defaultClient) {
o.ShutdownFunc = shutdownFunc
}
})
}
// WithClientRoundTripper provides a `RoundTripper` function for this client authenticator.
// The default round tripper is no-op.
func WithClientRoundTripper(roundTripperFunc ClientRoundTripperFunc) ClientOption {
return func(o *defaultClient) {
return clientOptionFunc(func(o *defaultClient) {
o.ClientRoundTripperFunc = roundTripperFunc
}
})
}
// WithClientPerRPCCredentials provides a `PerRPCCredentials` function for this client authenticator.
// There's no default.
func WithClientPerRPCCredentials(perRPCCredentialsFunc ClientPerRPCCredentialsFunc) ClientOption {
return func(o *defaultClient) {
return clientOptionFunc(func(o *defaultClient) {
o.ClientPerRPCCredentialsFunc = perRPCCredentialsFunc
}
})
}
// NewClient returns a Client configured with the provided options.
@ -92,7 +100,7 @@ func NewClient(options ...ClientOption) Client {
bc := &defaultClient{}
for _, op := range options {
op(bc)
op.apply(bc)
}
return bc

View File

@ -36,7 +36,15 @@ type defaultServer struct {
}
// ServerOption represents the possible options for NewServer.
type ServerOption func(*defaultServer)
type ServerOption interface {
apply(*defaultServer)
}
type serverOptionFunc func(*defaultServer)
func (of serverOptionFunc) apply(e *defaultServer) {
of(e)
}
// ServerAuthenticateFunc defines the signature for the function responsible for performing the authentication based
// on the given sources map. See Server.Authenticate.
@ -51,25 +59,25 @@ func (f ServerAuthenticateFunc) Authenticate(ctx context.Context, sources map[st
// WithServerAuthenticate specifies which function to use to perform the authentication.
func WithServerAuthenticate(authFunc ServerAuthenticateFunc) ServerOption {
return func(o *defaultServer) {
return serverOptionFunc(func(o *defaultServer) {
o.ServerAuthenticateFunc = authFunc
}
})
}
// WithServerStart overrides the default `Start` function for a component.Component.
// The default always returns nil.
func WithServerStart(startFunc component.StartFunc) ServerOption {
return func(o *defaultServer) {
return serverOptionFunc(func(o *defaultServer) {
o.StartFunc = startFunc
}
})
}
// WithServerShutdown overrides the default `Shutdown` function for a component.Component.
// The default always returns nil.
func WithServerShutdown(shutdownFunc component.ShutdownFunc) ServerOption {
return func(o *defaultServer) {
return serverOptionFunc(func(o *defaultServer) {
o.ShutdownFunc = shutdownFunc
}
})
}
// NewServer returns a Server configured with the provided options.
@ -77,7 +85,7 @@ func NewServer(options ...ServerOption) Server {
bc := &defaultServer{}
for _, op := range options {
op(bc)
op.apply(bc)
}
return bc

View File

@ -22,30 +22,38 @@ import (
var ErrSkipProcessingData = errors.New("sentinel error to skip processing data from the remainder of the pipeline")
// Option apply changes to internalOptions.
type Option func(*baseSettings)
type Option interface {
apply(*baseSettings)
}
type optionFunc func(*baseSettings)
func (of optionFunc) apply(e *baseSettings) {
of(e)
}
// WithStart overrides the default Start function for an processor.
// The default shutdown function does nothing and always returns nil.
func WithStart(start component.StartFunc) Option {
return func(o *baseSettings) {
return optionFunc(func(o *baseSettings) {
o.StartFunc = start
}
})
}
// WithShutdown overrides the default Shutdown function for an processor.
// The default shutdown function does nothing and always returns nil.
func WithShutdown(shutdown component.ShutdownFunc) Option {
return func(o *baseSettings) {
return optionFunc(func(o *baseSettings) {
o.ShutdownFunc = shutdown
}
})
}
// WithCapabilities overrides the default GetCapabilities function for an processor.
// The default GetCapabilities function returns mutable capabilities.
func WithCapabilities(capabilities consumer.Capabilities) Option {
return func(o *baseSettings) {
return optionFunc(func(o *baseSettings) {
o.consumerOptions = append(o.consumerOptions, consumer.WithCapabilities(capabilities))
}
})
}
type baseSettings struct {
@ -62,7 +70,7 @@ func fromOptions(options []Option) *baseSettings {
}
for _, op := range options {
op(opts)
op.apply(opts)
}
return opts

View File

@ -30,20 +30,28 @@ type Scraper interface {
}
// ScraperOption apply changes to internal options.
type ScraperOption func(*baseScraper)
type ScraperOption interface {
apply(*baseScraper)
}
type scraperOptionFunc func(*baseScraper)
func (of scraperOptionFunc) apply(e *baseScraper) {
of(e)
}
// WithStart sets the function that will be called on startup.
func WithStart(start component.StartFunc) ScraperOption {
return func(o *baseScraper) {
return scraperOptionFunc(func(o *baseScraper) {
o.StartFunc = start
}
})
}
// WithShutdown sets the function that will be called on shutdown.
func WithShutdown(shutdown component.ShutdownFunc) ScraperOption {
return func(o *baseScraper) {
return scraperOptionFunc(func(o *baseScraper) {
o.ShutdownFunc = shutdown
}
})
}
var _ Scraper = (*baseScraper)(nil)
@ -70,7 +78,7 @@ func NewScraper(t component.Type, scrape ScrapeFunc, options ...ScraperOption) (
id: component.NewID(t),
}
for _, op := range options {
op(bs)
op.apply(bs)
}
return bs, nil

View File

@ -20,7 +20,15 @@ import (
)
// ScraperControllerOption apply changes to internal options.
type ScraperControllerOption func(*controller)
type ScraperControllerOption interface {
apply(*controller)
}
type scraperControllerOptionFunc func(*controller)
func (of scraperControllerOptionFunc) apply(e *controller) {
of(e)
}
// AddScraper configures the provided scrape function to be called
// with the specified options, and at the specified collection interval.
@ -28,18 +36,18 @@ type ScraperControllerOption func(*controller)
// Observability information will be reported, and the scraped metrics
// will be passed to the next consumer.
func AddScraper(scraper Scraper) ScraperControllerOption {
return func(o *controller) {
return scraperControllerOptionFunc(func(o *controller) {
o.scrapers = append(o.scrapers, scraper)
}
})
}
// WithTickerChannel allows you to override the scraper controller's ticker
// channel to specify when scrape is called. This is only expected to be
// used by tests.
func WithTickerChannel(tickerCh <-chan time.Time) ScraperControllerOption {
return func(o *controller) {
return scraperControllerOptionFunc(func(o *controller) {
o.tickerCh = tickerCh
}
})
}
type controller struct {
@ -98,7 +106,7 @@ func NewScraperControllerReceiver(
}
for _, op := range options {
op(sc)
op.apply(sc)
}
sc.obsScrapers = make([]*obsReport, len(sc.scrapers))

View File

@ -178,12 +178,20 @@ type Settings struct {
Extensions builders.Extension
}
type Option func(*Extensions)
type Option interface {
apply(*Extensions)
}
type optionFunc func(*Extensions)
func (of optionFunc) apply(e *Extensions) {
of(e)
}
func WithReporter(reporter status.Reporter) Option {
return func(e *Extensions) {
return optionFunc(func(e *Extensions) {
e.reporter = reporter
}
})
}
// New creates a new Extensions from Config.
@ -197,7 +205,7 @@ func New(ctx context.Context, set Settings, cfg Config, options ...Option) (*Ext
}
for _, opt := range options {
opt(exts)
opt.apply(exts)
}
for _, extID := range cfg {