feat: add logging and collector implementations
- Introduced `hertzx` package with `NewHertz` function for server initialization. - Implemented `logx` package with various log collectors: Console, Loki, Elasticsearch, and Prometheus. - Added `Logger` struct to manage logging levels and collectors. - Created environment variable loading functionality in `osx` package to support configuration. - Enhanced logging capabilities with structured log entries and asynchronous collection.
This commit is contained in:
187
logx/collector.go
Normal file
187
logx/collector.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.liteyuki.org/LiteyukiStudio/folium/osx"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
type ConsoleCollector struct{}
|
||||
|
||||
func NewConsoleCollector() *ConsoleCollector { return &ConsoleCollector{} }
|
||||
|
||||
func (c *ConsoleCollector) Collect(ctx context.Context, e Entry) error {
|
||||
// 简单输出 JSON 行,供外部 log collector(Fluent/FluentBit)抓取
|
||||
b, _ := json.Marshal(e)
|
||||
fmt.Fprintln(os.Stdout, string(b))
|
||||
return nil
|
||||
}
|
||||
func (c *ConsoleCollector) Close() error { return nil }
|
||||
|
||||
// LokiCollector:把日志推送到 Loki push API(基本实现)
|
||||
type LokiCollector struct {
|
||||
url string
|
||||
client *http.Client
|
||||
labels string // e.g. `{job="myapp"}`
|
||||
}
|
||||
|
||||
func NewLokiCollector(collectorURL string, labels map[string]string) *LokiCollector {
|
||||
// 构建 labels 字符串
|
||||
lbl := "{"
|
||||
first := true
|
||||
for k, v := range labels {
|
||||
if !first {
|
||||
lbl += ","
|
||||
}
|
||||
lbl += fmt.Sprintf("%s=\"%s\"", k, v)
|
||||
first = false
|
||||
}
|
||||
lbl += "}"
|
||||
return &LokiCollector{
|
||||
url: collectorURL,
|
||||
client: &http.Client{Timeout: 5 * time.Second},
|
||||
labels: lbl,
|
||||
}
|
||||
}
|
||||
|
||||
type lokiStream struct {
|
||||
Stream map[string]string `json:"stream"`
|
||||
Values [][2]string `json:"values"`
|
||||
}
|
||||
type lokiPush struct {
|
||||
Streams []lokiStream `json:"streams"`
|
||||
}
|
||||
|
||||
func (c *LokiCollector) Collect(ctx context.Context, e Entry) error {
|
||||
// Loki requires timestamp in nanoseconds as string
|
||||
ts := fmt.Sprintf("%d", e.Time.UnixNano())
|
||||
lineB, _ := json.Marshal(e)
|
||||
stream := lokiStream{
|
||||
Stream: map[string]string{"level": string(e.Level)},
|
||||
Values: [][2]string{{ts, string(lineB)}},
|
||||
}
|
||||
push := lokiPush{Streams: []lokiStream{stream}}
|
||||
body, _ := json.Marshal(push)
|
||||
req, _ := http.NewRequestWithContext(ctx, "POST", c.url+"/loki/api/v1/push", bytes.NewBuffer(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("loki push status %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *LokiCollector) Close() error { return nil }
|
||||
|
||||
// ESCollector:把日志写入 Elasticsearch 简单实现(使用 index API)
|
||||
type ESCollector struct {
|
||||
url string // e.g. http://es:9200
|
||||
index string // index name
|
||||
client *http.Client
|
||||
auth *basicAuth // optional
|
||||
}
|
||||
|
||||
type basicAuth struct {
|
||||
user string
|
||||
pass string
|
||||
}
|
||||
|
||||
func NewESCollector(url, index string, authUser, authPass string) *ESCollector {
|
||||
var auth *basicAuth
|
||||
if authUser != "" {
|
||||
auth = &basicAuth{user: authUser, pass: authPass}
|
||||
}
|
||||
return &ESCollector{
|
||||
url: url,
|
||||
index: index,
|
||||
client: &http.Client{Timeout: 5 * time.Second},
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ESCollector) Collect(ctx context.Context, e Entry) error {
|
||||
b, _ := json.Marshal(e)
|
||||
endpoint := fmt.Sprintf("%s/%s/_doc", c.url, c.index)
|
||||
req, _ := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(b))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
if c.auth != nil {
|
||||
req.SetBasicAuth(c.auth.user, c.auth.pass)
|
||||
}
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("es index status %d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *ESCollector) Close() error { return nil }
|
||||
|
||||
// PromCollector:记录日志计数到 Prometheus(便于监控日志量)
|
||||
type PromCollector struct {
|
||||
counter *prometheus.CounterVec
|
||||
}
|
||||
|
||||
func NewPromCollector(namespace string) *PromCollector {
|
||||
cv := prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Name: "app_logs_total",
|
||||
Help: "Total application logs by level",
|
||||
}, []string{"level"})
|
||||
// 忽略重复注册错误(如果已存在,使用已注册的)
|
||||
_ = prometheus.Register(cv)
|
||||
return &PromCollector{
|
||||
counter: cv,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PromCollector) Collect(ctx context.Context, e Entry) error {
|
||||
p.counter.WithLabelValues(string(e.Level)).Inc()
|
||||
return nil
|
||||
}
|
||||
func (p *PromCollector) Close() error { return nil }
|
||||
|
||||
// LoadCollectorsFromEnv 根据环境变量 LOG_COLLECTORS 加载对应的 collectors
|
||||
func LoadCollectorsFromEnv() []Collector {
|
||||
collectors := osx.GetEnv("LOG_COLLECTORS", "")
|
||||
var result []Collector
|
||||
if collectors == "" {
|
||||
return result
|
||||
}
|
||||
types := bytes.Split([]byte(collectors), []byte(","))
|
||||
for _, t := range types {
|
||||
switch string(bytes.TrimSpace(t)) {
|
||||
case "console":
|
||||
result = append(result, NewConsoleCollector())
|
||||
case "loki":
|
||||
lokiURL := osx.GetEnv("LOKI_URL", "http://localhost:3100")
|
||||
labels := map[string]string{
|
||||
"job": osx.GetEnv("LOKI_JOB", "myapp"),
|
||||
}
|
||||
result = append(result, NewLokiCollector(lokiURL, labels))
|
||||
case "elasticsearch":
|
||||
esURL := osx.GetEnv("ES_URL", "http://localhost:9200")
|
||||
esIndex := osx.GetEnv("ES_INDEX", "app-logs")
|
||||
esUser := osx.GetEnv("ES_USER", "")
|
||||
esPass := osx.GetEnv("ES_PASS", "")
|
||||
result = append(result, NewESCollector(esURL, esIndex, esUser, esPass))
|
||||
case "prometheus":
|
||||
namespace := osx.GetEnv("PROM_NAMESPACE", "myapp")
|
||||
result = append(result, NewPromCollector(namespace))
|
||||
// 可扩展更多 collector 类型
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
442
logx/log.go
Normal file
442
logx/log.go
Normal file
@@ -0,0 +1,442 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.liteyuki.org/LiteyukiStudio/folium/osx"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// 支持的日志等级
|
||||
type Level string
|
||||
|
||||
const (
|
||||
LevelTrace Level = "trace"
|
||||
LevelDebug Level = "debug"
|
||||
LevelInfo Level = "info"
|
||||
LevelWarn Level = "warn"
|
||||
LevelError Level = "error"
|
||||
LevelFatal Level = "fatal"
|
||||
LevelPanic Level = "panic"
|
||||
)
|
||||
|
||||
// Entry 表示一条日志的可传输结构
|
||||
type Entry struct {
|
||||
Level Level `json:"level"`
|
||||
Time time.Time `json:"time"`
|
||||
Msg string `json:"msg"`
|
||||
Fields map[string]interface{} `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// Collector 是外部收集器接口(用户可实现)
|
||||
type Collector interface {
|
||||
Collect(ctx context.Context, e Entry) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Logger 支持本地打印并把日志发送到已注册的 collectors
|
||||
type Logger struct {
|
||||
zap *zap.Logger
|
||||
collectors []Collector
|
||||
mu sync.RWMutex
|
||||
wg sync.WaitGroup
|
||||
|
||||
minLevel Level // 低于此级别的日志将被忽略
|
||||
}
|
||||
|
||||
// 全局单例
|
||||
var (
|
||||
Default *Logger
|
||||
defaultOnce sync.Once
|
||||
)
|
||||
|
||||
// buildLoggerFromEnv 基于环境构造 Logger(不设置全局变量)
|
||||
func buildLoggerFromEnv() *Logger {
|
||||
// 输出格式
|
||||
output := strings.ToLower(osx.GetEnv("LOG_OUTPUT", "console"))
|
||||
cfg := zap.NewProductionConfig()
|
||||
if output == "json" {
|
||||
cfg.Encoding = "json"
|
||||
} else {
|
||||
cfg.Encoding = "console"
|
||||
}
|
||||
cfg.EncoderConfig.TimeKey = "ts"
|
||||
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
// 让 zap 本身也服从 LOG_LEVEL
|
||||
levelStr := strings.ToLower(osx.GetEnv("LOG_LEVEL", osx.GetEnv("LOG_MIN_LEVEL", "info")))
|
||||
var zapLevel zapcore.Level
|
||||
switch levelStr {
|
||||
case "trace", "debug":
|
||||
zapLevel = zapcore.DebugLevel
|
||||
case "info":
|
||||
zapLevel = zapcore.InfoLevel
|
||||
case "warn", "warning":
|
||||
zapLevel = zapcore.WarnLevel
|
||||
case "error":
|
||||
zapLevel = zapcore.ErrorLevel
|
||||
case "fatal":
|
||||
zapLevel = zapcore.FatalLevel
|
||||
case "panic":
|
||||
zapLevel = zapcore.PanicLevel
|
||||
default:
|
||||
zapLevel = zapcore.InfoLevel
|
||||
}
|
||||
cfg.Level = zap.NewAtomicLevelAt(zapLevel)
|
||||
|
||||
// 可通过环境关闭 stacktrace 输出
|
||||
if strings.ToLower(osx.GetEnv("LOG_DISABLE_STACKTRACE", "false")) == "true" {
|
||||
cfg.DisableStacktrace = true
|
||||
}
|
||||
|
||||
zl, _ := cfg.Build()
|
||||
|
||||
l := &Logger{
|
||||
zap: zl,
|
||||
collectors: nil,
|
||||
minLevel: LevelInfo,
|
||||
}
|
||||
|
||||
// 最低日志级别(同步 env)
|
||||
switch levelStr {
|
||||
case "trace":
|
||||
l.minLevel = LevelTrace
|
||||
case "debug":
|
||||
l.minLevel = LevelDebug
|
||||
case "info":
|
||||
l.minLevel = LevelInfo
|
||||
case "warn", "warning":
|
||||
l.minLevel = LevelWarn
|
||||
case "error":
|
||||
l.minLevel = LevelError
|
||||
case "fatal":
|
||||
l.minLevel = LevelFatal
|
||||
case "panic":
|
||||
l.minLevel = LevelPanic
|
||||
default:
|
||||
l.minLevel = LevelInfo
|
||||
}
|
||||
|
||||
// 从环境加载并注册 collectors(实现位于 collector.go)
|
||||
cols := LoadCollectorsFromEnv()
|
||||
for _, c := range cols {
|
||||
l.RegisterCollector(c)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// InitLogger 初始化全局单例(只第一次生效),返回单例
|
||||
func InitLogger() *Logger {
|
||||
defaultOnce.Do(func() {
|
||||
Default = buildLoggerFromEnv()
|
||||
})
|
||||
return Default
|
||||
}
|
||||
|
||||
// GetLogger 返回全局单例,如果尚未初始化则会自动 InitLogger
|
||||
func GetLogger() *Logger {
|
||||
return InitLogger()
|
||||
}
|
||||
|
||||
// 删除旧的 New / NewDefault,保留 New(...) 风格的局部 logger 创建函数改名为 NewLocal(可选)
|
||||
func NewLocal(zl *zap.Logger) *Logger {
|
||||
if zl == nil {
|
||||
// 使用一个轻量 zap 实例,不触碰全局单例
|
||||
cfg := zap.NewProductionConfig()
|
||||
cfg.Encoding = "console"
|
||||
cfg.EncoderConfig.TimeKey = "ts"
|
||||
cfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
zl2, _ := cfg.Build()
|
||||
return &Logger{
|
||||
zap: zl2,
|
||||
minLevel: LevelDebug,
|
||||
collectors: nil,
|
||||
}
|
||||
}
|
||||
return &Logger{
|
||||
zap: zl,
|
||||
minLevel: LevelDebug,
|
||||
collectors: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterCollector 在运行时注册一个 Collector(线程安全)
|
||||
func (l *Logger) RegisterCollector(c Collector) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.collectors = append(l.collectors, c)
|
||||
}
|
||||
|
||||
// UnregisterCollector 注销已注册的 Collector(按指针相等匹配)
|
||||
func (l *Logger) UnregisterCollector(c Collector) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
for i, col := range l.collectors {
|
||||
if col == c {
|
||||
l.collectors = append(l.collectors[:i], l.collectors[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ListCollectors 返回当前已注册的 collectors(副本,线程安全)
|
||||
func (l *Logger) ListCollectors() []Collector {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
cp := make([]Collector, len(l.collectors))
|
||||
copy(cp, l.collectors)
|
||||
return cp
|
||||
}
|
||||
|
||||
// Close 关闭所有 collectors(阻塞直到异步发送结束)
|
||||
func (l *Logger) Close() error {
|
||||
l.mu.RLock()
|
||||
collectors := append([]Collector(nil), l.collectors...)
|
||||
l.mu.RUnlock()
|
||||
|
||||
// 等待 async sending 完成
|
||||
l.wg.Wait()
|
||||
|
||||
var firstErr error
|
||||
for _, c := range collectors {
|
||||
if err := c.Close(); err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
}
|
||||
_ = l.zap.Sync()
|
||||
return firstErr
|
||||
}
|
||||
|
||||
// SetLevel 设置最低日志级别,低于该级别的日志将被忽略
|
||||
func (l *Logger) SetLevel(level Level) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.minLevel = level
|
||||
}
|
||||
|
||||
// level 排序辅助
|
||||
var levelOrder = map[Level]int{
|
||||
LevelTrace: 0,
|
||||
LevelDebug: 1,
|
||||
LevelInfo: 2,
|
||||
LevelWarn: 3,
|
||||
LevelError: 4,
|
||||
LevelFatal: 5,
|
||||
LevelPanic: 6,
|
||||
}
|
||||
|
||||
func (l *Logger) log(ctx context.Context, level Level, msg string, fields map[string]interface{}) {
|
||||
// 级别过滤
|
||||
l.mu.RLock()
|
||||
min := l.minLevel
|
||||
l.mu.RUnlock()
|
||||
if levelOrder[level] < levelOrder[min] {
|
||||
return
|
||||
}
|
||||
|
||||
// 本地打印(保持原有行为),并尽量保持 trace/level 字段
|
||||
switch level {
|
||||
case LevelTrace:
|
||||
l.zap.Debug(msg, zap.String("level", string(LevelTrace)), zap.Any("fields", fields))
|
||||
case LevelDebug:
|
||||
l.zap.Debug(msg, zap.Any("fields", fields))
|
||||
case LevelInfo:
|
||||
l.zap.Info(msg, zap.Any("fields", fields))
|
||||
case LevelWarn:
|
||||
l.zap.Warn(msg, zap.Any("fields", fields))
|
||||
case LevelError:
|
||||
l.zap.Error(msg, zap.Any("fields", fields))
|
||||
case LevelFatal:
|
||||
// Fatal 会调用 os.Exit(1)
|
||||
l.zap.Fatal(msg, zap.Any("fields", fields))
|
||||
case LevelPanic:
|
||||
// Panic 会 panic
|
||||
l.zap.Panic(msg, zap.Any("fields", fields))
|
||||
default:
|
||||
l.zap.Info(msg, zap.Any("level", level), zap.Any("fields", fields))
|
||||
}
|
||||
|
||||
// 向 collectors 异步发送
|
||||
l.mu.RLock()
|
||||
collectors := append([]Collector(nil), l.collectors...)
|
||||
l.mu.RUnlock()
|
||||
|
||||
if len(collectors) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
e := Entry{
|
||||
Level: level,
|
||||
Time: time.Now(),
|
||||
Msg: msg,
|
||||
Fields: fields,
|
||||
}
|
||||
|
||||
for _, c := range collectors {
|
||||
c := c
|
||||
l.wg.Add(1)
|
||||
go func() {
|
||||
defer l.wg.Done()
|
||||
ctx2, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
if err := c.Collect(ctx2, e); err != nil {
|
||||
// collectors 的错误不影响主流程,记录到本地日志
|
||||
l.zap.Warn("collector collect error", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// 便捷方法(增加 Trace, Fatal, Panic)
|
||||
// 保留 Logger 的方法签名:需要 ctx
|
||||
func (l *Logger) Trace(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelTrace, msg, fields)
|
||||
}
|
||||
func (l *Logger) Debug(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelDebug, msg, fields)
|
||||
}
|
||||
func (l *Logger) Info(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelInfo, msg, fields)
|
||||
}
|
||||
func (l *Logger) Warn(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelWarn, msg, fields)
|
||||
}
|
||||
func (l *Logger) Error(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelError, msg, fields)
|
||||
}
|
||||
func (l *Logger) Fatal(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelFatal, msg, fields)
|
||||
}
|
||||
func (l *Logger) Panic(ctx context.Context, msg string, fields map[string]interface{}) {
|
||||
l.log(ctx, LevelPanic, msg, fields)
|
||||
}
|
||||
|
||||
// SimpleLogger 提供不带 ctx 的简洁 API(可选 fields)
|
||||
type SimpleLogger struct {
|
||||
parent *Logger
|
||||
}
|
||||
|
||||
func (s *SimpleLogger) Trace(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Trace(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Debug(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Debug(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Info(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Info(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Warn(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Warn(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Error(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Error(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Fatal(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Fatal(context.Background(), msg, f)
|
||||
}
|
||||
func (s *SimpleLogger) Panic(msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
s.parent.Panic(context.Background(), msg, f)
|
||||
}
|
||||
|
||||
// Simple 返回一个绑定到当前 Logger 的 SimpleLogger(不创建新实例)
|
||||
func (l *Logger) Simple() *SimpleLogger {
|
||||
return &SimpleLogger{parent: l}
|
||||
}
|
||||
|
||||
// 包级简洁 API:无需 ctx,自动使用 background ctx(调用者更推荐显式使用 Ctx* 以保留 trace)
|
||||
func Trace(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Trace(msg, fields...) }
|
||||
func Debug(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Debug(msg, fields...) }
|
||||
func Info(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Info(msg, fields...) }
|
||||
func Warn(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Warn(msg, fields...) }
|
||||
func Error(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Error(msg, fields...) }
|
||||
func Fatal(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Fatal(msg, fields...) }
|
||||
func Panic(msg string, fields ...map[string]interface{}) { GetLogger().Simple().Panic(msg, fields...) }
|
||||
|
||||
// 包级带 ctx 的 API:当你有请求上下文(包含 trace)时使用
|
||||
func CtxTrace(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Trace(ctx, msg, f)
|
||||
}
|
||||
func CtxDebug(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Debug(ctx, msg, f)
|
||||
}
|
||||
func CtxInfo(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Info(ctx, msg, f)
|
||||
}
|
||||
func CtxWarn(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Warn(ctx, msg, f)
|
||||
}
|
||||
func CtxError(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Error(ctx, msg, f)
|
||||
}
|
||||
func CtxFatal(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Fatal(ctx, msg, f)
|
||||
}
|
||||
func CtxPanic(ctx context.Context, msg string, fields ...map[string]interface{}) {
|
||||
var f map[string]interface{}
|
||||
if len(fields) > 0 {
|
||||
f = fields[0]
|
||||
}
|
||||
GetLogger().Panic(ctx, msg, f)
|
||||
}
|
||||
Reference in New Issue
Block a user