Skip to content

Commit

Permalink
config: add support for logger provider configuration (#5427)
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
  • Loading branch information
codeboten and MrAlias authored Jun 17, 2024
1 parent e5130d2 commit 2e08706
Show file tree
Hide file tree
Showing 9 changed files with 555 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The gRPC trace `Filter` for interceptor is renamed to `InterceptorFilter`. (#5196)
- The gRPC trace filter functions `Any`, `All`, `None`, `Not`, `MethodName`, `MethodPrefix`, `FullMethodName`, `ServiceName`, `ServicePrefix` and `HealthCheck` for interceptor are moved to `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/filters/interceptor`.
With this change, the filters in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` are now working for stats handler. (#5196)
- `NewSDK` in `go.opentelemetry.io/contrib/config` now returns a configured SDK with a valid `LoggerProvider`. (#5427)

- `NewLogger` now accepts a `name` `string` as the first argument.
This parameter is used as a replacement of `WithInstrumentationScope` to specify the name of the logger backing the underlying `Handler`. (#5588)
Expand Down
16 changes: 14 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"errors"

"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
)
Expand Down Expand Up @@ -35,6 +36,7 @@ func noopShutdown(context.Context) error {
type SDK struct {
meterProvider metric.MeterProvider
tracerProvider trace.TracerProvider
loggerProvider log.LoggerProvider
shutdown shutdownFunc
}

Expand All @@ -48,6 +50,11 @@ func (s *SDK) MeterProvider() metric.MeterProvider {
return s.meterProvider
}

// LoggerProvider returns a configured log.LoggerProvider.
func (s *SDK) LoggerProvider() log.LoggerProvider {
return s.loggerProvider
}

// Shutdown calls shutdown on all configured providers.
func (s *SDK) Shutdown(ctx context.Context) error {
return s.shutdown(ctx)
Expand Down Expand Up @@ -77,12 +84,17 @@ func NewSDK(opts ...ConfigurationOption) (SDK, error) {
return SDK{}, err
}

lp, lpShutdown, err := loggerProvider(o, r)
if err != nil {
return SDK{}, err
}

return SDK{
meterProvider: mp,
tracerProvider: tp,
loggerProvider: lp,
shutdown: func(ctx context.Context) error {
err := mpShutdown(ctx)
return errors.Join(err, tpShutdown(ctx))
return errors.Join(mpShutdown(ctx), tpShutdown(ctx), lpShutdown(ctx))
},
}, nil
}
Expand Down
7 changes: 7 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

lognoop "go.opentelemetry.io/otel/log/noop"
metricnoop "go.opentelemetry.io/otel/metric/noop"
sdklog "go.opentelemetry.io/otel/sdk/log"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
tracenoop "go.opentelemetry.io/otel/trace/noop"
Expand All @@ -22,13 +24,15 @@ func TestNewSDK(t *testing.T) {
cfg []ConfigurationOption
wantTracerProvider any
wantMeterProvider any
wantLoggerProvider any
wantErr error
wantShutdownErr error
}{
{
name: "no-configuration",
wantTracerProvider: tracenoop.NewTracerProvider(),
wantMeterProvider: metricnoop.NewMeterProvider(),
wantLoggerProvider: lognoop.NewLoggerProvider(),
},
{
name: "with-configuration",
Expand All @@ -37,17 +41,20 @@ func TestNewSDK(t *testing.T) {
WithOpenTelemetryConfiguration(OpenTelemetryConfiguration{
TracerProvider: &TracerProvider{},
MeterProvider: &MeterProvider{},
LoggerProvider: &LoggerProvider{},
}),
},
wantTracerProvider: &sdktrace.TracerProvider{},
wantMeterProvider: &sdkmetric.MeterProvider{},
wantLoggerProvider: &sdklog.LoggerProvider{},
},
}
for _, tt := range tests {
sdk, err := NewSDK(tt.cfg...)
require.Equal(t, tt.wantErr, err)
assert.IsType(t, tt.wantTracerProvider, sdk.TracerProvider())
assert.IsType(t, tt.wantMeterProvider, sdk.MeterProvider())
assert.IsType(t, tt.wantLoggerProvider, sdk.LoggerProvider())
require.Equal(t, tt.wantShutdownErr, sdk.Shutdown(context.Background()))
}
}
Expand Down
3 changes: 3 additions & 0 deletions config/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ require (
github.com/prometheus/client_golang v1.19.1
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel v1.27.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0
go.opentelemetry.io/otel/exporters/prometheus v0.49.0
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.27.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0
go.opentelemetry.io/otel/log v0.3.0
go.opentelemetry.io/otel/metric v1.27.0
go.opentelemetry.io/otel/sdk v1.27.0
go.opentelemetry.io/otel/sdk/log v0.3.0
go.opentelemetry.io/otel/sdk/metric v1.27.0
go.opentelemetry.io/otel/trace v1.27.0
)
Expand Down
6 changes: 6 additions & 0 deletions config/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 h1:ccBrA8nCY5mM0y5uO7FT0ze4S0TuFcWdDB2FxGMTjkI=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0/go.mod h1:/9pb6634zi2Lk8LYg9Q0X8Ar6jka4dkFOylBLbVQPCE=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0 h1:bFgvUr3/O4PHj3VQcFEuYKvRZJX1SJDQ+11JXuSB3/w=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.27.0/go.mod h1:xJntEd2KL6Qdg5lwp97HMLQDVeAhrYxmzFseAMDPQ8I=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.27.0 h1:CIHWikMsN3wO+wq1Tp5VGdVRTcON+DmOJSfDjXypKOc=
Expand All @@ -51,10 +53,14 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.27.0 h1:/jlt1Y8gXWiHG9
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.27.0/go.mod h1:bmToOGOBZ4hA9ghphIc1PAf66VA8KOtsuy3+ScStG20=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0 h1:/0YaXu3755A/cFbtXp+21lkXgI0QE5avTWA2HjU9/WE=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0/go.mod h1:m7SFxp0/7IxmJPLIY3JhOcU9CoFzDaCPL6xxQIxhA+o=
go.opentelemetry.io/otel/log v0.3.0 h1:kJRFkpUFYtny37NQzL386WbznUByZx186DpEMKhEGZs=
go.opentelemetry.io/otel/log v0.3.0/go.mod h1:ziCwqZr9soYDwGNbIL+6kAvQC+ANvjgG367HVcyR/ys=
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI=
go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A=
go.opentelemetry.io/otel/sdk/log v0.3.0 h1:GEjJ8iftz2l+XO1GF2856r7yYVh74URiF9JMcAacr5U=
go.opentelemetry.io/otel/sdk/log v0.3.0/go.mod h1:BwCxtmux6ACLuys1wlbc0+vGBd+xytjmjajwqqIul2g=
go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI=
go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw=
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
Expand Down
144 changes: 144 additions & 0 deletions config/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package config // import "go.opentelemetry.io/contrib/config"

import (
"context"
"errors"
"fmt"
"net/url"
"time"

"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/noop"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
)

func loggerProvider(cfg configOptions, res *resource.Resource) (log.LoggerProvider, shutdownFunc, error) {
if cfg.opentelemetryConfig.LoggerProvider == nil {
return noop.NewLoggerProvider(), noopShutdown, nil
}
opts := []sdklog.LoggerProviderOption{
sdklog.WithResource(res),
}
var errs []error
for _, processor := range cfg.opentelemetryConfig.LoggerProvider.Processors {
sp, err := logProcessor(cfg.ctx, processor)
if err == nil {
opts = append(opts, sdklog.WithProcessor(sp))
} else {
errs = append(errs, err)
}
}

if len(errs) > 0 {
return noop.NewLoggerProvider(), noopShutdown, errors.Join(errs...)
}

lp := sdklog.NewLoggerProvider(opts...)
return lp, lp.Shutdown, nil
}

func logProcessor(ctx context.Context, processor LogRecordProcessor) (sdklog.Processor, error) {
if processor.Batch != nil && processor.Simple != nil {
return nil, errors.New("must not specify multiple log processor type")
}
if processor.Batch != nil {
exp, err := logExporter(ctx, processor.Batch.Exporter)
if err != nil {
return nil, err
}
return batchLogProcessor(processor.Batch, exp)
}
if processor.Simple != nil {
exp, err := logExporter(ctx, processor.Simple.Exporter)
if err != nil {
return nil, err
}
return sdklog.NewSimpleProcessor(exp), nil
}
return nil, fmt.Errorf("unsupported log processor type, must be one of simple or batch")
}

func logExporter(ctx context.Context, exporter LogRecordExporter) (sdklog.Exporter, error) {
if exporter.OTLP != nil {
switch exporter.OTLP.Protocol {
case protocolProtobufHTTP:
return otlpHTTPLogExporter(ctx, exporter.OTLP)
default:
return nil, fmt.Errorf("unsupported protocol %q", exporter.OTLP.Protocol)
}
}
return nil, errors.New("no valid log exporter")
}

func batchLogProcessor(blp *BatchLogRecordProcessor, exp sdklog.Exporter) (*sdklog.BatchProcessor, error) {
var opts []sdklog.BatchProcessorOption
if blp.ExportTimeout != nil {
if *blp.ExportTimeout < 0 {
return nil, fmt.Errorf("invalid export timeout %d", *blp.ExportTimeout)
}
opts = append(opts, sdklog.WithExportTimeout(time.Millisecond*time.Duration(*blp.ExportTimeout)))
}
if blp.MaxExportBatchSize != nil {
if *blp.MaxExportBatchSize < 0 {
return nil, fmt.Errorf("invalid batch size %d", *blp.MaxExportBatchSize)
}
opts = append(opts, sdklog.WithExportMaxBatchSize(*blp.MaxExportBatchSize))
}
if blp.MaxQueueSize != nil {
if *blp.MaxQueueSize < 0 {
return nil, fmt.Errorf("invalid queue size %d", *blp.MaxQueueSize)
}
opts = append(opts, sdklog.WithMaxQueueSize(*blp.MaxQueueSize))
}

if blp.ScheduleDelay != nil {
if *blp.ScheduleDelay < 0 {
return nil, fmt.Errorf("invalid schedule delay %d", *blp.ScheduleDelay)
}
opts = append(opts, sdklog.WithExportInterval(time.Millisecond*time.Duration(*blp.ScheduleDelay)))
}

return sdklog.NewBatchProcessor(exp, opts...), nil
}

func otlpHTTPLogExporter(ctx context.Context, otlpConfig *OTLP) (sdklog.Exporter, error) {
var opts []otlploghttp.Option

if len(otlpConfig.Endpoint) > 0 {
u, err := url.ParseRequestURI(otlpConfig.Endpoint)
if err != nil {
return nil, err
}
opts = append(opts, otlploghttp.WithEndpoint(u.Host))

if u.Scheme == "http" {
opts = append(opts, otlploghttp.WithInsecure())
}
if len(u.Path) > 0 {
opts = append(opts, otlploghttp.WithURLPath(u.Path))
}
}
if otlpConfig.Compression != nil {
switch *otlpConfig.Compression {
case compressionGzip:
opts = append(opts, otlploghttp.WithCompression(otlploghttp.GzipCompression))
case compressionNone:
opts = append(opts, otlploghttp.WithCompression(otlploghttp.NoCompression))
default:
return nil, fmt.Errorf("unsupported compression %q", *otlpConfig.Compression)
}
}
if otlpConfig.Timeout != nil && *otlpConfig.Timeout > 0 {
opts = append(opts, otlploghttp.WithTimeout(time.Millisecond*time.Duration(*otlpConfig.Timeout)))
}
if len(otlpConfig.Headers) > 0 {
opts = append(opts, otlploghttp.WithHeaders(otlpConfig.Headers))
}

return otlploghttp.New(ctx, opts...)
}
Loading

0 comments on commit 2e08706

Please sign in to comment.