Skip to content

Commit a71bdc8

Browse files
authored
otelzap: Split code attributes (#6423)
Same as #6415 for otelzap
1 parent cb458f1 commit a71bdc8

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2929
- Allow marshaling types in `go.opentelemetry.io/contrib/config`. (#6347)
3030
- Removed the redundant handling of panic from the `HTML` function in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#6373)
3131
- 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)
32+
- 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)
3233

3334
<!-- Released section -->
3435
<!-- Don't change this section unless doing release -->

bridges/otelslog/handler_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,12 @@ func TestSplitFuncName(t *testing.T) {
522522
wantFuncName: "foo",
523523
wantNamespace: "github.com/my/repo/pkg",
524524
},
525+
{
526+
// anonymous function
527+
fullFuncName: "github.com/my/repo/pkg.foo.func5",
528+
wantFuncName: "func5",
529+
wantNamespace: "github.com/my/repo/pkg.foo",
530+
},
525531
{
526532
fullFuncName: "net/http.Get",
527533
wantFuncName: "Get",

bridges/otelzap/core.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ package otelzap // import "go.opentelemetry.io/contrib/bridges/otelzap"
3636
import (
3737
"context"
3838
"slices"
39+
"strings"
3940

4041
"go.uber.org/zap/zapcore"
4142

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

203204
r.AddAttributes(o.attr...)
204205
if ent.Caller.Defined {
206+
funcName, namespace := splitFuncName(ent.Caller.Function)
205207
r.AddAttributes(
206208
log.String(string(semconv.CodeFilepathKey), ent.Caller.File),
207209
log.Int(string(semconv.CodeLineNumberKey), ent.Caller.Line),
208-
log.String(string(semconv.CodeFunctionKey), ent.Caller.Function),
210+
log.String(string(semconv.CodeFunctionKey), funcName),
211+
log.String(string(semconv.CodeNamespaceKey), namespace),
209212
)
210213
}
211214
if ent.Stack != "" {
@@ -262,3 +265,15 @@ func convertLevel(level zapcore.Level) log.Severity {
262265
return log.SeverityUndefined
263266
}
264267
}
268+
269+
// splitFuncName splits package path-qualified function name into
270+
// function name and package full name (namespace). E.g. it splits
271+
// "github.com/my/repo/pkg.foo" into
272+
// "foo" and "github.com/my/repo/pkg".
273+
func splitFuncName(f string) (string, string) {
274+
i := strings.LastIndexByte(f, '.')
275+
if i < 0 {
276+
return "", ""
277+
}
278+
return f[i+1:], f[:i]
279+
}

bridges/otelzap/core_test.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,17 @@ func TestCoreWithCaller(t *testing.T) {
175175
assert.Equal(t, testMessage, got.Body().AsString())
176176
assert.Equal(t, log.SeverityInfo, got.Severity())
177177
assert.Equal(t, zap.InfoLevel.String(), got.SeverityText())
178-
assert.Equal(t, 3, got.AttributesLen())
178+
assert.Equal(t, 4, got.AttributesLen())
179179
got.WalkAttributes(func(kv log.KeyValue) bool {
180180
switch kv.Key {
181181
case string(semconv.CodeFilepathKey):
182182
assert.Contains(t, kv.Value.AsString(), "core_test.go")
183183
case string(semconv.CodeLineNumberKey):
184184
assert.Positive(t, kv.Value.AsInt64())
185185
case string(semconv.CodeFunctionKey):
186-
assert.Contains(t, kv.Value.AsString(), "TestCoreWithCaller")
186+
assert.Equal(t, t.Name(), kv.Value.AsString())
187+
case string(semconv.CodeNamespaceKey):
188+
assert.Equal(t, "go.opentelemetry.io/contrib/bridges/otelzap", kv.Value.AsString())
187189
default:
188190
assert.Fail(t, "unexpected attribute key", kv.Key)
189191
}
@@ -269,6 +271,48 @@ func TestConvertLevel(t *testing.T) {
269271
}
270272
}
271273

274+
func TestSplitFuncName(t *testing.T) {
275+
testCases := []struct {
276+
fullFuncName string
277+
wantFuncName string
278+
wantNamespace string
279+
}{
280+
{
281+
fullFuncName: "github.com/my/repo/pkg.foo",
282+
wantFuncName: "foo",
283+
wantNamespace: "github.com/my/repo/pkg",
284+
},
285+
{
286+
// anonymous function
287+
fullFuncName: "github.com/my/repo/pkg.foo.func5",
288+
wantFuncName: "func5",
289+
wantNamespace: "github.com/my/repo/pkg.foo",
290+
},
291+
{
292+
fullFuncName: "net/http.Get",
293+
wantFuncName: "Get",
294+
wantNamespace: "net/http",
295+
},
296+
{
297+
fullFuncName: "invalid",
298+
wantFuncName: "",
299+
wantNamespace: "",
300+
},
301+
{
302+
fullFuncName: ".",
303+
wantFuncName: "",
304+
wantNamespace: "",
305+
},
306+
}
307+
for _, tc := range testCases {
308+
t.Run(tc.fullFuncName, func(t *testing.T) {
309+
gotFuncName, gotNamespace := splitFuncName(tc.fullFuncName)
310+
assert.Equal(t, tc.wantFuncName, gotFuncName)
311+
assert.Equal(t, tc.wantNamespace, gotNamespace)
312+
})
313+
}
314+
}
315+
272316
func BenchmarkCoreWrite(b *testing.B) {
273317
benchmarks := []struct {
274318
name string

0 commit comments

Comments
 (0)