log/utility.go

181 lines
4.0 KiB
Go

package log
import (
"encoding/json"
"fmt"
"net"
"os"
"path"
"runtime"
"strings"
"time"
"apigo.cc/go/cast"
)
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()
addrs, err := net.InterfaceAddrs()
if err == nil {
for _, a := range addrs {
if an, ok := a.(*net.IPNet); ok {
// 忽略 Docker 私有网段
if an.IP.IsGlobalUnicast() && !strings.HasPrefix(an.IP.To4().String(), "172.17.") {
serverIp = an.IP.To4().String()
break
}
}
}
}
}
// MakeTime 解析时间字符串
func MakeTime(logTime string) time.Time {
tm, _ := time.Parse(time.RFC3339Nano, logTime)
return tm
}
// MakeLogTime 格式化时间为 RFC3339Nano
func MakeLogTime(tm time.Time) string {
return tm.Format(time.RFC3339Nano)
}
// MakeUsedTime 计算消耗时间(毫秒)
func MakeUsedTime(startTime, endTime time.Time) float32 {
return float32(endTime.UnixNano()-startTime.UnixNano()) / 1e6
}
// ParseBaseLog 解析基础日志行
func ParseBaseLog(line string) *BaseLog {
pos := strings.IndexByte(line, '{')
if pos == -1 {
return ParseBadLog(line)
}
l := make(map[string]any)
err := json.Unmarshal([]byte(line[pos:]), &l)
if err != nil {
return ParseBadLog(line)
}
baseLog := BaseLog{Extra: make(map[string]any)}
for k, v := range l {
lk := strings.ToLower(k)
switch lk {
case "logname":
baseLog.LogName = cast.String(v)
case "logtype":
baseLog.LogType = cast.String(v)
case "logtime":
baseLog.LogTime = cast.String(v)
case "traceid":
baseLog.TraceId = cast.String(v)
case "imagename":
baseLog.ImageName = cast.String(v)
case "imagetag":
baseLog.ImageTag = cast.String(v)
case "servername":
baseLog.ServerName = cast.String(v)
case "serverip":
baseLog.ServerIp = cast.String(v)
default:
baseLog.Extra[lk] = v
}
}
return &baseLog
}
// ParseBadLog 解析非 JSON 格式的日志
func ParseBadLog(line string) *BaseLog {
baseLog := BaseLog{Extra: make(map[string]any)}
baseLog.LogType = LogTypeUndefined
if len(line) > 19 && line[19] == ' ' {
tm, err := time.Parse("2006/01/02 15:04:05", line[0:19])
if err == nil {
baseLog.LogTime = MakeLogTime(tm)
line = line[20:]
} else {
return nil
}
} else if len(line) > 26 && line[26] == ' ' {
tm, err := time.Parse("2006/01/02 15:04:05.000000", line[0:26])
if err == nil {
baseLog.LogTime = MakeLogTime(tm)
line = line[27:]
} else {
return nil
}
} else {
return nil
}
baseLog.Extra["info"] = line
return &baseLog
}
// fixField 格式化字段名(去横线,小写)
func fixField(s string) string {
return strings.ToLower(strings.ReplaceAll(s, "-", ""))
}
// 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
}
if strings.Contains(file, "/log/") { // 注意这里的路径匹配,迁移后是 /log/
if inLogger {
continue
}
} else {
inLogger = false
}
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
}
// GetDefaultName 获取默认应用名称
func GetDefaultName() string {
name := os.Getenv("DISCOVER_APP")
if name == "" {
name = os.Getenv("discover_app")
}
if name == "" {
imageName := os.Getenv("DOCKER_IMAGE_NAME")
if imageName != "" {
parts := strings.Split(imageName, "/")
imageName = parts[len(parts)-1]
imageName = strings.SplitN(imageName, ":", 2)[0]
imageName = strings.SplitN(imageName, "#", 2)[0]
name = imageName
}
}
if name == "" {
name = path.Base(os.Args[0])
}
return name
}