Skip to content

Commit

Permalink
otelzap: Split code attributes (#6423)
Browse files Browse the repository at this point in the history
Same as
#6415 for
otelzap
  • Loading branch information
pellared authored Dec 12, 2024
1 parent cb458f1 commit a71bdc8
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Allow marshaling types in `go.opentelemetry.io/contrib/config`. (#6347)
- Removed the redundant handling of panic from the `HTML` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6373)
- The `code.function` attribute emitted by `go.opentelemetry.io/contrib/bridges/otelslog` now stores just the function name instead the package path-qualified function name. The `code.namespace` attribute now stores the package path. (#6415)
- The `code.function` attribute emitted by `go.opentelemetry.io/contrib/bridges/otelzap` now stores just the function name instead the package path-qualified function name. The `code.namespace` attribute now stores the package path. (#6423)

<!-- Released section -->
<!-- Don't change this section unless doing release -->
Expand Down
6 changes: 6 additions & 0 deletions bridges/otelslog/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,12 @@ func TestSplitFuncName(t *testing.T) {
wantFuncName: "foo",
wantNamespace: "github.com/my/repo/pkg",
},
{
// anonymous function
fullFuncName: "github.com/my/repo/pkg.foo.func5",
wantFuncName: "func5",
wantNamespace: "github.com/my/repo/pkg.foo",
},
{
fullFuncName: "net/http.Get",
wantFuncName: "Get",
Expand Down
17 changes: 16 additions & 1 deletion bridges/otelzap/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ package otelzap // import "go.opentelemetry.io/contrib/bridges/otelzap"
import (
"context"
"slices"
"strings"

"go.uber.org/zap/zapcore"

Expand Down Expand Up @@ -202,10 +203,12 @@ func (o *Core) Write(ent zapcore.Entry, fields []zapcore.Field) error {

r.AddAttributes(o.attr...)
if ent.Caller.Defined {
funcName, namespace := splitFuncName(ent.Caller.Function)
r.AddAttributes(
log.String(string(semconv.CodeFilepathKey), ent.Caller.File),
log.Int(string(semconv.CodeLineNumberKey), ent.Caller.Line),
log.String(string(semconv.CodeFunctionKey), ent.Caller.Function),
log.String(string(semconv.CodeFunctionKey), funcName),
log.String(string(semconv.CodeNamespaceKey), namespace),
)
}
if ent.Stack != "" {
Expand Down Expand Up @@ -262,3 +265,15 @@ func convertLevel(level zapcore.Level) log.Severity {
return log.SeverityUndefined
}
}

// splitFuncName splits package path-qualified function name into
// function name and package full name (namespace). E.g. it splits
// "github.com/my/repo/pkg.foo" into
// "foo" and "github.com/my/repo/pkg".
func splitFuncName(f string) (string, string) {
i := strings.LastIndexByte(f, '.')
if i < 0 {
return "", ""
}
return f[i+1:], f[:i]
}
48 changes: 46 additions & 2 deletions bridges/otelzap/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,17 @@ func TestCoreWithCaller(t *testing.T) {
assert.Equal(t, testMessage, got.Body().AsString())
assert.Equal(t, log.SeverityInfo, got.Severity())
assert.Equal(t, zap.InfoLevel.String(), got.SeverityText())
assert.Equal(t, 3, got.AttributesLen())
assert.Equal(t, 4, got.AttributesLen())
got.WalkAttributes(func(kv log.KeyValue) bool {
switch kv.Key {
case string(semconv.CodeFilepathKey):
assert.Contains(t, kv.Value.AsString(), "core_test.go")
case string(semconv.CodeLineNumberKey):
assert.Positive(t, kv.Value.AsInt64())
case string(semconv.CodeFunctionKey):
assert.Contains(t, kv.Value.AsString(), "TestCoreWithCaller")
assert.Equal(t, t.Name(), kv.Value.AsString())
case string(semconv.CodeNamespaceKey):
assert.Equal(t, "go.opentelemetry.io/contrib/bridges/otelzap", kv.Value.AsString())
default:
assert.Fail(t, "unexpected attribute key", kv.Key)
}
Expand Down Expand Up @@ -269,6 +271,48 @@ func TestConvertLevel(t *testing.T) {
}
}

func TestSplitFuncName(t *testing.T) {
testCases := []struct {
fullFuncName string
wantFuncName string
wantNamespace string
}{
{
fullFuncName: "github.com/my/repo/pkg.foo",
wantFuncName: "foo",
wantNamespace: "github.com/my/repo/pkg",
},
{
// anonymous function
fullFuncName: "github.com/my/repo/pkg.foo.func5",
wantFuncName: "func5",
wantNamespace: "github.com/my/repo/pkg.foo",
},
{
fullFuncName: "net/http.Get",
wantFuncName: "Get",
wantNamespace: "net/http",
},
{
fullFuncName: "invalid",
wantFuncName: "",
wantNamespace: "",
},
{
fullFuncName: ".",
wantFuncName: "",
wantNamespace: "",
},
}
for _, tc := range testCases {
t.Run(tc.fullFuncName, func(t *testing.T) {
gotFuncName, gotNamespace := splitFuncName(tc.fullFuncName)
assert.Equal(t, tc.wantFuncName, gotFuncName)
assert.Equal(t, tc.wantNamespace, gotNamespace)
})
}
}

func BenchmarkCoreWrite(b *testing.B) {
benchmarks := []struct {
name string
Expand Down

0 comments on commit a71bdc8

Please sign in to comment.