mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-25 17:44:32 +02:00 
			
		
		
		
	Result of running `perl -p -i -e 's#interface\{\}#any#g' **/*` and `make fmt`.
Basically the same [as golang did](2580d0e08d).
		
	
			
		
			
				
	
	
		
			173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package routing
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	funcInfoMap     = map[uintptr]*FuncInfo{}
 | |
| 	funcInfoNameMap = map[string]*FuncInfo{}
 | |
| 	funcInfoMapMu   sync.RWMutex
 | |
| )
 | |
| 
 | |
| // FuncInfo contains information about the function to be logged by the router log
 | |
| type FuncInfo struct {
 | |
| 	file      string
 | |
| 	shortFile string
 | |
| 	line      int
 | |
| 	name      string
 | |
| 	shortName string
 | |
| }
 | |
| 
 | |
| // String returns a string form of the FuncInfo for logging
 | |
| func (info *FuncInfo) String() string {
 | |
| 	if info == nil {
 | |
| 		return "unknown-handler"
 | |
| 	}
 | |
| 	return fmt.Sprintf("%s:%d(%s)", info.shortFile, info.line, info.shortName)
 | |
| }
 | |
| 
 | |
| // GetFuncInfo returns the FuncInfo for a provided function and friendlyname
 | |
| func GetFuncInfo(fn any, friendlyName ...string) *FuncInfo {
 | |
| 	// ptr represents the memory position of the function passed in as v.
 | |
| 	// This will be used as program counter in FuncForPC below
 | |
| 	ptr := reflect.ValueOf(fn).Pointer()
 | |
| 
 | |
| 	// if we have been provided with a friendlyName look for the named funcs
 | |
| 	if len(friendlyName) == 1 {
 | |
| 		name := friendlyName[0]
 | |
| 		funcInfoMapMu.RLock()
 | |
| 		info, ok := funcInfoNameMap[name]
 | |
| 		funcInfoMapMu.RUnlock()
 | |
| 		if ok {
 | |
| 			return info
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Otherwise attempt to get pre-cached information for this function pointer
 | |
| 	funcInfoMapMu.RLock()
 | |
| 	info, ok := funcInfoMap[ptr]
 | |
| 	funcInfoMapMu.RUnlock()
 | |
| 
 | |
| 	if ok {
 | |
| 		if len(friendlyName) == 1 {
 | |
| 			name := friendlyName[0]
 | |
| 			info = copyFuncInfo(info)
 | |
| 			info.shortName = name
 | |
| 
 | |
| 			funcInfoNameMap[name] = info
 | |
| 			funcInfoMapMu.Lock()
 | |
| 			funcInfoNameMap[name] = info
 | |
| 			funcInfoMapMu.Unlock()
 | |
| 		}
 | |
| 		return info
 | |
| 	}
 | |
| 
 | |
| 	// This is likely the first time we have seen this function
 | |
| 	//
 | |
| 	// Get the runtime.func for this function (if we can)
 | |
| 	f := runtime.FuncForPC(ptr)
 | |
| 	if f != nil {
 | |
| 		info = convertToFuncInfo(f)
 | |
| 
 | |
| 		// cache this info globally
 | |
| 		funcInfoMapMu.Lock()
 | |
| 		funcInfoMap[ptr] = info
 | |
| 
 | |
| 		// if we have been provided with a friendlyName override the short name we've generated
 | |
| 		if len(friendlyName) == 1 {
 | |
| 			name := friendlyName[0]
 | |
| 			info = copyFuncInfo(info)
 | |
| 			info.shortName = name
 | |
| 			funcInfoNameMap[name] = info
 | |
| 		}
 | |
| 		funcInfoMapMu.Unlock()
 | |
| 	}
 | |
| 	return info
 | |
| }
 | |
| 
 | |
| // convertToFuncInfo take a runtime.Func and convert it to a logFuncInfo, fill in shorten filename, etc
 | |
| func convertToFuncInfo(f *runtime.Func) *FuncInfo {
 | |
| 	file, line := f.FileLine(f.Entry())
 | |
| 
 | |
| 	info := &FuncInfo{
 | |
| 		file: strings.ReplaceAll(file, "\\", "/"),
 | |
| 		line: line,
 | |
| 		name: f.Name(),
 | |
| 	}
 | |
| 
 | |
| 	// only keep last 2 names in path, fall back to funcName if not
 | |
| 	info.shortFile = shortenFilename(info.file, info.name)
 | |
| 
 | |
| 	// remove package prefix. eg: "xxx.com/pkg1/pkg2.foo" => "pkg2.foo"
 | |
| 	pos := strings.LastIndexByte(info.name, '/')
 | |
| 	if pos >= 0 {
 | |
| 		info.shortName = info.name[pos+1:]
 | |
| 	} else {
 | |
| 		info.shortName = info.name
 | |
| 	}
 | |
| 
 | |
| 	// remove ".func[0-9]*" suffix for anonymous func
 | |
| 	info.shortName = trimAnonymousFunctionSuffix(info.shortName)
 | |
| 
 | |
| 	return info
 | |
| }
 | |
| 
 | |
| func copyFuncInfo(l *FuncInfo) *FuncInfo {
 | |
| 	return &FuncInfo{
 | |
| 		file:      l.file,
 | |
| 		shortFile: l.shortFile,
 | |
| 		line:      l.line,
 | |
| 		name:      l.name,
 | |
| 		shortName: l.shortName,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // shortenFilename generates a short source code filename from a full package path, eg: "code.gitea.io/routers/common/logger_context.go" => "common/logger_context.go"
 | |
| func shortenFilename(filename, fallback string) string {
 | |
| 	if filename == "" {
 | |
| 		return fallback
 | |
| 	}
 | |
| 	if lastIndex := strings.LastIndexByte(filename, '/'); lastIndex >= 0 {
 | |
| 		if secondLastIndex := strings.LastIndexByte(filename[:lastIndex], '/'); secondLastIndex >= 0 {
 | |
| 			return filename[secondLastIndex+1:]
 | |
| 		}
 | |
| 	}
 | |
| 	return filename
 | |
| }
 | |
| 
 | |
| // trimAnonymousFunctionSuffix trims ".func[0-9]*" from the end of anonymous function names, we only want to see the main function names in logs
 | |
| func trimAnonymousFunctionSuffix(name string) string {
 | |
| 	// if the name is an anonymous name, it should be like "{main-function}.func1", so the length can not be less than 7
 | |
| 	if len(name) < 7 {
 | |
| 		return name
 | |
| 	}
 | |
| 
 | |
| 	funcSuffixIndex := strings.LastIndex(name, ".func")
 | |
| 	if funcSuffixIndex < 0 {
 | |
| 		return name
 | |
| 	}
 | |
| 
 | |
| 	hasFuncSuffix := true
 | |
| 
 | |
| 	// len(".func") = 5
 | |
| 	for i := funcSuffixIndex + 5; i < len(name); i++ {
 | |
| 		if name[i] < '0' || name[i] > '9' {
 | |
| 			hasFuncSuffix = false
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if hasFuncSuffix {
 | |
| 		return name[:funcSuffixIndex]
 | |
| 	}
 | |
| 	return name
 | |
| }
 |