Files
Rogee 7fcabe0225
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
first commit
2025-09-28 10:05:07 +08:00

522 lines
13 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}