diff --git a/bridges/otelzerolog/hook.go b/bridges/otelzerolog/hook.go index 2928396240b..5f8327f1f01 100644 --- a/bridges/otelzerolog/hook.go +++ b/bridges/otelzerolog/hook.go @@ -100,5 +100,33 @@ func NewHook(name string, options ...Option) *Hook { // Run handles the passed record, and sends it to OpenTelemetry. func (h Hook) Run(e *zerolog.Event, level zerolog.Level, msg string) { - // TODO + r := log.Record{} + r.SetSeverity(convertLevel(level)) + r.SetBody(log.StringValue(msg)) + r.SetSeverityText(level.String()) + + // TODO: add support for attributes + // This is limited by zerolog's inability to retrieve fields. + // https://github.com/rs/zerolog/issues/493 + + h.logger.Emit(e.GetCtx(), r) +} + +func convertLevel(level zerolog.Level) log.Severity { + switch level { + case zerolog.DebugLevel: + return log.SeverityDebug + case zerolog.InfoLevel: + return log.SeverityInfo + case zerolog.WarnLevel: + return log.SeverityWarn + case zerolog.ErrorLevel: + return log.SeverityError + case zerolog.PanicLevel: + return log.SeverityFatal1 + case zerolog.FatalLevel: + return log.SeverityFatal2 + default: + return log.SeverityUndefined + } } diff --git a/bridges/otelzerolog/hook_test.go b/bridges/otelzerolog/hook_test.go index 273e9c73c59..27f23a4a192 100644 --- a/bridges/otelzerolog/hook_test.go +++ b/bridges/otelzerolog/hook_test.go @@ -3,13 +3,17 @@ package otelzerolog import ( + "os" "testing" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/log" "go.opentelemetry.io/otel/log/embedded" "go.opentelemetry.io/otel/log/global" + "go.opentelemetry.io/otel/log/logtest" ) type mockLoggerProvider struct { @@ -103,3 +107,83 @@ func TestNewHook(t *testing.T) { }) } } + +var ( + testMessage = "log message" + loggerName = "name" + testKey = "key" + testValue = "value" + testEntry = zerolog.InfoLevel +) + +func TestHookRun(t *testing.T) { + rec := logtest.NewRecorder() + hook := NewHook(loggerName, WithLoggerProvider(rec)) + + logger := zerolog.New(os.Stderr).Hook(hook) + + t.Run("Run", func(t *testing.T) { + // Create an event and run the hook + event := logger.Info().Str(testKey, testValue) + hook.Run(event, testEntry, testMessage) + + // Check the results + require.Len(t, rec.Result(), 1) + require.Len(t, rec.Result()[0].Records, 1) + got := rec.Result()[0].Records[0] + assert.Equal(t, testMessage, got.Body().AsString()) + assert.Equal(t, log.SeverityInfo, got.Severity()) + assert.Equal(t, zerolog.InfoLevel.String(), got.SeverityText()) + }) +} + +func TestConvertLevel(t *testing.T) { + tests := []struct { + name string + zerologLevel zerolog.Level + expected log.Severity + }{ + { + name: "DebugLevel", + zerologLevel: zerolog.DebugLevel, + expected: log.SeverityDebug, + }, + { + name: "InfoLevel", + zerologLevel: zerolog.InfoLevel, + expected: log.SeverityInfo, + }, + { + name: "WarnLevel", + zerologLevel: zerolog.WarnLevel, + expected: log.SeverityWarn, + }, + { + name: "ErrorLevel", + zerologLevel: zerolog.ErrorLevel, + expected: log.SeverityError, + }, + { + name: "PanicLevel", + zerologLevel: zerolog.PanicLevel, + expected: log.SeverityFatal1, + }, + { + name: "FatalLevel", + zerologLevel: zerolog.FatalLevel, + expected: log.SeverityFatal2, + }, + { + name: "UnknownLevel", + zerologLevel: zerolog.NoLevel, // An unknown level + expected: log.SeverityUndefined, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := convertLevel(tt.zerologLevel) + assert.Equal(t, tt.expected, actual, "severity mismatch") + }) + } +}