Skip to content

[configoptional] Extend Get() method with boolean #13177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions config/configoptional/optional.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"go.opentelemetry.io/collector/confmap"
)

var errOptionNoSuchElement = fmt.Errorf("no such element")

Check failure on line 15 in config/configoptional/optional.go

View workflow job for this annotation

GitHub Actions / CodeQL-Build

var errOptionNoSuchElement is unused (unused)

Check failure on line 15 in config/configoptional/optional.go

View workflow job for this annotation

GitHub Actions / lint

var errOptionNoSuchElement is unused (unused)

// Optional represents a value that may or may not be present.
// It supports two flavors for all types: Some(value) and None.
// It supports a third flavor for struct types: Default(defaultVal).
Expand All @@ -21,11 +23,14 @@
type Optional[T any] struct {
// value is the value of the Optional.
value T

// hasValue indicates if the Optional has a value.
hasValue bool
}

func empty[T any]() (t T) {
return
}

// deref a reflect.Type to its underlying type.
func deref(t reflect.Type) reflect.Type {
for t.Kind() == reflect.Ptr {
Expand Down Expand Up @@ -118,12 +123,20 @@
return o.hasValue
}

// Get returns the value of the Optional.
// If the value is not present, it returns nil.
func (o *Optional[T]) Get() *T {
// Get returns value and presence.
func (o *Optional[T]) Get() (T, bool) {
if !o.HasValue() {
return empty[T](), false
}
return o.value, true
}

// ToPointer returns value if present or a nil pointer.
func (o *Optional[T]) ToPointer() *T {
if !o.hasValue {
return nil
}

return &o.value
}

Expand Down
27 changes: 20 additions & 7 deletions config/configoptional/optional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package configoptional

import (
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -95,27 +96,39 @@ func TestEqualityDefault(t *testing.T) {
func TestNoneZeroVal(t *testing.T) {
var none Optional[Sub]
require.False(t, none.HasValue())
require.Nil(t, none.Get())
require.Nil(t, none.ToPointer())
}

func TestGetNonZeroSize(t *testing.T) {
var none Optional[Sub]
zeroVal, ok := none.Get()
require.False(t, ok)
require.Equal(t, reflect.TypeOf(Sub{}).Size(), reflect.TypeOf(zeroVal).Size())
var nonePointer Optional[*Sub]
zeroPointer, ok := nonePointer.Get()
require.False(t, ok)
require.Nil(t, zeroPointer)
require.Equal(t, reflect.TypeOf(&Sub{}).Size(), reflect.TypeOf(zeroPointer).Size())
}

func TestNone(t *testing.T) {
none := None[Sub]()
require.False(t, none.HasValue())
require.Nil(t, none.Get())
require.Nil(t, none.ToPointer())
}

func TestSome(t *testing.T) {
some := Some(Sub{
Foo: "foobar",
})
require.True(t, some.HasValue())
assert.Equal(t, "foobar", some.Get().Foo)
assert.Equal(t, "foobar", some.ToPointer().Foo)
}

func TestDefault(t *testing.T) {
defaultSub := Default(&subDefault)
require.False(t, defaultSub.HasValue())
require.Nil(t, defaultSub.Get())
require.Nil(t, defaultSub.ToPointer())
}

func TestUnmarshalOptional(t *testing.T) {
Expand Down Expand Up @@ -247,7 +260,7 @@ func TestUnmarshalOptional(t *testing.T) {
require.NoError(t, conf.Unmarshal(&cfg))
require.Equal(t, test.expectedSub, cfg.Sub1.HasValue())
if test.expectedSub {
require.Equal(t, test.expectedFoo, cfg.Sub1.Get().Foo)
require.Equal(t, test.expectedFoo, cfg.Sub1.ToPointer().Foo)
}
})
}
Expand All @@ -273,7 +286,7 @@ func TestUnmarshalConfigPointer(t *testing.T) {
err := cm.Unmarshal(&cfg)
require.NoError(t, err)
assert.True(t, cfg.Sub1.HasValue())
assert.Equal(t, "bar", (*cfg.Sub1.Get()).Foo)
assert.Equal(t, "bar", (*cfg.Sub1.ToPointer()).Foo)
}

func TestUnmarshalErr(t *testing.T) {
Expand Down Expand Up @@ -317,5 +330,5 @@ func TestSquashedOptional(t *testing.T) {
require.NoError(t, err)

assert.True(t, cfg.HasValue())
assert.Equal(t, 42, cfg.Get().Val)
assert.Equal(t, 42, cfg.ToPointer().Val)
}
13 changes: 5 additions & 8 deletions receiver/otlpreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@ import (

// GetOrInsertDefault is a helper function to get or insert a default value for a configoptional.Optional type.
func GetOrInsertDefault[T any](t *testing.T, opt *configoptional.Optional[T]) *T {
if opt.HasValue() {
return opt.Get()
if _, found := opt.Get(); !found {
empty := confmap.NewFromStringMap(map[string]any{})
require.NoError(t, empty.Unmarshal(opt))
}

empty := confmap.NewFromStringMap(map[string]any{})
require.NoError(t, empty.Unmarshal(opt))
val := opt.Get()
require.NotNil(t, "Expected a default value to be set for %T", val)
return val
require.NotNil(t, "Expected a default value to be set for %T", opt.ToPointer())
return opt.ToPointer()
}

func TestUnmarshalDefaultConfig(t *testing.T) {
Expand Down
154 changes: 75 additions & 79 deletions receiver/otlpreceiver/otlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,105 +87,101 @@ func newOtlpReceiver(cfg *Config, set *receiver.Settings) (*otlpReceiver, error)
}

func (r *otlpReceiver) startGRPCServer(host component.Host) error {
// If GRPC is not enabled, nothing to start.
if !r.cfg.GRPC.HasValue() {
return nil
}
if grpcCfg, found := r.cfg.GRPC.Get(); found {
var err error
if r.serverGRPC, err = grpcCfg.ToServer(context.Background(), host, r.settings.TelemetrySettings); err != nil {
return err
}

grpcCfg := r.cfg.GRPC.Get()
var err error
if r.serverGRPC, err = grpcCfg.ToServer(context.Background(), host, r.settings.TelemetrySettings); err != nil {
return err
}
if r.nextTraces != nil {
ptraceotlp.RegisterGRPCServer(r.serverGRPC, trace.New(r.nextTraces, r.obsrepGRPC))
}

if r.nextTraces != nil {
ptraceotlp.RegisterGRPCServer(r.serverGRPC, trace.New(r.nextTraces, r.obsrepGRPC))
}
if r.nextMetrics != nil {
pmetricotlp.RegisterGRPCServer(r.serverGRPC, metrics.New(r.nextMetrics, r.obsrepGRPC))
}

if r.nextMetrics != nil {
pmetricotlp.RegisterGRPCServer(r.serverGRPC, metrics.New(r.nextMetrics, r.obsrepGRPC))
}
if r.nextLogs != nil {
plogotlp.RegisterGRPCServer(r.serverGRPC, logs.New(r.nextLogs, r.obsrepGRPC))
}

if r.nextLogs != nil {
plogotlp.RegisterGRPCServer(r.serverGRPC, logs.New(r.nextLogs, r.obsrepGRPC))
}
if r.nextProfiles != nil {
pprofileotlp.RegisterGRPCServer(r.serverGRPC, profiles.New(r.nextProfiles))
}

if r.nextProfiles != nil {
pprofileotlp.RegisterGRPCServer(r.serverGRPC, profiles.New(r.nextProfiles))
}
r.settings.Logger.Info("Starting GRPC server", zap.String("endpoint", grpcCfg.NetAddr.Endpoint))
var gln net.Listener
if gln, err = grpcCfg.NetAddr.Listen(context.Background()); err != nil {
return err
}

r.settings.Logger.Info("Starting GRPC server", zap.String("endpoint", grpcCfg.NetAddr.Endpoint))
var gln net.Listener
if gln, err = grpcCfg.NetAddr.Listen(context.Background()); err != nil {
return err
}
r.shutdownWG.Add(1)
go func() {
defer r.shutdownWG.Done()

r.shutdownWG.Add(1)
go func() {
defer r.shutdownWG.Done()
if errGrpc := r.serverGRPC.Serve(gln); errGrpc != nil && !errors.Is(errGrpc, grpc.ErrServerStopped) {
componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errGrpc))
}
}()
}

if errGrpc := r.serverGRPC.Serve(gln); errGrpc != nil && !errors.Is(errGrpc, grpc.ErrServerStopped) {
componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errGrpc))
}
}()
// If GRPC is not enabled, nothing to start.
return nil
}

func (r *otlpReceiver) startHTTPServer(ctx context.Context, host component.Host) error {
// If HTTP is not enabled, nothing to start.
if !r.cfg.HTTP.HasValue() {
return nil
}
if httpCfg, found := r.cfg.HTTP.Get(); found {
httpMux := http.NewServeMux()
if r.nextTraces != nil {
httpTracesReceiver := trace.New(r.nextTraces, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.TracesURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleTraces(resp, req, httpTracesReceiver)
})
}

httpCfg := r.cfg.HTTP.Get()
httpMux := http.NewServeMux()
if r.nextTraces != nil {
httpTracesReceiver := trace.New(r.nextTraces, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.TracesURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleTraces(resp, req, httpTracesReceiver)
})
}
if r.nextMetrics != nil {
httpMetricsReceiver := metrics.New(r.nextMetrics, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.MetricsURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleMetrics(resp, req, httpMetricsReceiver)
})
}

if r.nextMetrics != nil {
httpMetricsReceiver := metrics.New(r.nextMetrics, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.MetricsURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleMetrics(resp, req, httpMetricsReceiver)
})
}
if r.nextLogs != nil {
httpLogsReceiver := logs.New(r.nextLogs, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.LogsURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleLogs(resp, req, httpLogsReceiver)
})
}

if r.nextLogs != nil {
httpLogsReceiver := logs.New(r.nextLogs, r.obsrepHTTP)
httpMux.HandleFunc(string(httpCfg.LogsURLPath), func(resp http.ResponseWriter, req *http.Request) {
handleLogs(resp, req, httpLogsReceiver)
})
}
if r.nextProfiles != nil {
httpProfilesReceiver := profiles.New(r.nextProfiles)
httpMux.HandleFunc(defaultProfilesURLPath, func(resp http.ResponseWriter, req *http.Request) {
handleProfiles(resp, req, httpProfilesReceiver)
})
}

if r.nextProfiles != nil {
httpProfilesReceiver := profiles.New(r.nextProfiles)
httpMux.HandleFunc(defaultProfilesURLPath, func(resp http.ResponseWriter, req *http.Request) {
handleProfiles(resp, req, httpProfilesReceiver)
})
}
var err error
if r.serverHTTP, err = httpCfg.ServerConfig.ToServer(ctx, host, r.settings.TelemetrySettings, httpMux, confighttp.WithErrorHandler(errorHandler)); err != nil {
return err
}

var err error
if r.serverHTTP, err = httpCfg.ServerConfig.ToServer(ctx, host, r.settings.TelemetrySettings, httpMux, confighttp.WithErrorHandler(errorHandler)); err != nil {
return err
}
r.settings.Logger.Info("Starting HTTP server", zap.String("endpoint", httpCfg.ServerConfig.Endpoint))
var hln net.Listener
if hln, err = httpCfg.ServerConfig.ToListener(ctx); err != nil {
return err
}

r.settings.Logger.Info("Starting HTTP server", zap.String("endpoint", httpCfg.ServerConfig.Endpoint))
var hln net.Listener
if hln, err = httpCfg.ServerConfig.ToListener(ctx); err != nil {
return err
}
r.shutdownWG.Add(1)
go func() {
defer r.shutdownWG.Done()

r.shutdownWG.Add(1)
go func() {
defer r.shutdownWG.Done()
if errHTTP := r.serverHTTP.Serve(hln); errHTTP != nil && !errors.Is(errHTTP, http.ErrServerClosed) {
componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errHTTP))
}
}()
}

if errHTTP := r.serverHTTP.Serve(hln); errHTTP != nil && !errors.Is(errHTTP, http.ErrServerClosed) {
componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errHTTP))
}
}()
// If HTTP is not enabled, nothing to start.
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion receiver/otlpreceiver/otlp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ func TestGRPCMaxRecvSize(t *testing.T) {
assert.NoError(t, cc.Close())
require.NoError(t, recv.Shutdown(context.Background()))

cfg.GRPC.Get().MaxRecvMsgSizeMiB = 100
cfg.GRPC.ToPointer().MaxRecvMsgSizeMiB = 100
recv = newReceiver(t, componenttest.NewNopTelemetrySettings(), cfg, otlpReceiverID, sink)
require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()))
t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) })
Expand Down
Loading