1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-03 18:35:08 +02:00

Implement the providerConfig (#5074)

* Implement the providerConfig

* Add test for NewLoggerProvider configuration

* Add TestLimitValueFailsOpen

* Fix merge
This commit is contained in:
Tyler Yahn
2024-03-15 10:24:32 -07:00
committed by GitHub
parent da047e70ef
commit 3a72c5ea94
2 changed files with 223 additions and 9 deletions
+97 -9
View File
@@ -5,22 +5,105 @@ package log // import "go.opentelemetry.io/otel/sdk/log"
import ( import (
"context" "context"
"fmt"
"os"
"strconv"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/embedded" "go.opentelemetry.io/otel/log/embedded"
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
) )
// Compile-time check LoggerProvider implements log.LoggerProvider. const (
var _ log.LoggerProvider = (*LoggerProvider)(nil) defaultAttrCntLim = 128
defaultAttrValLenLim = -1
envarAttrCntLim = "OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT"
envarAttrValLenLim = "OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT"
)
type providerConfig struct {
resource *resource.Resource
processors []Processor
attrCntLim limit
attrValLenLim limit
}
func newProviderConfig(opts []LoggerProviderOption) providerConfig {
var c providerConfig
for _, opt := range opts {
c = opt.apply(c)
}
if c.resource == nil {
c.resource = resource.Default()
}
c.attrCntLim = c.attrCntLim.Resolve(
envarAttrCntLim,
defaultAttrCntLim,
)
c.attrValLenLim = c.attrValLenLim.Resolve(
envarAttrValLenLim,
defaultAttrValLenLim,
)
return c
}
type limit struct {
value int
set bool
}
func newLimit(value int) limit {
return limit{value: value, set: true}
}
// Resolve returns the resolved form of the limit l. If l's value is set, it
// will return l. If the l's value is not set, a new limit based on the
// environment variable envar will be returned if that environment variable is
// set. Otherwise, fallback is used to construct a new limit that is returned.
func (l limit) Resolve(envar string, fallback int) limit {
if l.set {
return l
}
if v := os.Getenv(envar); v != "" {
n, err := strconv.Atoi(v)
if err == nil {
return newLimit(n)
}
otel.Handle(fmt.Errorf("invalid %s value %s: %w", envar, v, err))
}
return newLimit(fallback)
}
// Value returns the limit value if set. Otherwise, it returns -1.
func (l limit) Value() int {
if l.set {
return l.value
}
// Fail open, not closed (-1 == unlimited).
return -1
}
// LoggerProvider handles the creation and coordination of Loggers. All Loggers // LoggerProvider handles the creation and coordination of Loggers. All Loggers
// created by a LoggerProvider will be associated with the same Resource. // created by a LoggerProvider will be associated with the same Resource.
type LoggerProvider struct { type LoggerProvider struct {
embedded.LoggerProvider embedded.LoggerProvider
resource *resource.Resource
processors []Processor
attributeCountLimit int
attributeValueLengthLimit int
} }
type providerConfig struct{} // Compile-time check LoggerProvider implements log.LoggerProvider.
var _ log.LoggerProvider = (*LoggerProvider)(nil)
// NewLoggerProvider returns a new and configured LoggerProvider. // NewLoggerProvider returns a new and configured LoggerProvider.
// //
@@ -29,8 +112,13 @@ type providerConfig struct{}
// created. This means the returned LoggerProvider, one created with no // created. This means the returned LoggerProvider, one created with no
// Processors, will perform no operations. // Processors, will perform no operations.
func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProvider { func NewLoggerProvider(opts ...LoggerProviderOption) *LoggerProvider {
// TODO (#5060): Implement. cfg := newProviderConfig(opts)
return nil return &LoggerProvider{
resource: cfg.resource,
processors: cfg.processors,
attributeCountLimit: cfg.attrCntLim.Value(),
attributeValueLengthLimit: cfg.attrValLenLim.Value(),
}
} }
// Logger returns a new [log.Logger] with the provided name and configuration. // Logger returns a new [log.Logger] with the provided name and configuration.
@@ -76,7 +164,7 @@ func (fn loggerProviderOptionFunc) apply(c providerConfig) providerConfig {
// go.opentelemetry.io/otel/sdk/resource package will be used. // go.opentelemetry.io/otel/sdk/resource package will be used.
func WithResource(res *resource.Resource) LoggerProviderOption { func WithResource(res *resource.Resource) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig { return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
// TODO (#5060): Implement. cfg.resource = res
return cfg return cfg
}) })
} }
@@ -93,7 +181,7 @@ func WithResource(res *resource.Resource) LoggerProviderOption {
// For testing and debugging, use [NewSimpleProcessor] to synchronously export log records. // For testing and debugging, use [NewSimpleProcessor] to synchronously export log records.
func WithProcessor(processor Processor) LoggerProviderOption { func WithProcessor(processor Processor) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig { return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
// TODO (#5060): Implement. cfg.processors = append(cfg.processors, processor)
return cfg return cfg
}) })
} }
@@ -112,7 +200,7 @@ func WithProcessor(processor Processor) LoggerProviderOption {
// passed, 128 will be used. // passed, 128 will be used.
func WithAttributeCountLimit(limit int) LoggerProviderOption { func WithAttributeCountLimit(limit int) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig { return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
// TODO (#5060): Implement. cfg.attrCntLim = newLimit(limit)
return cfg return cfg
}) })
} }
@@ -131,7 +219,7 @@ func WithAttributeCountLimit(limit int) LoggerProviderOption {
// passed, no limit (-1) will be used. // passed, no limit (-1) will be used.
func WithAttributeValueLengthLimit(limit int) LoggerProviderOption { func WithAttributeValueLengthLimit(limit int) LoggerProviderOption {
return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig { return loggerProviderOptionFunc(func(cfg providerConfig) providerConfig {
// TODO (#5060): Implement. cfg.attrValLenLim = newLimit(limit)
return cfg return cfg
}) })
} }
+126
View File
@@ -0,0 +1,126 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package log // import "go.opentelemetry.io/otel/sdk/log"
import (
"context"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
)
type processor struct {
name string
}
func (processor) OnEmit(context.Context, Record) error { return nil }
func (processor) Enabled(context.Context, Record) bool { return true }
func (processor) Shutdown(context.Context) error { return nil }
func (processor) ForceFlush(context.Context) error { return nil }
func TestNewLoggerProviderConfiguration(t *testing.T) {
t.Cleanup(func(orig otel.ErrorHandler) func() {
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
t.Log(err)
}))
return func() { otel.SetErrorHandler(orig) }
}(otel.GetErrorHandler()))
res := resource.NewSchemaless(attribute.String("key", "value"))
p0, p1 := processor{name: "0"}, processor{name: "1"}
attrCntLim := 12
attrValLenLim := 21
testcases := []struct {
name string
envars map[string]string
options []LoggerProviderOption
want *LoggerProvider
}{
{
name: "Defaults",
want: &LoggerProvider{
resource: resource.Default(),
attributeCountLimit: defaultAttrCntLim,
attributeValueLengthLimit: defaultAttrValLenLim,
},
},
{
name: "Options",
options: []LoggerProviderOption{
WithResource(res),
WithProcessor(p0),
WithProcessor(p1),
WithAttributeCountLimit(attrCntLim),
WithAttributeValueLengthLimit(attrValLenLim),
},
want: &LoggerProvider{
resource: res,
processors: []Processor{p0, p1},
attributeCountLimit: attrCntLim,
attributeValueLengthLimit: attrValLenLim,
},
},
{
name: "Environment",
envars: map[string]string{
envarAttrCntLim: strconv.Itoa(attrCntLim),
envarAttrValLenLim: strconv.Itoa(attrValLenLim),
},
want: &LoggerProvider{
resource: resource.Default(),
attributeCountLimit: attrCntLim,
attributeValueLengthLimit: attrValLenLim,
},
},
{
name: "InvalidEnvironment",
envars: map[string]string{
envarAttrCntLim: "invalid attributeCountLimit",
envarAttrValLenLim: "invalid attributeValueLengthLimit",
},
want: &LoggerProvider{
resource: resource.Default(),
attributeCountLimit: defaultAttrCntLim,
attributeValueLengthLimit: defaultAttrValLenLim,
},
},
{
name: "Precedence",
envars: map[string]string{
envarAttrCntLim: strconv.Itoa(100),
envarAttrValLenLim: strconv.Itoa(101),
},
options: []LoggerProviderOption{
// These override the environment variables.
WithAttributeCountLimit(attrCntLim),
WithAttributeValueLengthLimit(attrValLenLim),
},
want: &LoggerProvider{
resource: resource.Default(),
attributeCountLimit: attrCntLim,
attributeValueLengthLimit: attrValLenLim,
},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
for key, value := range tc.envars {
t.Setenv(key, value)
}
assert.Equal(t, tc.want, NewLoggerProvider(tc.options...))
})
}
}
func TestLimitValueFailsOpen(t *testing.T) {
var l limit
assert.Equal(t, -1, l.Value(), "limit value should default to unlimited")
}