github.com/ssgreg/logf@v1.4.1/caller.go (about) 1 package logf 2 3 import ( 4 "runtime" 5 "strconv" 6 "strings" 7 "unsafe" 8 ) 9 10 // EntryCaller holds values returned by runtime.Caller. 11 type EntryCaller struct { 12 PC uintptr 13 File string 14 Line int 15 Specified bool 16 } 17 18 // NewEntryCaller creates an instance of EntryCaller with the given number 19 // of frames to skip. 20 func NewEntryCaller(skip int) EntryCaller { 21 var c EntryCaller 22 c.PC, c.File, c.Line, c.Specified = runtime.Caller(skip + 1) 23 24 return c 25 } 26 27 // FileWithPackage cuts a package name and a file name from EntryCaller.File. 28 func (c EntryCaller) FileWithPackage() string { 29 30 // As for os-specific path separator battle here, my opinion coincides 31 // with the last comment here https://github.com/golang/go/issues/3335. 32 // 33 // Go team should simply document the current behavior of always using 34 // '/' in stack frame data. That's the way it's been implemented for 35 // years, and packages like github.com/go-stack/stack that have been 36 // stable for years expect it. Changing the behavior in a future version 37 // of Go will break working code without a clearly documented benefit. 38 // Documenting the behavior will help avoid new code from making the 39 // wrong assumptions. 40 41 found := strings.LastIndexByte(c.File, '/') 42 if found == -1 { 43 return c.File 44 } 45 found = strings.LastIndexByte(c.File[:found], '/') 46 if found == -1 { 47 return c.File 48 } 49 50 return c.File[found+1:] 51 } 52 53 // CallerEncoder is the function type to encode the given EntryCaller. 54 type CallerEncoder func(EntryCaller, TypeEncoder) 55 56 // ShortCallerEncoder encodes the given EntryCaller using it's FileWithPackage 57 // function. 58 func ShortCallerEncoder(c EntryCaller, m TypeEncoder) { 59 var callerBuf [64]byte 60 var b []byte 61 b = callerBuf[:0] 62 b = append(b, c.FileWithPackage()...) 63 b = append(b, ':') 64 b = strconv.AppendInt(b, int64(c.Line), 10) 65 66 m.EncodeTypeUnsafeBytes(noescape(unsafe.Pointer(&b))) 67 runtime.KeepAlive(&b) 68 } 69 70 // FullCallerEncoder encodes the given EntryCaller using a full file path. 71 func FullCallerEncoder(c EntryCaller, m TypeEncoder) { 72 var callerBuf [256]byte 73 var b []byte 74 b = callerBuf[:0] 75 b = append(b, c.File...) 76 b = append(b, ':') 77 b = strconv.AppendInt(b, int64(c.Line), 10) 78 79 m.EncodeTypeUnsafeBytes(noescape(unsafe.Pointer(&b))) 80 runtime.KeepAlive(&b) 81 }