218 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package logger ...
 | |
| //
 | |
| // Description : logger ...
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 2022-06-12 18:39
 | |
| package logger
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 
 | |
| 	"git.zhangdeman.cn/zhangdeman/consts"
 | |
| 	"git.zhangdeman.cn/zhangdeman/network/util"
 | |
| 	"git.zhangdeman.cn/zhangdeman/serialize"
 | |
| 	"git.zhangdeman.cn/zhangdeman/wrapper/op_any"
 | |
| 
 | |
| 	"git.zhangdeman.cn/zhangdeman/websocket/storage"
 | |
| 	"go.uber.org/zap"
 | |
| 	"go.uber.org/zap/zapcore"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	wsLoggerConnect storage.IConnection // ws 日志连接管理实例
 | |
| )
 | |
| 
 | |
| // SetWsLoggerConnect 设置ws connect
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 15:20 2024/7/23
 | |
| func SetWsLoggerConnect(connect storage.IConnection) {
 | |
| 	wsLoggerConnect = connect
 | |
| }
 | |
| 
 | |
| // GetWsLoggConnect 获取ws连接
 | |
| //
 | |
| // Author : go_developer@163.com<白茶清欢>
 | |
| //
 | |
| // Date : 15:34 2024/7/23
 | |
| func GetWsLoggConnect() storage.IConnection {
 | |
| 	return wsLoggerConnect
 | |
| }
 | |
| 
 | |
| // LogData 记录日志数据
 | |
| type LogData struct {
 | |
| 	Env            string         `json:"env"`             // 运行环境
 | |
| 	Uri            string         `json:"uri"`             // 请求的接口
 | |
| 	TraceID        string         `json:"trace_id"`        // 请求的trace_id
 | |
| 	UserID         string         `json:"user_id"`         // 用户ID
 | |
| 	OperateMode    string         `json:"operate_mode"`    // 操作模式(PC/APP/PAD等)
 | |
| 	LogType        string         `json:"log_type"`        // 日志类型
 | |
| 	CodeVersion    string         `json:"code_version"`    // 代码版本(可以设置为git commit id)
 | |
| 	ServiceVersion string         `json:"service_version"` // 服务本身的版本
 | |
| 	ClientIp       string         `json:"client_ip"`       // 客户端IP
 | |
| 	ServerIp       string         `json:"server_ip"`       // 服务器IP
 | |
| 	Hostname       string         `json:"hostname"`        // 服务器主机名
 | |
| 	Code           string         `json:"code"`            // 日志分类标记码
 | |
| 	Data           map[string]any `json:"data"`            // 扩展记录的数据, 会展开一层进行记录
 | |
| }
 | |
| 
 | |
| // ToFieldList 转换为 zap.Field 列表
 | |
| func (ld *LogData) ToFieldList() []zap.Field {
 | |
| 	var (
 | |
| 		fieldList  []zap.Field
 | |
| 		mapLogData map[string]any
 | |
| 	)
 | |
| 	serialize.JSON.TransitionIgnoreError(ld, &mapLogData)
 | |
| 	for k, v := range mapLogData {
 | |
| 		fieldList = append(fieldList, zap.Any(k, v))
 | |
| 	}
 | |
| 	return fieldList
 | |
| }
 | |
| 
 | |
| // InputLogConfig 输入的日志配置
 | |
| type InputLogConfig struct {
 | |
| 	Name             string      `json:"name" yaml:"name"`                             // 日志文件名
 | |
| 	Path             string      `json:"path" yaml:"path"`                             // 日志文件路径
 | |
| 	TimeIntervalType LogSplit    `json:"time_interval_type" yaml:"time_interval_type"` // 日志切割规则
 | |
| 	DivisionChar     string      `json:"division_char" yaml:"division_char"`           // 文件名分隔符
 | |
| 	LogLevel         LogLevel    `json:"log_level" yaml:"log_level"`                   // 日志等级
 | |
| 	Console          bool        `json:"console" yaml:"console"`                       // 是否进行控制台日志输出
 | |
| 	UseJson          bool        `json:"use_json" yaml:"use_json"`                     // 日志是否使用JSON格式
 | |
| 	FileLine         bool        `json:"file_line" yaml:"file_line"`                   // 日志是否打印行号
 | |
| 	MessageKey       string      `json:"message_key" yaml:"message_key"`               // message 字段
 | |
| 	LevelKey         string      `json:"level_key" yaml:"level_key"`                   // level 字段
 | |
| 	TimeKey          string      `json:"time_key" yaml:"time_key"`                     // 时间字段
 | |
| 	CallerKey        string      `json:"caller_key" yaml:"caller_key"`                 // 记录日志的文件的代码行数
 | |
| 	UseShortFile     bool        `json:"use_short_file" yaml:"use_short_file"`         // 是否使用短文件格式
 | |
| 	CallerSkip       int         `json:"caller_skip" yaml:"caller_skip"`               // 日志记录的文件跳过多少层
 | |
| 	MaxAge           int64       `json:"max_age" yaml:"max_age"`                       // 日志最长保存时间, 单位 : 秒
 | |
| 	ZincSyncConfig   *ZincConfig `json:"zinc_sync_config" yaml:"zinc_sync_config"`     // 日志同步至zinc的配置
 | |
| }
 | |
| 
 | |
| // NewLogData ...
 | |
| func NewLogData(ctx context.Context, logType string, code string, logData map[string]any) *LogData {
 | |
| 	hostname, _ := os.Hostname()
 | |
| 	if nil == ctx {
 | |
| 		ctx = context.Background()
 | |
| 	}
 | |
| 	commonLogData := &LogData{
 | |
| 		Env:            getStrVal(ctx, consts.GinEnvField),
 | |
| 		Uri:            getStrVal(ctx, consts.GinRequestURIField),
 | |
| 		TraceID:        getStrVal(ctx, consts.GinTraceIDField),
 | |
| 		UserID:         getStrVal(ctx, consts.GinUserIDField),
 | |
| 		OperateMode:    getStrVal(ctx, consts.GinOperateModeField),
 | |
| 		LogType:        logType,
 | |
| 		CodeVersion:    getStrVal(ctx, consts.GinCodeVersionField),
 | |
| 		ServiceVersion: getStrVal(ctx, consts.GinServiceVersionField),
 | |
| 		ClientIp:       getStrVal(ctx, consts.GinClientIpField),
 | |
| 		ServerIp:       util.IP.GetHostIP(),
 | |
| 		Hostname:       hostname,
 | |
| 		Code:           code,
 | |
| 		Data:           logData,
 | |
| 	}
 | |
| 	return commonLogData
 | |
| }
 | |
| 
 | |
| func getStrVal(ctx context.Context, key string) string {
 | |
| 	val := ctx.Value(key)
 | |
| 	if nil != val {
 | |
| 		return op_any.AnyDataType(val).ToString()
 | |
| 	}
 | |
| 	if v := ctx.Value(consts.GinContextDataField); nil != v {
 | |
| 		if data, ok := v.(map[string]any); ok {
 | |
| 			if searchVal, exist := data[key]; exist && nil != searchVal {
 | |
| 				return fmt.Sprintf("%v", searchVal)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return ""
 | |
| }
 | |
| 
 | |
| // GetLogInstanceFromInputConfig 从输入配置获取日志实例
 | |
| func GetLogInstanceFromInputConfig(logConf *InputLogConfig) (*zap.Logger, error) {
 | |
| 	if nil == logConf {
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 	logConfList := []SetLoggerOptionFunc{
 | |
| 		WithCallerSkip(logConf.CallerSkip),
 | |
| 		WithCaller(),
 | |
| 		WithUseJsonFormat(logConf.UseJson),
 | |
| 		WithShortCaller(logConf.UseShortFile),
 | |
| 	}
 | |
| 	if logConf.Console {
 | |
| 		logConfList = append(logConfList, WithConsoleOutput())
 | |
| 	}
 | |
| 	// 配置zinc日志同步
 | |
| 	logConfList = append(logConfList, WithZincLogCollect(logConf.ZincSyncConfig))
 | |
| 
 | |
| 	var (
 | |
| 		err            error
 | |
| 		loggerInstance *zap.Logger
 | |
| 		splitConfig    *RotateLogConfig
 | |
| 	)
 | |
| 	if splitConfig, err = NewRotateLogConfig(
 | |
| 		logConf.Path,
 | |
| 		logConf.Name,
 | |
| 		WithDivisionChar(logConf.DivisionChar),
 | |
| 		WithTimeIntervalType(logConf.TimeIntervalType),
 | |
| 		WithMaxAge(logConf.MaxAge)); nil != err {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if loggerInstance, err = NewLogger(logConf.LogLevel, splitConfig, logConfList...); nil != err {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return loggerInstance, nil
 | |
| }
 | |
| 
 | |
| // inputLevel2ZapLevel 输入日志等级转化为zap日志等级
 | |
| func inputLevel2ZapLevel(inputLoggerLevel LogLevel) zapcore.Level {
 | |
| 	inputLoggerLevel = LogLevel(strings.ToUpper(inputLoggerLevel.String()))
 | |
| 	if !inputLoggerLevel.IsValid() {
 | |
| 		// 非法的日志等级, 自动重定向为 info 级别
 | |
| 		inputLoggerLevel = LogLevelInfo
 | |
| 	}
 | |
| 	loggerLevel := zapcore.DebugLevel
 | |
| 	switch inputLoggerLevel {
 | |
| 	case LogLevelDebug:
 | |
| 		loggerLevel = zapcore.DebugLevel
 | |
| 	case LogLevelInfo:
 | |
| 		loggerLevel = zapcore.InfoLevel
 | |
| 	case LogLevelWarn:
 | |
| 		loggerLevel = zapcore.WarnLevel
 | |
| 	case LogLevelError:
 | |
| 		loggerLevel = zapcore.ErrorLevel
 | |
| 	case LogLevelPanic:
 | |
| 		loggerLevel = zapcore.PanicLevel
 | |
| 	}
 | |
| 	return loggerLevel
 | |
| }
 | |
| 
 | |
| // ZincConfig zinc服务配置
 | |
| type ZincConfig struct {
 | |
| 	Authorization string `json:"authorization" dc:"授权secret,生成方式base64(user:password)"`
 | |
| 	Domain        string `json:"domain" dc:"zinc服务域名"`
 | |
| 	Timeout       int    `json:"timeout" dc:"超时时间,单位毫秒,默认5000"`
 | |
| 	Async         bool   `json:"async" dc:"数据异步写入"`
 | |
| 	Index         string `json:"index" dc:"日志使用的索引"`
 | |
| 	CreateType    string `json:"create_type" dc:"日志同步的类型: single - 单个同步 batch - 批量创建"`
 | |
| 	BufferSize    int    `json:"buffer_size" dc:"批量创建时, 数据缓存buffer大小, 默认1000"`
 | |
| 	ForceSyncTime int    `json:"force_sync_time" dc:"批量同步日志时,强制同步的时间间隔,buffer没满也会强制同步, 单位: 秒"`
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	DefaultTimeout           = 5000 // 默认超时时间
 | |
| 	DefaultBufferSize        = 1000 // 默认buffer大小
 | |
| 	DefaultForceFlushLogTime = 1000 // 强制刷新日志的时间间隔, 单位毫秒
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	CreateTypeSingle = "single" // 逐条日志同步
 | |
| 	CreateTypeBatch  = "batch"  // 批量日志同步
 | |
| )
 |