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  }