Skip to content
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

otelzap: Add skeleton and config options #5449

Merged
merged 19 commits into from
May 8, 2024
Merged
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
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ updates:
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /bridges/otelzap
labels:
- dependencies
- go
- Skip Changelog
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /bridges/prometheus
labels:
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CODEOWNERS @MrAlias @MadVikingGod @pellared @dashpole

bridges/otelslog @open-telemetry/go-approvers @MrAlias @pellared
bridges/prometheus/ @open-telemetry/go-approvers @dashpole
bridges/otelzap/ @open-telemetry/go-approvers @pellared @khushijain21

config/ @open-telemetry/go-approvers @MadVikingGod @pellared @codeboten

Expand Down
136 changes: 136 additions & 0 deletions bridges/otelzap/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// Package otelzap provides a bridge between the [go.uber.org/zap] and
// OpenTelemetry logging.
package otelzap // import "go.opentelemetry.io/contrib/bridges/otelzap"

import (
"go.uber.org/zap/zapcore"

"go.opentelemetry.io/otel/log"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/sdk/instrumentation"
)

const (
bridgeName = "go.opentelemetry.io/contrib/bridges/otelzap"
)

type config struct {
provider log.LoggerProvider
scope instrumentation.Scope
}

func newConfig(options []Option) config {
var c config
for _, opt := range options {
c = opt.apply(c)
}

var emptyScope instrumentation.Scope
if c.scope == emptyScope {
c.scope = instrumentation.Scope{
Name: bridgeName,
Version: version,
}
}

if c.provider == nil {
c.provider = global.GetLoggerProvider()
}

return c
}

func (c config) logger() log.Logger {
var opts []log.LoggerOption
if c.scope.Version != "" {
opts = append(opts, log.WithInstrumentationVersion(c.scope.Version))
}
if c.scope.SchemaURL != "" {
opts = append(opts, log.WithSchemaURL(c.scope.SchemaURL))
}
return c.provider.Logger(c.scope.Name, opts...)
}

// Option configures a [Core].
type Option interface {
apply(config) config
}

type optFunc func(config) config

func (f optFunc) apply(c config) config { return f(c) }

// WithInstrumentationScope returns an [Option] that configures the scope of
// the [log.Logger] used by a [Core].
//
// By default if this Option is not provided, [Core] will use a default
// instrumentation scope describing this bridge package. It is recommended to
// provide this so log data can be associated with its source package or
// module.
func WithInstrumentationScope(scope instrumentation.Scope) Option {
return optFunc(func(c config) config {
c.scope = scope
return c
})
}

// WithLoggerProvider returns an [Option] that configures [log.LoggerProvider]
// used by a [Core] to create its [log.Logger].
//
// By default if this Option is not provided, the Handler will use the global
// LoggerProvider.
func WithLoggerProvider(provider log.LoggerProvider) Option {
return optFunc(func(c config) config {
c.provider = provider
return c
})
}

// Core is a [zapcore.Core] that sends logging records to OpenTelemetry.
type Core struct {
logger log.Logger
}

// Compile-time check *Core implements zapcore.Core.
var _ zapcore.Core = (*Core)(nil)

// NewCore creates a new [zapcore.Core] that can be used with [go.uber.org/zap.New].
func NewCore(opts ...Option) *Core {
cfg := newConfig(opts)
return &Core{
logger: cfg.logger(),
}
}

// TODO
// LevelEnabler decides whether a given logging level is enabled when logging a message.
func (o *Core) Enabled(level zapcore.Level) bool {
return true

Check warning on line 111 in bridges/otelzap/core.go

View check run for this annotation

Codecov / codecov/patch

bridges/otelzap/core.go#L110-L111

Added lines #L110 - L111 were not covered by tests
}

// TODO
// With adds structured context to the Core.
func (o *Core) With(fields []zapcore.Field) zapcore.Core {
return o

Check warning on line 117 in bridges/otelzap/core.go

View check run for this annotation

Codecov / codecov/patch

bridges/otelzap/core.go#L116-L117

Added lines #L116 - L117 were not covered by tests
}

// TODO
// Sync flushes buffered logs (if any).
khushijain21 marked this conversation as resolved.
Show resolved Hide resolved
func (o *Core) Sync() error {
return nil

Check warning on line 123 in bridges/otelzap/core.go

View check run for this annotation

Codecov / codecov/patch

bridges/otelzap/core.go#L122-L123

Added lines #L122 - L123 were not covered by tests
}

// TODO
// Check determines whether the supplied Entry should be logged using core.Enabled method.
func (o *Core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
return ce

Check warning on line 129 in bridges/otelzap/core.go

View check run for this annotation

Codecov / codecov/patch

bridges/otelzap/core.go#L128-L129

Added lines #L128 - L129 were not covered by tests
}

// TODO
// Write method encodes zap fields to OTel logs and emits them.
func (o *Core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
return nil

Check warning on line 135 in bridges/otelzap/core.go

View check run for this annotation

Codecov / codecov/patch

bridges/otelzap/core.go#L134-L135

Added lines #L134 - L135 were not covered by tests
}
55 changes: 55 additions & 0 deletions bridges/otelzap/core_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package otelzap

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/log/logtest"
"go.opentelemetry.io/otel/sdk/instrumentation"
)

func TestNewCoreConfiguration(t *testing.T) {
t.Run("Default", func(t *testing.T) {
r := logtest.NewRecorder()
prev := global.GetLoggerProvider()
defer global.SetLoggerProvider(prev)
global.SetLoggerProvider(r)
khushijain21 marked this conversation as resolved.
Show resolved Hide resolved

var h *Core
require.NotPanics(t, func() { h = NewCore() })
require.NotNil(t, h.logger)
require.IsType(t, &logtest.Recorder{}, h.logger)
l := h.logger.(*logtest.Recorder)
require.Len(t, l.Result(), 1)

want := &logtest.ScopeRecords{Name: bridgeName, Version: version}
got := l.Result()[0]
assert.Equal(t, want, got)
})

t.Run("Options", func(t *testing.T) {
r := logtest.NewRecorder()
scope := instrumentation.Scope{Name: "name", Version: "ver", SchemaURL: "url"}
var h *Core
require.NotPanics(t, func() {
h = NewCore(
WithLoggerProvider(r),
WithInstrumentationScope(scope),
)
})
require.NotNil(t, h.logger)
require.IsType(t, &logtest.Recorder{}, h.logger)
l := h.logger.(*logtest.Recorder)
require.Len(t, l.Result(), 1)

want := &logtest.ScopeRecords{Name: scope.Name, Version: scope.Version, SchemaURL: scope.SchemaURL}
got := l.Result()[0]
assert.Equal(t, want, got)
})
}
22 changes: 22 additions & 0 deletions bridges/otelzap/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module go.opentelemetry.io/contrib/bridges/otelzap

go 1.21

require (
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel/log v0.2.0-alpha
go.opentelemetry.io/otel/sdk v1.26.0
go.uber.org/zap v1.27.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
go.opentelemetry.io/otel/metric v1.26.0 // indirect
go.opentelemetry.io/otel/trace v1.26.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
33 changes: 33 additions & 0 deletions bridges/otelzap/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
go.opentelemetry.io/otel/log v0.2.0-alpha h1:ixOPvMzserpqA07SENHvRzkZOsnG0XbPr74hv1AQ+n0=
go.opentelemetry.io/otel/log v0.2.0-alpha/go.mod h1:vbFZc65yq4c4ssvXY43y/nIqkNJLxORrqw0L85P59LA=
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7 changes: 7 additions & 0 deletions bridges/otelzap/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package otelzap // import "go.opentelemetry.io/contrib/bridges/otelzap"

// Version is the current release version of otelzap in use.
const version = "0.1.0"
1 change: 1 addition & 0 deletions versions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ module-sets:
modules:
- go.opentelemetry.io/contrib/processors/baggage/baggagetrace
excluded-modules:
- go.opentelemetry.io/contrib/bridges/otelzap
- go.opentelemetry.io/contrib/instrgen
- go.opentelemetry.io/contrib/instrgen/driver
- go.opentelemetry.io/contrib/instrgen/testdata/interface