refactor(logger): 1. optimize the logger log module design and add link tracking related designs
2. add logger facade functions to simplify the use of alarm functions
This commit is contained in:
parent
d2196701ec
commit
9aa5b0dcc6
|
|
@ -9,6 +9,6 @@ import (
|
|||
|
||||
type ModelParseConfig struct {
|
||||
ComponentInfo orm.Component
|
||||
Context context.Context
|
||||
Ctx context.Context
|
||||
AnchorChan chan AnchorParamConfig
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Package logger define log struct of modelRT project
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var (
|
||||
f *facade
|
||||
fOnce sync.Once
|
||||
)
|
||||
|
||||
type facade struct {
|
||||
_logger *zap.Logger
|
||||
}
|
||||
|
||||
// Debug define facade func of debug level log
|
||||
func Debug(ctx context.Context, msg string, kv ...any) {
|
||||
logFacade().log(ctx, zapcore.DebugLevel, msg, kv...)
|
||||
}
|
||||
|
||||
// Info define facade func of info level log
|
||||
func Info(ctx context.Context, msg string, kv ...any) {
|
||||
logFacade().log(ctx, zapcore.InfoLevel, msg, kv...)
|
||||
}
|
||||
|
||||
// Warn define facade func of warn level log
|
||||
func Warn(ctx context.Context, msg string, kv ...any) {
|
||||
logFacade().log(ctx, zapcore.WarnLevel, msg, kv...)
|
||||
}
|
||||
|
||||
// Error define facade func of error level log
|
||||
func Error(ctx context.Context, msg string, kv ...any) {
|
||||
logFacade().log(ctx, zapcore.ErrorLevel, msg, kv...)
|
||||
}
|
||||
|
||||
func (f *facade) log(ctx context.Context, lvl zapcore.Level, msg string, kv ...any) {
|
||||
fields := makeLogFields(ctx, kv...)
|
||||
ce := f._logger.Check(lvl, msg)
|
||||
ce.Write(fields...)
|
||||
}
|
||||
|
||||
func logFacade() *facade {
|
||||
fOnce.Do(func() {
|
||||
f = &facade{
|
||||
_logger: GetLoggerInstance(),
|
||||
}
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// Package logger define log struct of modelRT project
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"runtime"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type logger struct {
|
||||
ctx context.Context
|
||||
traceID string
|
||||
spanID string
|
||||
pSpanID string
|
||||
_logger *zap.Logger
|
||||
}
|
||||
|
||||
func (l *logger) Debug(msg string, kv ...any) {
|
||||
l.log(zapcore.DebugLevel, msg, kv...)
|
||||
}
|
||||
|
||||
func (l *logger) Info(msg string, kv ...any) {
|
||||
l.log(zapcore.InfoLevel, msg, kv...)
|
||||
}
|
||||
|
||||
func (l *logger) Warn(msg string, kv ...any) {
|
||||
l.log(zapcore.WarnLevel, msg, kv...)
|
||||
}
|
||||
|
||||
func (l *logger) Error(msg string, kv ...any) {
|
||||
l.log(zapcore.ErrorLevel, msg, kv...)
|
||||
}
|
||||
|
||||
func (l *logger) log(lvl zapcore.Level, msg string, kv ...any) {
|
||||
fields := makeLogFields(l.ctx, kv...)
|
||||
ce := l._logger.Check(lvl, msg)
|
||||
ce.Write(fields...)
|
||||
}
|
||||
|
||||
func makeLogFields(ctx context.Context, kv ...any) []zap.Field {
|
||||
// Ensure that log information appears in pairs in the form of key-value pairs
|
||||
if len(kv)%2 != 0 {
|
||||
kv = append(kv, "unknown")
|
||||
}
|
||||
|
||||
kv = append(kv, "traceID", ctx.Value("traceID"), "spanID", ctx.Value("spanID"), "pspanID", ctx.Value("pspanID"))
|
||||
|
||||
funcName, file, line := getLoggerCallerInfo()
|
||||
kv = append(kv, "func", funcName, "file", file, "line", line)
|
||||
fields := make([]zap.Field, 0, len(kv)/2)
|
||||
for i := 0; i < len(kv); i += 2 {
|
||||
key := kv[i].(string)
|
||||
value := kv[i+1]
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
fields = append(fields, zap.String(key, v))
|
||||
case int:
|
||||
fields = append(fields, zap.Int(key, v))
|
||||
case int64:
|
||||
fields = append(fields, zap.Int64(key, v))
|
||||
case float32:
|
||||
fields = append(fields, zap.Float32(key, v))
|
||||
case float64:
|
||||
fields = append(fields, zap.Float64(key, v))
|
||||
case bool:
|
||||
fields = append(fields, zap.Bool(key, v))
|
||||
case error:
|
||||
fields = append(fields, zap.Error(v))
|
||||
default:
|
||||
fields = append(fields, zap.Any(key, v))
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// getLoggerCallerInfo define func of return log caller information、method name、file name、line number
|
||||
func getLoggerCallerInfo() (funcName, file string, line int) {
|
||||
pc, file, line, ok := runtime.Caller(4)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
file = path.Base(file)
|
||||
funcName = runtime.FuncForPC(pc).Name()
|
||||
return
|
||||
}
|
||||
|
||||
func New(ctx context.Context) *logger {
|
||||
var traceID, spanID, pSpanID string
|
||||
if ctx.Value("traceID") != nil {
|
||||
traceID = ctx.Value("traceID").(string)
|
||||
}
|
||||
if ctx.Value("spanID") != nil {
|
||||
spanID = ctx.Value("spanID").(string)
|
||||
}
|
||||
if ctx.Value("psapnID") != nil {
|
||||
pSpanID = ctx.Value("pspanID").(string)
|
||||
}
|
||||
|
||||
return &logger{
|
||||
ctx: ctx,
|
||||
traceID: traceID,
|
||||
spanID: spanID,
|
||||
pSpanID: pSpanID,
|
||||
_logger: GetLoggerInstance(),
|
||||
}
|
||||
}
|
||||
|
|
@ -68,15 +68,15 @@ func initLogger(lCfg config.LoggerConfig) *zap.Logger {
|
|||
return logger
|
||||
}
|
||||
|
||||
// InitLoggerInstance return instance of zap logger
|
||||
func InitLoggerInstance(lCfg config.LoggerConfig) *zap.Logger {
|
||||
// InitLoggerInstance define func of return instance of zap logger
|
||||
func InitLoggerInstance(lCfg config.LoggerConfig) {
|
||||
once.Do(func() {
|
||||
_globalLogger = initLogger(lCfg)
|
||||
})
|
||||
return _globalLogger
|
||||
defer _globalLogger.Sync()
|
||||
}
|
||||
|
||||
// GetLoggerInstance returns the global logger instance It's safe for concurrent use.
|
||||
// GetLoggerInstance define func of returns the global logger instance It's safe for concurrent use.
|
||||
func GetLoggerInstance() *zap.Logger {
|
||||
_globalLoggerMu.RLock()
|
||||
logger := _globalLogger
|
||||
25
main.go
25
main.go
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
|
@ -43,7 +42,6 @@ var (
|
|||
var (
|
||||
modelRTConfig config.ModelRTConfig
|
||||
postgresDBClient *gorm.DB
|
||||
zapLogger *zap.Logger
|
||||
alertManager *alert.EventManager
|
||||
)
|
||||
|
||||
|
|
@ -65,8 +63,7 @@ func main() {
|
|||
}()
|
||||
|
||||
// init logger
|
||||
zapLogger = logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
||||
defer zapLogger.Sync()
|
||||
logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
||||
|
||||
// init alert manager
|
||||
_ = alert.InitAlertEventManager()
|
||||
|
|
@ -74,7 +71,7 @@ func main() {
|
|||
// init model parse ants pool
|
||||
parsePool, err := ants.NewPoolWithFunc(modelRTConfig.ParseConcurrentQuantity, pool.ParseFunc)
|
||||
if err != nil {
|
||||
zapLogger.Error("init concurrent parse task pool failed", zap.Error(err))
|
||||
logger.Error(ctx, "init concurrent parse task pool failed", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
defer parsePool.Release()
|
||||
|
|
@ -88,7 +85,7 @@ func main() {
|
|||
// init anchor param ants pool
|
||||
anchorRealTimePool, err := pool.AnchorPoolInit(modelRTConfig.RTDReceiveConcurrentQuantity)
|
||||
if err != nil {
|
||||
zapLogger.Error("init concurrent anchor param task pool failed", zap.Error(err))
|
||||
logger.Error(ctx, "init concurrent anchor param task pool failed", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
defer anchorRealTimePool.Release()
|
||||
|
|
@ -101,16 +98,16 @@ func main() {
|
|||
|
||||
postgresDBClient.Transaction(func(tx *gorm.DB) error {
|
||||
// load circuit diagram from postgres
|
||||
componentTypeMap, err := database.QueryCircuitDiagramComponentFromDB(cancelCtx, tx, parsePool, zapLogger)
|
||||
componentTypeMap, err := database.QueryCircuitDiagramComponentFromDB(cancelCtx, tx, parsePool)
|
||||
if err != nil {
|
||||
zapLogger.Error("load circuit diagrams from postgres failed", zap.Error(err))
|
||||
logger.Error(ctx, "load circuit diagrams from postgres failed", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// TODO 暂时屏蔽完成 swagger 启动测试
|
||||
tree, err := database.QueryTopologicFromDB(ctx, tx, zapLogger, componentTypeMap)
|
||||
tree, err := database.QueryTopologicFromDB(ctx, tx, componentTypeMap)
|
||||
if err != nil {
|
||||
zapLogger.Error("load topologic info from postgres failed", zap.Error(err))
|
||||
logger.Error(ctx, "load topologic info from postgres failed", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
diagram.GlobalTree = tree
|
||||
|
|
@ -125,10 +122,10 @@ func main() {
|
|||
engine.Use(limiter.Middleware)
|
||||
|
||||
// diagram api
|
||||
engine.GET("/model/diagram_load", handler.CircuitDiagramLoadHandler)
|
||||
engine.POST("/model/diagram_create", handler.CircuitDiagramCreateHandler)
|
||||
engine.POST("/model/diagram_update", handler.CircuitDiagramUpdateHandler)
|
||||
engine.POST("/model/diagram_delete", handler.CircuitDiagramDeleteHandler)
|
||||
engine.GET("/diagram/load", handler.CircuitDiagramLoadHandler)
|
||||
engine.POST("/diagram/create", handler.CircuitDiagramCreateHandler)
|
||||
engine.POST("/diagram/update", handler.CircuitDiagramUpdateHandler)
|
||||
engine.POST("/diagram/delete", handler.CircuitDiagramDeleteHandler)
|
||||
|
||||
// real time data api
|
||||
engine.GET("/ws/rtdatas", handler.RealTimeDataReceivehandler)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"modelRT/util"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// StartTrace define func of set trace info from request header
|
||||
func StartTrace() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
traceID := c.Request.Header.Get("traceid")
|
||||
pSpanID := c.Request.Header.Get("spanid")
|
||||
spanID := util.GenerateSpanID(c.Request.RemoteAddr)
|
||||
if traceID == "" { // 如果traceId 为空,证明是链路的发端,把它设置成此次的spanId,发端的spanId是root spanId
|
||||
traceID = spanID // trace 标识整个请求的链路, span则标识链路中的不同服务
|
||||
}
|
||||
c.Set("traceid", traceID)
|
||||
c.Set("spanid", spanID)
|
||||
c.Set("pspanid", pSpanID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GenerateSpanID define func of generate spanID
|
||||
func GenerateSpanID(addr string) string {
|
||||
strAddr := strings.Split(addr, ":")
|
||||
ip := strAddr[0]
|
||||
ipLong, _ := IP2Long(ip)
|
||||
times := uint64(time.Now().UnixNano())
|
||||
rand.NewSource(time.Now().UnixNano())
|
||||
spanID := ((times ^ uint64(ipLong)) << 32) | uint64(rand.Int31())
|
||||
return strconv.FormatUint(spanID, 16)
|
||||
}
|
||||
|
||||
// IP2Long define func of convert ip to unit32 type
|
||||
func IP2Long(ip string) (uint32, error) {
|
||||
ipAddr, err := net.ResolveIPAddr("ip", ip)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return binary.BigEndian.Uint32(ipAddr.IP.To4()), nil
|
||||
}
|
||||
|
||||
// GetTraceInfoFromCtx define func of get trace info from context
|
||||
func GetTraceInfoFromCtx(ctx context.Context) (traceID, spanID, pSpanID string) {
|
||||
if ctx.Value("traceid") != nil {
|
||||
traceID = ctx.Value("traceid").(string)
|
||||
}
|
||||
if ctx.Value("spanid") != nil {
|
||||
spanID = ctx.Value("spanid").(string)
|
||||
}
|
||||
if ctx.Value("pspanid") != nil {
|
||||
pSpanID = ctx.Value("pspanid").(string)
|
||||
}
|
||||
return
|
||||
}
|
||||
Loading…
Reference in New Issue