2026-05-02 23:39:10 +08:00
|
|
|
package log
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"net"
|
|
|
|
|
"os"
|
|
|
|
|
"path"
|
|
|
|
|
"runtime"
|
2026-05-09 14:44:41 +08:00
|
|
|
"runtime/debug"
|
2026-05-02 23:39:10 +08:00
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
dockerImageName string
|
|
|
|
|
dockerImageTag string
|
|
|
|
|
serverName string
|
|
|
|
|
serverIp string
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
dockerImageName = os.Getenv("DOCKER_IMAGE_NAME")
|
|
|
|
|
dockerImageTag = os.Getenv("DOCKER_IMAGE_TAG")
|
|
|
|
|
serverName, _ = os.Hostname()
|
2026-05-09 14:44:41 +08:00
|
|
|
|
|
|
|
|
// 获取真实局域网 IP (UDP 8.8.8.8 伪拨号法)
|
|
|
|
|
conn, err := net.Dial("udp", "8.8.8.8:80")
|
2026-05-02 23:39:10 +08:00
|
|
|
if err == nil {
|
2026-05-09 14:44:41 +08:00
|
|
|
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
|
|
|
|
serverIp = localAddr.IP.String()
|
|
|
|
|
_ = conn.Close()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if serverIp == "" {
|
|
|
|
|
addrs, err := net.InterfaceAddrs()
|
|
|
|
|
if err == nil {
|
|
|
|
|
for _, a := range addrs {
|
|
|
|
|
if an, ok := a.(*net.IPNet); ok {
|
|
|
|
|
if an.IP.IsGlobalUnicast() {
|
|
|
|
|
serverIp = an.IP.To4().String()
|
|
|
|
|
break
|
|
|
|
|
}
|
2026-05-02 23:39:10 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-05 23:09:46 +08:00
|
|
|
// fixField 格式化字段名(去横线、下划线,小写)
|
2026-05-02 23:39:10 +08:00
|
|
|
func fixField(s string) string {
|
2026-05-05 23:09:46 +08:00
|
|
|
s = strings.ReplaceAll(s, "-", "")
|
|
|
|
|
s = strings.ReplaceAll(s, "_", "")
|
|
|
|
|
return strings.ToLower(s)
|
2026-05-02 23:39:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getCallStacks 获取调用栈
|
|
|
|
|
func getCallStacks(truncations []string) []string {
|
|
|
|
|
callStacks := make([]string, 0)
|
|
|
|
|
inLogger := true
|
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
|
_, file, line, ok := runtime.Caller(i)
|
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if strings.Contains(file, "/go/src/") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2026-05-04 01:14:46 +08:00
|
|
|
// 只有在 logger.go, extra.go 等核心实现文件中的帧才被认为是 "inLogger"
|
|
|
|
|
// 这样可以保留测试文件 (xxx_test.go) 的调用栈
|
|
|
|
|
isLogInternal := (strings.Contains(file, "/log/logger.go") ||
|
|
|
|
|
strings.Contains(file, "/log/utility.go") ||
|
|
|
|
|
strings.Contains(file, "/log/standard.go") ||
|
2026-05-13 01:07:42 +08:00
|
|
|
strings.Contains(file, "/log/default_logger.go") ||
|
2026-05-04 01:14:46 +08:00
|
|
|
strings.Contains(file, "/log/extra.go"))
|
|
|
|
|
|
|
|
|
|
if isLogInternal {
|
2026-05-02 23:39:10 +08:00
|
|
|
if inLogger {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inLogger = false
|
|
|
|
|
}
|
2026-05-04 01:14:46 +08:00
|
|
|
|
2026-05-02 23:39:10 +08:00
|
|
|
if truncations != nil {
|
|
|
|
|
for _, truncation := range truncations {
|
|
|
|
|
if pos := strings.Index(file, truncation); pos != -1 {
|
|
|
|
|
file = file[pos+len(truncation):]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
callStacks = append(callStacks, fmt.Sprintf("%s:%d", file, line))
|
|
|
|
|
}
|
|
|
|
|
return callStacks
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-12 22:25:06 +08:00
|
|
|
var globalDefaultName string
|
|
|
|
|
|
|
|
|
|
// getDefaultName 获取默认应用名称
|
|
|
|
|
func getDefaultName() string {
|
|
|
|
|
if globalDefaultName != "" {
|
|
|
|
|
return globalDefaultName
|
|
|
|
|
}
|
2026-05-10 10:50:00 +08:00
|
|
|
name := ""
|
|
|
|
|
if info, ok := debug.ReadBuildInfo(); ok && info.Path != "" && info.Path != "command-line-arguments" {
|
|
|
|
|
name = path.Base(info.Path)
|
2026-05-02 23:39:10 +08:00
|
|
|
}
|
|
|
|
|
if name == "" {
|
|
|
|
|
name = path.Base(os.Args[0])
|
|
|
|
|
}
|
2026-05-10 10:50:00 +08:00
|
|
|
// 处理 Windows 下的 .exe 后缀
|
|
|
|
|
name = strings.TrimSuffix(name, ".exe")
|
2026-05-02 23:39:10 +08:00
|
|
|
return name
|
|
|
|
|
}
|