@@ -2,8 +2,10 @@ package otelzap
22
33import (
44 "bytes"
5+ "context"
56 "encoding/json"
67 "errors"
8+ "fmt"
79 "math"
810 "testing"
911 "time"
@@ -228,7 +230,7 @@ func TestOtelZapCore_Write(t *testing.T) {
228230 wantMessage : "fail" ,
229231 wantAttrs : map [string ]string {
230232 "err" : "fail" ,
231- "exception.type" : "file.go:42" ,
233+ "caller" : "file.go:42" ,
232234 "exception.stacktrace" : "stacktrace" ,
233235 },
234236 },
@@ -490,3 +492,105 @@ func (t *testMixedArray) MarshalLogArray(enc zapcore.ArrayEncoder) error {
490492 }
491493 return nil
492494}
495+
496+ func TestCallerInfo (t * testing.T ) {
497+ // Setup OTEL exporter
498+ var buf bytes.Buffer
499+ exporter , err := stdoutlog .New (stdoutlog .WithWriter (& buf ))
500+ require .NoError (t , err )
501+
502+ // Setup OTEL provider
503+ provider := sdklog .NewLoggerProvider (sdklog .WithProcessor (sdklog .NewBatchProcessor (exporter )))
504+
505+ // Create otel zap core
506+ logger := provider .Logger ("test" )
507+ core := NewCore (logger )
508+
509+ tests := []struct {
510+ name string
511+ level zapcore.Level
512+ caller zapcore.EntryCaller
513+ wantCaller bool
514+ }{
515+ {
516+ name : "info with caller" ,
517+ level : zapcore .InfoLevel ,
518+ caller : zapcore.EntryCaller {Defined : true , File : "test.go" , Line : 123 , Function : "TestFunc" },
519+ wantCaller : true ,
520+ },
521+ {
522+ name : "error with caller" ,
523+ level : zapcore .ErrorLevel ,
524+ caller : zapcore.EntryCaller {Defined : true , File : "error.go" , Line : 456 , Function : "ErrorFunc" },
525+ wantCaller : true ,
526+ },
527+ {
528+ name : "debug without caller" ,
529+ level : zapcore .DebugLevel ,
530+ caller : zapcore.EntryCaller {Defined : false },
531+ wantCaller : false ,
532+ },
533+ }
534+
535+ for _ , tt := range tests {
536+ t .Run (tt .name , func (t * testing.T ) {
537+ buf .Reset ()
538+
539+ entry := zapcore.Entry {
540+ Message : "test message" ,
541+ Level : tt .level ,
542+ Time : time .Now (),
543+ Caller : tt .caller ,
544+ }
545+
546+ err := core .Write (entry , nil )
547+ require .NoError (t , err )
548+
549+ // Force flush
550+ require .NoError (t , provider .ForceFlush (context .Background ()))
551+
552+ if ! tt .wantCaller {
553+ // If no caller expected, we just check that no caller attributes exist
554+ var logEntry struct {
555+ Attributes []struct {
556+ Key string `json:"key"`
557+ Value struct {
558+ Value interface {} `json:"value"`
559+ } `json:"value"`
560+ } `json:"attributes"`
561+ }
562+ err = json .Unmarshal (buf .Bytes (), & logEntry )
563+ require .NoError (t , err )
564+
565+ for _ , attr := range logEntry .Attributes {
566+ assert .NotContains (t , []string {"caller" , "source.file" , "source.line" , "source.function" }, attr .Key )
567+ }
568+ return
569+ }
570+
571+ // Parse JSON output and check for caller attributes
572+ var logEntry struct {
573+ Attributes []struct {
574+ Key string `json:"key"`
575+ Value struct {
576+ Value string `json:"value"`
577+ } `json:"value"`
578+ } `json:"attributes"`
579+ }
580+ err = json .Unmarshal (buf .Bytes (), & logEntry )
581+ require .NoError (t , err , "failed to parse OTEL JSON log output" )
582+
583+ got := map [string ]string {}
584+ for _ , attr := range logEntry .Attributes {
585+ got [attr .Key ] = attr .Value .Value
586+ }
587+
588+ // Check required caller attributes
589+ assert .Contains (t , got , "caller" )
590+
591+ expectedCaller := fmt .Sprintf ("%s:%d" , tt .caller .File , tt .caller .Line )
592+ assert .Equal (t , expectedCaller , fmt .Sprintf ("%v" , got ["caller" ]))
593+
594+ })
595+ }
596+ }
0 commit comments