Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
522 lines
13 KiB
Go
522 lines
13 KiB
Go
package logging
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"runtime"
|
||
"time"
|
||
)
|
||
|
||
// LogLevel 定义日志级别
|
||
type LogLevel int
|
||
|
||
const (
|
||
DEBUG LogLevel = iota
|
||
INFO
|
||
WARN
|
||
ERROR
|
||
FATAL
|
||
)
|
||
|
||
// LogEntry 表示日志条目
|
||
// 该结构体包含结构化日志的所有字段
|
||
type LogEntry struct {
|
||
// 基本字段
|
||
Timestamp time.Time `json:"timestamp"`
|
||
Level LogLevel `json:"level"`
|
||
Message string `json:"message"`
|
||
LevelString string `json:"level_string"`
|
||
|
||
// 位置信息
|
||
File string `json:"file,omitempty"`
|
||
Line int `json:"line,omitempty"`
|
||
Function string `json:"function,omitempty"`
|
||
Stacktrace string `json:"stacktrace,omitempty"`
|
||
|
||
// 上下文信息
|
||
RequestID string `json:"request_id,omitempty"`
|
||
UserID string `json:"user_id,omitempty"`
|
||
SessionID string `json:"session_id,omitempty"`
|
||
IPAddress string `json:"ip_address,omitempty"`
|
||
UserAgent string `json:"user_agent,omitempty"`
|
||
|
||
// 分类信息
|
||
Category string `json:"category,omitempty"`
|
||
Subsystem string `json:"subsystem,omitempty"`
|
||
Component string `json:"component,omitempty"`
|
||
Operation string `json:"operation,omitempty"`
|
||
|
||
// 数据字段
|
||
Fields map[string]interface{} `json:"fields,omitempty"`
|
||
Metrics map[string]interface{} `json:"metrics,omitempty"`
|
||
Tags []string `json:"tags,omitempty"`
|
||
|
||
// 错误信息
|
||
Error error `json:"error,omitempty"`
|
||
ErrorType string `json:"error_type,omitempty"`
|
||
ErrorDetail string `json:"error_detail,omitempty"`
|
||
|
||
// 性能信息
|
||
Duration time.Duration `json:"duration,omitempty"`
|
||
MemoryUsage int64 `json:"memory_usage,omitempty"`
|
||
CPUUsage float64 `json:"cpu_usage,omitempty"`
|
||
|
||
// 请求信息
|
||
Method string `json:"method,omitempty"`
|
||
Path string `json:"path,omitempty"`
|
||
StatusCode int `json:"status_code,omitempty"`
|
||
ResponseSize int64 `json:"response_size,omitempty"`
|
||
|
||
// 自定义属性
|
||
Custom map[string]interface{} `json:"custom,omitempty"`
|
||
}
|
||
|
||
// NewLogEntry 创建新的日志条目
|
||
// 返回包含基本信息的LogEntry结构体
|
||
func NewLogEntry(level LogLevel, message string) *LogEntry {
|
||
return &LogEntry{
|
||
Timestamp: time.Now(),
|
||
Level: level,
|
||
Message: message,
|
||
LevelString: levelToString(level),
|
||
Fields: make(map[string]interface{}),
|
||
Metrics: make(map[string]interface{}),
|
||
Custom: make(map[string]interface{}),
|
||
}
|
||
}
|
||
|
||
// NewLogEntryWithLocation 创建包含位置信息的日志条目
|
||
// 返回包含调用位置信息的LogEntry结构体
|
||
func NewLogEntryWithLocation(level LogLevel, message string) *LogEntry {
|
||
entry := NewLogEntry(level, message)
|
||
entry.captureLocation()
|
||
return entry
|
||
}
|
||
|
||
// captureLocation 捕获调用位置信息
|
||
func (e *LogEntry) captureLocation() {
|
||
_, file, line, ok := runtime.Caller(2) // 跳过2层调用栈
|
||
if ok {
|
||
e.File = file
|
||
e.Line = line
|
||
e.Function = getFunctionName(file, line)
|
||
}
|
||
}
|
||
|
||
// getFunctionName 获取函数名称
|
||
func getFunctionName(file string, line int) string {
|
||
// 简化的函数名获取,实际可以使用更复杂的方法
|
||
return fmt.Sprintf("%s:%d", file, line)
|
||
}
|
||
|
||
// WithField 添加字段到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithField(key string, value interface{}) *LogEntry {
|
||
if e.Fields == nil {
|
||
e.Fields = make(map[string]interface{})
|
||
}
|
||
e.Fields[key] = value
|
||
return e
|
||
}
|
||
|
||
// WithFields 添加多个字段到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithFields(fields map[string]interface{}) *LogEntry {
|
||
if e.Fields == nil {
|
||
e.Fields = make(map[string]interface{})
|
||
}
|
||
for k, v := range fields {
|
||
e.Fields[k] = v
|
||
}
|
||
return e
|
||
}
|
||
|
||
// WithMetric 添加指标到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithMetric(key string, value interface{}) *LogEntry {
|
||
if e.Metrics == nil {
|
||
e.Metrics = make(map[string]interface{})
|
||
}
|
||
e.Metrics[key] = value
|
||
return e
|
||
}
|
||
|
||
// WithTag 添加标签到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithTag(tag string) *LogEntry {
|
||
if e.Tags == nil {
|
||
e.Tags = make([]string, 0)
|
||
}
|
||
e.Tags = append(e.Tags, tag)
|
||
return e
|
||
}
|
||
|
||
// WithTags 添加多个标签到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithTags(tags []string) *LogEntry {
|
||
if e.Tags == nil {
|
||
e.Tags = make([]string, 0)
|
||
}
|
||
e.Tags = append(e.Tags, tags...)
|
||
return e
|
||
}
|
||
|
||
// WithError 添加错误信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithError(err error) *LogEntry {
|
||
if err != nil {
|
||
e.Error = err
|
||
e.ErrorType = fmt.Sprintf("%T", err)
|
||
e.ErrorDetail = err.Error()
|
||
}
|
||
return e
|
||
}
|
||
|
||
// WithDuration 添加持续时间到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithDuration(duration time.Duration) *LogEntry {
|
||
e.Duration = duration
|
||
return e
|
||
}
|
||
|
||
// WithRequest 添加请求信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithRequest(method, path string, statusCode int) *LogEntry {
|
||
e.Method = method
|
||
e.Path = path
|
||
e.StatusCode = statusCode
|
||
return e
|
||
}
|
||
|
||
// WithContext 添加上下文信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithContext(requestID, userID, sessionID string) *LogEntry {
|
||
e.RequestID = requestID
|
||
e.UserID = userID
|
||
e.SessionID = sessionID
|
||
return e
|
||
}
|
||
|
||
// WithNetwork 添加网络信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithNetwork(ip, userAgent string) *LogEntry {
|
||
e.IPAddress = ip
|
||
e.UserAgent = userAgent
|
||
return e
|
||
}
|
||
|
||
// WithCategory 添加分类信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithCategory(category, subsystem, component string) *LogEntry {
|
||
e.Category = category
|
||
e.Subsystem = subsystem
|
||
e.Component = component
|
||
return e
|
||
}
|
||
|
||
// WithOperation 添加操作信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithOperation(operation string) *LogEntry {
|
||
e.Operation = operation
|
||
return e
|
||
}
|
||
|
||
// WithPerformance 添加性能信息到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithPerformance(memory int64, cpu float64) *LogEntry {
|
||
e.MemoryUsage = memory
|
||
e.CPUUsage = cpu
|
||
return e
|
||
}
|
||
|
||
// WithCustom 添加自定义属性到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithCustom(key string, value interface{}) *LogEntry {
|
||
if e.Custom == nil {
|
||
e.Custom = make(map[string]interface{})
|
||
}
|
||
e.Custom[key] = value
|
||
return e
|
||
}
|
||
|
||
// WithResponseSize 添加响应大小到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithResponseSize(size int64) *LogEntry {
|
||
e.ResponseSize = size
|
||
return e
|
||
}
|
||
|
||
// WithStacktrace 添加堆栈跟踪到日志条目
|
||
// 返回更新后的LogEntry实例
|
||
func (e *LogEntry) WithStacktrace(stacktrace string) *LogEntry {
|
||
e.Stacktrace = stacktrace
|
||
return e
|
||
}
|
||
|
||
// String 返回日志条目的字符串表示
|
||
// 实现Stringer接口
|
||
func (e *LogEntry) String() string {
|
||
if e.Level == DEBUG || e.Level == INFO {
|
||
return fmt.Sprintf("[%s] %s", e.LevelString, e.Message)
|
||
}
|
||
return fmt.Sprintf("[%s] %s - %s:%d", e.LevelString, e.Message, e.File, e.Line)
|
||
}
|
||
|
||
// ToJSON 将日志条目转换为JSON格式
|
||
// 返回JSON格式的日志字符串
|
||
func (e *LogEntry) ToJSON() (string, error) {
|
||
data, err := json.Marshal(e)
|
||
if err != nil {
|
||
return "", fmt.Errorf("failed to marshal log entry: %v", err)
|
||
}
|
||
return string(data), nil
|
||
}
|
||
|
||
// ToJSONBytes 将日志条目转换为JSON字节数组
|
||
// 返回JSON格式的日志字节数组
|
||
func (e *LogEntry) ToJSONBytes() ([]byte, error) {
|
||
return json.Marshal(e)
|
||
}
|
||
|
||
// FromJSON 从JSON字符串解析日志条目
|
||
// 解析JSON字符串到LogEntry
|
||
func (e *LogEntry) FromJSON(jsonStr string) error {
|
||
return json.Unmarshal([]byte(jsonStr), e)
|
||
}
|
||
|
||
// ToText 将日志条目转换为文本格式
|
||
// 返回文本格式的日志字符串
|
||
func (e *LogEntry) ToText() string {
|
||
var fields []string
|
||
for k, v := range e.Fields {
|
||
fields = append(fields, fmt.Sprintf("%s=%v", k, v))
|
||
}
|
||
|
||
var metrics []string
|
||
for k, v := range e.Metrics {
|
||
metrics = append(metrics, fmt.Sprintf("%s=%v", k, v))
|
||
}
|
||
|
||
var tags []string
|
||
for _, tag := range e.Tags {
|
||
tags = append(tags, tag)
|
||
}
|
||
|
||
result := fmt.Sprintf("[%s] %s", e.LevelString, e.Message)
|
||
|
||
if len(fields) > 0 {
|
||
result += fmt.Sprintf(" fields=[%s]", joinStrings(fields, ", "))
|
||
}
|
||
|
||
if len(metrics) > 0 {
|
||
result += fmt.Sprintf(" metrics=[%s]", joinStrings(metrics, ", "))
|
||
}
|
||
|
||
if len(tags) > 0 {
|
||
result += fmt.Sprintf(" tags=[%s]", joinStrings(tags, ", "))
|
||
}
|
||
|
||
if e.Duration > 0 {
|
||
result += fmt.Sprintf(" duration=%v", e.Duration)
|
||
}
|
||
|
||
if e.Error != nil {
|
||
result += fmt.Sprintf(" error=%v", e.Error)
|
||
}
|
||
|
||
if e.File != "" {
|
||
result += fmt.Sprintf(" location=%s:%d", e.File, e.Line)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// Validate 验证日志条目的有效性
|
||
// 返回error如果日志条目无效,nil表示有效
|
||
func (e *LogEntry) Validate() error {
|
||
if e.Timestamp.IsZero() {
|
||
return fmt.Errorf("timestamp cannot be zero")
|
||
}
|
||
|
||
if e.Message == "" {
|
||
return fmt.Errorf("message cannot be empty")
|
||
}
|
||
|
||
if e.Level < DEBUG || e.Level > FATAL {
|
||
return fmt.Errorf("invalid log level: %d", e.Level)
|
||
}
|
||
|
||
if e.LevelString != levelToString(e.Level) {
|
||
return fmt.Errorf("level string mismatch: expected %s, got %s",
|
||
levelToString(e.Level), e.LevelString)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Clone 创建日志条目的副本
|
||
// 返回新的LogEntry实例
|
||
func (e *LogEntry) Clone() *LogEntry {
|
||
clone := &LogEntry{
|
||
Timestamp: e.Timestamp,
|
||
Level: e.Level,
|
||
Message: e.Message,
|
||
LevelString: e.LevelString,
|
||
File: e.File,
|
||
Line: e.Line,
|
||
Function: e.Function,
|
||
Stacktrace: e.Stacktrace,
|
||
RequestID: e.RequestID,
|
||
UserID: e.UserID,
|
||
SessionID: e.SessionID,
|
||
IPAddress: e.IPAddress,
|
||
UserAgent: e.UserAgent,
|
||
Category: e.Category,
|
||
Subsystem: e.Subsystem,
|
||
Component: e.Component,
|
||
Operation: e.Operation,
|
||
Error: e.Error,
|
||
ErrorType: e.ErrorType,
|
||
ErrorDetail: e.ErrorDetail,
|
||
Duration: e.Duration,
|
||
MemoryUsage: e.MemoryUsage,
|
||
CPUUsage: e.CPUUsage,
|
||
Method: e.Method,
|
||
Path: e.Path,
|
||
StatusCode: e.StatusCode,
|
||
ResponseSize: e.ResponseSize,
|
||
}
|
||
|
||
// 深拷贝切片
|
||
if e.Tags != nil {
|
||
clone.Tags = make([]string, len(e.Tags))
|
||
copy(clone.Tags, e.Tags)
|
||
}
|
||
|
||
// 深拷贝映射
|
||
if e.Fields != nil {
|
||
clone.Fields = make(map[string]interface{})
|
||
for k, v := range e.Fields {
|
||
clone.Fields[k] = v
|
||
}
|
||
}
|
||
|
||
if e.Metrics != nil {
|
||
clone.Metrics = make(map[string]interface{})
|
||
for k, v := range e.Metrics {
|
||
clone.Metrics[k] = v
|
||
}
|
||
}
|
||
|
||
if e.Custom != nil {
|
||
clone.Custom = make(map[string]interface{})
|
||
for k, v := range e.Custom {
|
||
clone.Custom[k] = v
|
||
}
|
||
}
|
||
|
||
return clone
|
||
}
|
||
|
||
// GetField 获取字段值
|
||
// 返回指定字段的值和是否存在
|
||
func (e *LogEntry) GetField(key string) (interface{}, bool) {
|
||
value, exists := e.Fields[key]
|
||
return value, exists
|
||
}
|
||
|
||
// GetMetric 获取指标值
|
||
// 返回指定指标的值和是否存在
|
||
func (e *LogEntry) GetMetric(key string) (interface{}, bool) {
|
||
value, exists := e.Metrics[key]
|
||
return value, exists
|
||
}
|
||
|
||
// GetCustom 获取自定义属性值
|
||
// 返回指定自定义属性的值和是否存在
|
||
func (e *LogEntry) GetCustom(key string) (interface{}, bool) {
|
||
value, exists := e.Custom[key]
|
||
return value, exists
|
||
}
|
||
|
||
// HasTag 检查是否包含指定标签
|
||
// 返回true如果包含指定标签
|
||
func (e *LogEntry) HasTag(tag string) bool {
|
||
for _, t := range e.Tags {
|
||
if t == tag {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// IsErrorLevel 检查是否为错误级别
|
||
// 返回true如果是ERROR或FATAL级别
|
||
func (e *LogEntry) IsErrorLevel() bool {
|
||
return e.Level >= ERROR
|
||
}
|
||
|
||
// IsDebugLevel 检查是否为调试级别
|
||
// 返回true如果是DEBUG级别
|
||
func (e *LogEntry) IsDebugLevel() bool {
|
||
return e.Level == DEBUG
|
||
}
|
||
|
||
// GetLevelString 获取级别字符串
|
||
// 返回日志级别的字符串表示
|
||
func (e *LogEntry) GetLevelString() string {
|
||
return e.LevelString
|
||
}
|
||
|
||
// GetTimestamp 获取时间戳
|
||
// 返回日志记录的时间戳
|
||
func (e *LogEntry) GetTimestamp() time.Time {
|
||
return e.Timestamp
|
||
}
|
||
|
||
// GetMessage 获取消息
|
||
// 返回日志消息
|
||
func (e *LogEntry) GetMessage() string {
|
||
return e.Message
|
||
}
|
||
|
||
// GetError 获取错误信息
|
||
// 返回错误信息
|
||
func (e *LogEntry) GetError() error {
|
||
return e.Error
|
||
}
|
||
|
||
// GetDuration 获取持续时间
|
||
// 返回操作持续时间
|
||
func (e *LogEntry) GetDuration() time.Duration {
|
||
return e.Duration
|
||
}
|
||
|
||
// 辅助函数
|
||
func levelToString(level LogLevel) string {
|
||
switch level {
|
||
case DEBUG:
|
||
return "DEBUG"
|
||
case INFO:
|
||
return "INFO"
|
||
case WARN:
|
||
return "WARN"
|
||
case ERROR:
|
||
return "ERROR"
|
||
case FATAL:
|
||
return "FATAL"
|
||
default:
|
||
return "UNKNOWN"
|
||
}
|
||
}
|
||
|
||
func joinStrings(strings []string, separator string) string {
|
||
result := ""
|
||
for i, s := range strings {
|
||
if i > 0 {
|
||
result += separator
|
||
}
|
||
result += s
|
||
}
|
||
return result
|
||
} |