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 {
|
type ModelParseConfig struct {
|
||||||
ComponentInfo orm.Component
|
ComponentInfo orm.Component
|
||||||
Context context.Context
|
Ctx context.Context
|
||||||
AnchorChan chan AnchorParamConfig
|
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
|
return logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLoggerInstance return instance of zap logger
|
// InitLoggerInstance define func of return instance of zap logger
|
||||||
func InitLoggerInstance(lCfg config.LoggerConfig) *zap.Logger {
|
func InitLoggerInstance(lCfg config.LoggerConfig) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
_globalLogger = initLogger(lCfg)
|
_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 {
|
func GetLoggerInstance() *zap.Logger {
|
||||||
_globalLoggerMu.RLock()
|
_globalLoggerMu.RLock()
|
||||||
logger := _globalLogger
|
logger := _globalLogger
|
||||||
25
main.go
25
main.go
|
|
@ -24,7 +24,6 @@ import (
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"go.uber.org/zap"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -43,7 +42,6 @@ var (
|
||||||
var (
|
var (
|
||||||
modelRTConfig config.ModelRTConfig
|
modelRTConfig config.ModelRTConfig
|
||||||
postgresDBClient *gorm.DB
|
postgresDBClient *gorm.DB
|
||||||
zapLogger *zap.Logger
|
|
||||||
alertManager *alert.EventManager
|
alertManager *alert.EventManager
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -65,8 +63,7 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// init logger
|
// init logger
|
||||||
zapLogger = logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
logger.InitLoggerInstance(modelRTConfig.LoggerConfig)
|
||||||
defer zapLogger.Sync()
|
|
||||||
|
|
||||||
// init alert manager
|
// init alert manager
|
||||||
_ = alert.InitAlertEventManager()
|
_ = alert.InitAlertEventManager()
|
||||||
|
|
@ -74,7 +71,7 @@ func main() {
|
||||||
// init model parse ants pool
|
// init model parse ants pool
|
||||||
parsePool, err := ants.NewPoolWithFunc(modelRTConfig.ParseConcurrentQuantity, pool.ParseFunc)
|
parsePool, err := ants.NewPoolWithFunc(modelRTConfig.ParseConcurrentQuantity, pool.ParseFunc)
|
||||||
if err != nil {
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer parsePool.Release()
|
defer parsePool.Release()
|
||||||
|
|
@ -88,7 +85,7 @@ func main() {
|
||||||
// init anchor param ants pool
|
// init anchor param ants pool
|
||||||
anchorRealTimePool, err := pool.AnchorPoolInit(modelRTConfig.RTDReceiveConcurrentQuantity)
|
anchorRealTimePool, err := pool.AnchorPoolInit(modelRTConfig.RTDReceiveConcurrentQuantity)
|
||||||
if err != nil {
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer anchorRealTimePool.Release()
|
defer anchorRealTimePool.Release()
|
||||||
|
|
@ -101,16 +98,16 @@ func main() {
|
||||||
|
|
||||||
postgresDBClient.Transaction(func(tx *gorm.DB) error {
|
postgresDBClient.Transaction(func(tx *gorm.DB) error {
|
||||||
// load circuit diagram from postgres
|
// load circuit diagram from postgres
|
||||||
componentTypeMap, err := database.QueryCircuitDiagramComponentFromDB(cancelCtx, tx, parsePool, zapLogger)
|
componentTypeMap, err := database.QueryCircuitDiagramComponentFromDB(cancelCtx, tx, parsePool)
|
||||||
if err != nil {
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 暂时屏蔽完成 swagger 启动测试
|
// TODO 暂时屏蔽完成 swagger 启动测试
|
||||||
tree, err := database.QueryTopologicFromDB(ctx, tx, zapLogger, componentTypeMap)
|
tree, err := database.QueryTopologicFromDB(ctx, tx, componentTypeMap)
|
||||||
if err != nil {
|
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)
|
panic(err)
|
||||||
}
|
}
|
||||||
diagram.GlobalTree = tree
|
diagram.GlobalTree = tree
|
||||||
|
|
@ -125,10 +122,10 @@ func main() {
|
||||||
engine.Use(limiter.Middleware)
|
engine.Use(limiter.Middleware)
|
||||||
|
|
||||||
// diagram api
|
// diagram api
|
||||||
engine.GET("/model/diagram_load", handler.CircuitDiagramLoadHandler)
|
engine.GET("/diagram/load", handler.CircuitDiagramLoadHandler)
|
||||||
engine.POST("/model/diagram_create", handler.CircuitDiagramCreateHandler)
|
engine.POST("/diagram/create", handler.CircuitDiagramCreateHandler)
|
||||||
engine.POST("/model/diagram_update", handler.CircuitDiagramUpdateHandler)
|
engine.POST("/diagram/update", handler.CircuitDiagramUpdateHandler)
|
||||||
engine.POST("/model/diagram_delete", handler.CircuitDiagramDeleteHandler)
|
engine.POST("/diagram/delete", handler.CircuitDiagramDeleteHandler)
|
||||||
|
|
||||||
// real time data api
|
// real time data api
|
||||||
engine.GET("/ws/rtdatas", handler.RealTimeDataReceivehandler)
|
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