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

otellogrus: Fix logrus.Level conversion #6191

Merged
merged 10 commits into from
Oct 10, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

- Possible nil dereference panic in `go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace`. (#5965)
- Non-200 HTTP status codes when retrieving sampling rules in `go.opentelemetry.io/contrib/samplers/aws/xray` now return an error. (#5718)
- `logrus.Level` transformed to appropriate `log.Severity` in `go.opentelemetry.io/contrib/bridges/otellogrus`. (#6191)

### Removed

Expand Down
38 changes: 31 additions & 7 deletions bridges/otellogrus/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
// set.
// - Fields are transformed and set as the attributes.
//
// The Level is transformed by using the static offset to the OpenTelemetry
// The Level is transformed to the OpenTelemetry
// Severity types. For example:
//
// - [logrus.DebugLevel] is transformed to [log.SeverityDebug]
// - [logrus.InfoLevel] is transformed to [log.SeverityTrace4]
// - [logrus.WarnLevel] is transformed to [log.SeverityTrace3]
// - [logrus.ErrorLevel] is transformed to [log.SeverityTrace2]
// - [logrus.InfoLevel] is transformed to [log.SeverityInfo]
// - [logrus.WarnLevel] is transformed to [log.SeverityWarn]
// - [logrus.ErrorLevel] is transformed to [log.SeverityError]
// - [logrus.FatalLevel] is transformed to [log.SeverityFatal]
// - [logrus.PanicLevel] is transformed to [log.SeverityFatal4]
//
// Field values are transformed based on their type into log attributes, or
// into a string value if there is no matching type.
Expand Down Expand Up @@ -164,9 +166,7 @@
var record log.Record
record.SetTimestamp(e.Time)
record.SetBody(log.StringValue(e.Message))

const sevOffset = logrus.Level(log.SeverityDebug) - logrus.DebugLevel
record.SetSeverity(log.Severity(e.Level + sevOffset))
record.SetSeverity(convertSeverity(e.Level))
record.AddAttributes(convertFields(e.Data)...)

return record
Expand All @@ -183,6 +183,30 @@
return kvs
}

func convertSeverity(level logrus.Level) log.Severity {
switch level {
case logrus.PanicLevel:
// PanicLevel is not supported by OpenTelemetry, use Fatal4 as the highest severity.
return log.SeverityFatal4
case logrus.FatalLevel:
return log.SeverityFatal
case logrus.ErrorLevel:
return log.SeverityError
case logrus.WarnLevel:
return log.SeverityWarn
case logrus.InfoLevel:
return log.SeverityInfo
case logrus.DebugLevel:
return log.SeverityDebug
case logrus.TraceLevel:
return log.SeverityTrace
default:

Check warning on line 203 in bridges/otellogrus/hook.go

View check run for this annotation

Codecov / codecov/patch

bridges/otellogrus/hook.go#L203

Added line #L203 was not covered by tests
// If the level is not recognized, use SeverityUndefined as the lowest severity.
// we should never reach this point as logrus only uses the above levels.
return log.SeverityUndefined

Check warning on line 206 in bridges/otellogrus/hook.go

View check run for this annotation

Codecov / codecov/patch

bridges/otellogrus/hook.go#L206

Added line #L206 was not covered by tests
}
}

func convertValue(v interface{}) log.Value {
switch v := v.(type) {
case bool:
Expand Down
76 changes: 71 additions & 5 deletions bridges/otellogrus/hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func TestHookFire(t *testing.T) {

wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, 0, nil),
buildRecord(log.StringValue(""), time.Time{}, log.SeverityFatal4, nil),
},
},
},
Expand All @@ -173,18 +173,84 @@ func TestHookFire(t *testing.T) {
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), now, 0, nil),
buildRecord(log.StringValue(""), now, log.SeverityFatal4, nil),
},
},
},
{
name: "emits a log entry with severity level",
name: "emits a log entry with panic severity level",
entry: &logrus.Entry{
Level: logrus.PanicLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityFatal4, nil),
},
},
},
{
name: "emits a log entry with fatal severity level",
entry: &logrus.Entry{
Level: logrus.FatalLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityTrace1, nil),
buildRecord(log.StringValue(""), time.Time{}, log.SeverityFatal, nil),
},
},
},
{
name: "emits a log entry with error severity level",
entry: &logrus.Entry{
Level: logrus.ErrorLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityError, nil),
},
},
},
{
name: "emits a log entry with warn severity level",
entry: &logrus.Entry{
Level: logrus.WarnLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityWarn, nil),
},
},
},
{
name: "emits a log entry with info severity level",
entry: &logrus.Entry{
Level: logrus.InfoLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityInfo, nil),
},
},
},
{
name: "emits a log entry with info severity level",
entry: &logrus.Entry{
Level: logrus.DebugLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityDebug, nil),
},
},
},
{
name: "emits a log entry with info severity level",
entry: &logrus.Entry{
Level: logrus.TraceLevel,
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, log.SeverityTrace, nil),
},
},
},
Expand All @@ -197,7 +263,7 @@ func TestHookFire(t *testing.T) {
},
wantRecords: map[string][]log.Record{
name: {
buildRecord(log.StringValue(""), time.Time{}, 0, []log.KeyValue{
buildRecord(log.StringValue(""), time.Time{}, log.SeverityFatal4, []log.KeyValue{
log.String("hello", "world"),
}),
},
Expand Down
Loading