From ebed85772f99471542122ed98a14a39a7be55c82 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Sat, 20 Jun 2026 23:29:58 +0800 Subject: [PATCH] codex optz. --- cache/mapsync/map.go | 62 +++++++++++ cache/mapsync/map_float.go | 56 +--------- cache/mapsync/map_int.go | 56 +--------- cache/mapsync/map_string.go | 56 +--------- cache/redis/redis.go | 35 +++++-- database/new.go | 94 ++++++----------- database/sql/postgresql.go | 17 +-- go.mod | 22 ++-- go.sum | 44 ++++---- logger/logger.go | 201 +++++++++++++----------------------- utils/net.go | 61 ++++++++--- 11 files changed, 282 insertions(+), 422 deletions(-) create mode 100644 cache/mapsync/map.go diff --git a/cache/mapsync/map.go b/cache/mapsync/map.go new file mode 100644 index 0000000..b7fce53 --- /dev/null +++ b/cache/mapsync/map.go @@ -0,0 +1,62 @@ +package mapsync + +import "sync" + +type syncMap[T any] struct { + sync.RWMutex + Data map[string]T +} + +func newSyncMap[T any]() *syncMap[T] { + return &syncMap[T]{ + Data: make(map[string]T), + } +} + +func (c *syncMap[T]) Set(key string, val T) { + c.Lock() + defer c.Unlock() + + if c.Data == nil { + c.Data = make(map[string]T) + } + c.Data[key] = val +} + +func (c *syncMap[T]) Get(key string) T { + c.RLock() + defer c.RUnlock() + + return c.Data[key] +} + +func (c *syncMap[T]) Del(key string) { + c.Lock() + defer c.Unlock() + + delete(c.Data, key) +} + +func (c *syncMap[T]) Keys() (keys []string) { + c.RLock() + defer c.RUnlock() + + keys = make([]string, 0, len(c.Data)) + for k := range c.Data { + keys = append(keys, k) + } + + return keys +} + +func (c *syncMap[T]) All() map[string]T { + c.RLock() + defer c.RUnlock() + + out := make(map[string]T, len(c.Data)) + for k, v := range c.Data { + out[k] = v + } + + return out +} diff --git a/cache/mapsync/map_float.go b/cache/mapsync/map_float.go index c6f1fc7..3f92a02 100644 --- a/cache/mapsync/map_float.go +++ b/cache/mapsync/map_float.go @@ -1,64 +1,12 @@ package mapsync -import ( - "sync" -) - var ( // sync map MapFloat *mapFloat ) -// lock -type mapFloat struct { - sync.RWMutex - Data map[string]float64 -} +type mapFloat = syncMap[float64] func NewMapFloat() *mapFloat { - return &mapFloat{ - Data: make(map[string]float64), - } -} -func (c *mapFloat) Set(key string, val float64) { - c.Lock() - defer c.Unlock() - c.Data[key] = val -} - -func (c *mapFloat) Get(key string) float64 { - c.RLock() - defer c.RUnlock() - - vals, ok := c.Data[key] - if !ok { - return 0 - } - - return vals -} - -func (c *mapFloat) Del(key string) { - c.Lock() - defer c.Unlock() - - delete(c.Data, key) -} - -func (c *mapFloat) Keys() (keys []string) { - c.RLock() - defer c.RUnlock() - - for k, _ := range c.Data { - keys = append(keys, k) - } - - return -} - -func (c *mapFloat) All() map[string]float64 { - c.RLock() - defer c.RUnlock() - - return c.Data + return newSyncMap[float64]() } diff --git a/cache/mapsync/map_int.go b/cache/mapsync/map_int.go index dd6df2e..72fd81c 100644 --- a/cache/mapsync/map_int.go +++ b/cache/mapsync/map_int.go @@ -1,64 +1,12 @@ package mapsync -import ( - "sync" -) - var ( // sync map MapInt *mapInt ) -// lock -type mapInt struct { - sync.RWMutex - Data map[string]int -} +type mapInt = syncMap[int] func NewMapInt() *mapInt { - return &mapInt{ - Data: make(map[string]int), - } -} - -func (c *mapInt) Set(key string, val int) { - c.Lock() - defer c.Unlock() - c.Data[key] = val -} - -func (c *mapInt) Get(key string) int { - c.RLock() - defer c.RUnlock() - - vals, ok := c.Data[key] - if !ok { - return 0 - } - - return vals -} - -func (c *mapInt) Del(key string) { - c.Lock() - defer c.Unlock() - - delete(c.Data, key) -} - -func (c *mapInt) All() map[string]int { - c.RLock() - defer c.RUnlock() - - return c.Data -} -func (c *mapInt) Keys() (keys []string) { - c.RLock() - defer c.RUnlock() - - for k, _ := range c.Data { - keys = append(keys, k) - } - - return + return newSyncMap[int]() } diff --git a/cache/mapsync/map_string.go b/cache/mapsync/map_string.go index 91cc345..f273f06 100644 --- a/cache/mapsync/map_string.go +++ b/cache/mapsync/map_string.go @@ -1,64 +1,12 @@ package mapsync -import ( - "sync" -) - var ( // sync map MapString *mapString ) -// lock -type mapString struct { - sync.RWMutex - Data map[string]string -} +type mapString = syncMap[string] func NewMapString() *mapString { - return &mapString{ - Data: make(map[string]string), - } -} - -func (c *mapString) Set(key, val string) { - c.Lock() - defer c.Unlock() - c.Data[key] = val -} -func (c *mapString) Get(key string) string { - c.RLock() - defer c.RUnlock() - - vals, ok := c.Data[key] - if !ok { - return "" - } - - return vals -} - -func (c *mapString) Del(key string) { - c.Lock() - defer c.Unlock() - - delete(c.Data, key) -} - -func (c *mapString) Keys() (keys []string) { - c.RLock() - defer c.RUnlock() - - for k, _ := range c.Data { - keys = append(keys, k) - } - - return -} - -func (c *mapString) All() map[string]string { - c.RLock() - defer c.RUnlock() - - return c.Data + return newSyncMap[string]() } diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 5a55333..0e3a2e0 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -2,6 +2,7 @@ package redis import ( "context" + "fmt" "hash/fnv" "net/url" "strconv" @@ -24,10 +25,22 @@ type RedisClient struct { } func New(dsn string, hashRadix string) *RedisClient { - arg, err := url.Parse(dsn) + client, err := NewWithContext(context.Background(), dsn, hashRadix) if err != nil { panic(err) } + return client +} + +func NewWithContext(ctx context.Context, dsn string, hashRadix string) (*RedisClient, error) { + if ctx == nil { + ctx = context.Background() + } + + arg, err := url.Parse(dsn) + if err != nil { + return nil, fmt.Errorf("parse redis dsn: %w", err) + } pwd, _ := arg.User.Password() //get db number,default:0 @@ -36,7 +49,10 @@ func New(dsn string, hashRadix string) *RedisClient { if arg.Path == "" { db = Hash(hashRadix) } else { - db, _ = strconv.Atoi(arg.Path) + db, err = strconv.Atoi(arg.Path) + if err != nil { + return nil, fmt.Errorf("parse redis db index: %w", err) + } } //connect redis server @@ -46,21 +62,26 @@ func New(dsn string, hashRadix string) *RedisClient { DB: db, // use default DB Protocol: 3, }) - _, err = client.Ping(context.Background()).Result() + _, err = client.Ping(ctx).Result() if err != nil { - panic(err) + _ = client.Close() + return nil, fmt.Errorf("ping redis: %w", err) } return &RedisClient{ DB: db, Client: client, - Ctx: context.Background(), + Ctx: ctx, memory: make(map[string]any), - } + }, nil } func Hash(s string) int { + if vars.RedisShardings <= 0 { + return 0 + } + h := fnv.New32a() - h.Write([]byte(strings.ToLower(s))) + _, _ = h.Write([]byte(strings.ToLower(s))) return int(h.Sum32()) % vars.RedisShardings } diff --git a/database/new.go b/database/new.go index 46d0109..8837531 100644 --- a/database/new.go +++ b/database/new.go @@ -6,9 +6,8 @@ import ( "fmt" "strings" - "git.apinb.com/bsm-sdk/core/database/sql" + dbsql "git.apinb.com/bsm-sdk/core/database/sql" "git.apinb.com/bsm-sdk/core/types" - "git.apinb.com/bsm-sdk/core/vars" "gorm.io/driver/mysql" "gorm.io/gorm" ) @@ -50,47 +49,50 @@ func NewDatabase(driver string, dsn []string, options *types.SqlOptions) (db *go return db, nil } +func firstDSN(dsn []string) (string, error) { + if len(dsn) == 0 || strings.TrimSpace(dsn[0]) == "" { + return "", fmt.Errorf("database dsn is empty") + } + return dsn[0], nil +} + +func applySqlOptions(gormDb *gorm.DB, options *types.SqlOptions) (*gorm.DB, error) { + if options.Debug { + gormDb = gormDb.Debug() + } + + sqlDB, err := gormDb.DB() + if err != nil { + return nil, err + } + + sqlDB.SetMaxIdleConns(options.MaxIdleConns) + sqlDB.SetMaxOpenConns(options.MaxOpenConns) + sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime) + + return gormDb, nil +} + // NewMysql 创建MySQL数据库服务 // dsn: 数据源名称数组 // options: 数据库连接选项 // 返回: GORM数据库实例 func NewMysql(dsn []string, options *types.SqlOptions) (gormDb *gorm.DB, err error) { - // 设置连接默认值 - if options == nil { - options = &types.SqlOptions{ - MaxIdleConns: vars.SqlOptionMaxIdleConns, - MaxOpenConns: vars.SqlOptionMaxOpenConns, - ConnMaxLifetime: vars.SqlOptionConnMaxLifetime, - LogStdout: false, - Debug: true, - } + options = dbsql.SetOptions(options) + + dsn0, err := firstDSN(dsn) + if err != nil { + return nil, err } - gormDb, err = gorm.Open(mysql.Open(dsn[0]), &gorm.Config{ + gormDb, err = gorm.Open(mysql.Open(dsn0), &gorm.Config{ SkipDefaultTransaction: true, }) if err != nil { return nil, err } - if options.Debug { - gormDb = gormDb.Debug() - } - - // 获取通用数据库对象 sql.DB,然后使用其提供的功能 - sqlDB, err := gormDb.DB() - if err != nil { - return nil, err - } - - // SetMaxIdleConns 用于设置连接池中空闲连接的最大数量 - sqlDB.SetMaxIdleConns(options.MaxIdleConns) - // SetMaxOpenConns 设置打开数据库连接的最大数量 - sqlDB.SetMaxOpenConns(options.MaxOpenConns) - // SetConnMaxLifetime 设置了连接可复用的最大时间 - sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime) - - return gormDb, nil + return applySqlOptions(gormDb, options) } // NewPostgres 创建PostgreSQL数据库服务 @@ -98,40 +100,12 @@ func NewMysql(dsn []string, options *types.SqlOptions) (gormDb *gorm.DB, err err // options: 数据库连接选项 // 返回: GORM数据库实例 func NewPostgres(dsn []string, options *types.SqlOptions) (gormDb *gorm.DB, err error) { - // 设置连接默认值 - if options == nil { - options = &types.SqlOptions{ - MaxIdleConns: vars.SqlOptionMaxIdleConns, - MaxOpenConns: vars.SqlOptionMaxOpenConns, - ConnMaxLifetime: vars.SqlOptionConnMaxLifetime, - LogStdout: false, - Debug: true, - } - } - - gormDb, err = sql.NewPostgreSql(dsn[0], options) + dsn0, err := firstDSN(dsn) if err != nil { return nil, err } - if options.Debug { - gormDb = gormDb.Debug() - } - - // 获取通用数据库对象 sql.DB,然后使用其提供的功能 - sqlDB, err := gormDb.DB() - if err != nil { - return nil, err - } - - // SetMaxIdleConns 用于设置连接池中空闲连接的最大数量 - sqlDB.SetMaxIdleConns(options.MaxIdleConns) - // SetMaxOpenConns 设置打开数据库连接的最大数量 - sqlDB.SetMaxOpenConns(options.MaxOpenConns) - // SetConnMaxLifetime 设置了连接可复用的最大时间 - sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime) - - return gormDb, nil + return dbsql.NewPostgreSql(dsn0, options) } // AppendMigrate 调用此函数后,会在数据库初始化时自动迁移表结构 diff --git a/database/sql/postgresql.go b/database/sql/postgresql.go index 7540578..6b67a32 100644 --- a/database/sql/postgresql.go +++ b/database/sql/postgresql.go @@ -15,7 +15,7 @@ func SetOptions(options *types.SqlOptions) *types.SqlOptions { MaxOpenConns: vars.SqlOptionMaxOpenConns, ConnMaxLifetime: vars.SqlOptionConnMaxLifetime, LogStdout: false, - Debug: false, + Debug: true, } } @@ -26,16 +26,7 @@ func SetOptions(options *types.SqlOptions) *types.SqlOptions { func NewPostgreSql(dsn string, options *types.SqlOptions) (*gorm.DB, error) { var err error - //set connection default val. - if options == nil { - options = &types.SqlOptions{ - MaxIdleConns: vars.SqlOptionMaxIdleConns, - MaxOpenConns: vars.SqlOptionMaxOpenConns, - ConnMaxLifetime: vars.SqlOptionConnMaxLifetime, - LogStdout: false, - Debug: true, - } - } + options = SetOptions(options) gormDb, err := gorm.Open(postgres.New(postgres.Config{ DSN: dsn, @@ -60,7 +51,7 @@ func NewPostgreSql(dsn string, options *types.SqlOptions) (*gorm.DB, error) { if err != nil { return nil, err } - + // SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。 sqlDB.SetMaxIdleConns(options.MaxIdleConns) // SetMaxOpenConns 设置打开数据库连接的最大数量。 @@ -69,4 +60,4 @@ func NewPostgreSql(dsn string, options *types.SqlOptions) (*gorm.DB, error) { sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime) return gormDb, nil -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index dd3efb8..3608ee5 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,11 @@ require ( github.com/nats-io/nats.go v1.52.0 github.com/oklog/ulid/v2 v2.1.1 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/redis/go-redis/v9 v9.19.0 + github.com/redis/go-redis/v9 v9.20.1 github.com/shirou/gopsutil v3.21.11+incompatible github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - go.etcd.io/etcd/client/pkg/v3 v3.6.11 - go.etcd.io/etcd/client/v3 v3.6.11 + go.etcd.io/etcd/client/pkg/v3 v3.6.12 + go.etcd.io/etcd/client/v3 v3.6.12 google.golang.org/grpc v1.81.1 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.6.0 @@ -70,7 +70,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.etcd.io/etcd/api/v3 v3.6.11 // indirect + go.etcd.io/etcd/api/v3 v3.6.12 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel v1.43.0 // indirect @@ -80,12 +80,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.23.0 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/net v0.52.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.44.0 // indirect - golang.org/x/text v0.36.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.38.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 // indirect google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index fe468c7..3f0594e 100644 --- a/go.sum +++ b/go.sum @@ -120,8 +120,8 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= -github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= -github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= +github.com/redis/go-redis/v9 v9.20.1 h1:sfCU6A8P3dXbKyWes02uxA2baehGux9dZHfEKtsTB1w= +github.com/redis/go-redis/v9 v9.20.1/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= @@ -154,12 +154,12 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= -go.etcd.io/etcd/api/v3 v3.6.11 h1:XFGTgrJ8nak3kB4NgMG8t7NT+lEeuuvKQAqUHKVgkWQ= -go.etcd.io/etcd/api/v3 v3.6.11/go.mod h1:HYfTh0jyh+uFgp6gMbxJteIDYY97yMuYz85Rnw6Gy9o= -go.etcd.io/etcd/client/pkg/v3 v3.6.11 h1:e41mp315Yn3QMGPmEzCyLsMINgJXTY/dX8kM++1csxU= -go.etcd.io/etcd/client/pkg/v3 v3.6.11/go.mod h1:DysuMe/inqRyC/1tjRR6hReH/VV9Lufs27YKSKBWWJg= -go.etcd.io/etcd/client/v3 v3.6.11 h1:LAByD96VmmeuairkvdAcE0RZnrmGz/q3ceeWePo9bwc= -go.etcd.io/etcd/client/v3 v3.6.11/go.mod h1:vOTDMCo+fGPEClJqcFEFSqZ+8e7WKV7AyqJjX//HR2w= +go.etcd.io/etcd/api/v3 v3.6.12 h1:OLOZUKEuAA36TR48F0cIaa8FdzrWygjyfrJxXg4iDgs= +go.etcd.io/etcd/api/v3 v3.6.12/go.mod h1:p14EIQXHbuOQbVvL/WEes5uqKnxP9AgKJgpjbMVvzvE= +go.etcd.io/etcd/client/pkg/v3 v3.6.12 h1:36zzB+pQOdHbhN+kH2iJz/K8bJn0ZLtLfPPO7jozTDo= +go.etcd.io/etcd/client/pkg/v3 v3.6.12/go.mod h1:hh2+ZXtfLzs3o6mn92ntgNPBrTJJOvXqICM5g3L3DMY= +go.etcd.io/etcd/client/v3 v3.6.12 h1:kMSP6JcPZMqSJiX+TXdUIBU/4eXEZWBAaui4VihMbIc= +go.etcd.io/etcd/client/v3 v3.6.12/go.mod h1:CMs6fJWYiZQk4ytFjd4lE1diOvvRMmtbbn/alZXd3dQ= go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -189,32 +189,32 @@ golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -225,10 +225,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= -google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3 h1:ctPmKL12ZsoKAlmPUsoW70zEDiYF+/H6aLieXxgAU0k= +google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3/go.mod h1:Z4WJ5pJOYWFWcHEQUelD5QaZDknIQkpIL/+fyJOT9+A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 h1:phvBWCAQMGN1945mp5fjCXP6jEF0+a0+4TjokS4sxNY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= diff --git a/logger/logger.go b/logger/logger.go index 867bcca..cec8be7 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -168,122 +168,94 @@ func (l *Logger) sendToRemote(level, name, out string) { utils.HttpPost(l.endpoint, nil, jsonBytes) } +func (l *Logger) loggerFor(level vars.LogLevel) (*log.Logger, string) { + switch level { + case vars.DEBUG: + return l.debugLogger, "DEBUG" + case vars.INFO: + return l.infoLogger, "INFO" + case vars.WARN: + return l.warnLogger, "WARN" + case vars.ERROR: + return l.errorLogger, "ERROR" + default: + return l.fatalLogger, "FATAL" + } +} + +func (l *Logger) output(level vars.LogLevel, out string, fatal bool) { + if !fatal && l.level > level { + return + } + + _ = l.checkAndRotateLog() + logger, levelName := l.loggerFor(level) + if fatal { + logger = l.fatalLogger + levelName = "FATAL" + } + if l.onRemote { + go l.sendToRemote(levelName, l.name, out) + } + _ = logger.Output(3, out) + + if fatal { + os.Exit(1) + } +} + +func (l *Logger) outputf(level vars.LogLevel, format string, v ...any) { + l.output(level, fmt.Sprintf(format, v...), false) +} + // Debug 输出调试信息 func (l *Logger) Debug(v ...any) { - if l.level <= vars.DEBUG { - l.checkAndRotateLog() - out := fmt.Sprint(v...) - if l.onRemote { - go l.sendToRemote("DEBUG", l.name, out) - } - l.debugLogger.Output(2, out) - } + l.output(vars.DEBUG, fmt.Sprint(v...), false) } // Debugf 格式化输出调试信息 func (l *Logger) Debugf(format string, v ...any) { - if l.level <= vars.DEBUG { - l.checkAndRotateLog() - out := fmt.Sprintf(format, v...) - if l.onRemote { - go l.sendToRemote("DEBUG", l.name, out) - } - l.debugLogger.Output(2, out) - } + l.outputf(vars.DEBUG, format, v...) } // Info 输出信息 func (l *Logger) Info(v ...any) { - if l.level <= vars.INFO { - l.checkAndRotateLog() - out := fmt.Sprint(v...) - if l.onRemote { - go l.sendToRemote("INFO", l.name, out) - } - l.infoLogger.Output(2, out) - } + l.output(vars.INFO, fmt.Sprint(v...), false) } // Infof 格式化输出信息 func (l *Logger) Infof(format string, v ...any) { - if l.level <= vars.INFO { - l.checkAndRotateLog() - out := fmt.Sprintf(format, v...) - if l.onRemote { - go l.sendToRemote("INFO", l.name, out) - } - l.infoLogger.Output(2, out) - } + l.outputf(vars.INFO, format, v...) } // Warn 输出警告 func (l *Logger) Warn(v ...any) { - if l.level <= vars.WARN { - l.checkAndRotateLog() - out := fmt.Sprint(v...) - if l.onRemote { - go l.sendToRemote("WARN", l.name, out) - } - l.warnLogger.Output(2, out) - } + l.output(vars.WARN, fmt.Sprint(v...), false) } // Warnf 格式化输出警告 func (l *Logger) Warnf(format string, v ...any) { - if l.level <= vars.WARN { - l.checkAndRotateLog() - out := fmt.Sprintf(format, v...) - if l.onRemote { - go l.sendToRemote("WARN", l.name, out) - } - l.warnLogger.Output(2, out) - } + l.outputf(vars.WARN, format, v...) } // Error 输出错误 func (l *Logger) Error(v ...any) { - if l.level <= vars.ERROR { - l.checkAndRotateLog() - out := fmt.Sprint(v...) - if l.onRemote { - go l.sendToRemote("ERROR", l.name, out) - } - l.errorLogger.Output(2, out) - } + l.output(vars.ERROR, fmt.Sprint(v...), false) } // Errorf 格式化输出错误 func (l *Logger) Errorf(format string, v ...any) { - if l.level <= vars.ERROR { - l.checkAndRotateLog() - out := fmt.Sprintf(format, v...) - if l.onRemote { - go l.sendToRemote("ERROR", l.name, out) - } - l.errorLogger.Output(2, out) - } + l.outputf(vars.ERROR, format, v...) } // Fatal 输出致命错误并退出程序 func (l *Logger) Fatal(v ...any) { - l.checkAndRotateLog() - out := fmt.Sprint(v...) - if l.onRemote { - go l.sendToRemote("FATAL", l.name, out) - } - l.fatalLogger.Output(2, out) - os.Exit(1) + l.output(vars.ERROR, fmt.Sprint(v...), true) } // Fatalf 格式化输出致命错误并退出程序 func (l *Logger) Fatalf(format string, v ...any) { - l.checkAndRotateLog() - out := fmt.Sprintf(format, v...) - if l.onRemote { - go l.sendToRemote("FATAL", l.name, out) - } - l.fatalLogger.Output(2, out) - os.Exit(1) + l.output(vars.ERROR, fmt.Sprintf(format, v...), true) } // Print 输出信息(兼容标准log包) @@ -325,95 +297,64 @@ func (l *Logger) Close() error { // 全局日志函数(兼容标准log包) -// Debug 全局调试日志 +// Global logger functions. + +func withGlobalLogger(fn func(*Logger)) { + if globalLogger != nil { + fn(globalLogger) + } +} + func Debug(v ...any) { - if globalLogger != nil { - globalLogger.Debug(v...) - } + withGlobalLogger(func(l *Logger) { l.Debug(v...) }) } -// Debugf 全局调试日志 func Debugf(format string, v ...any) { - if globalLogger != nil { - globalLogger.Debugf(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Debugf(format, v...) }) } -// Info 全局信息日志 func Info(v ...any) { - if globalLogger != nil { - globalLogger.Info(v...) - } + withGlobalLogger(func(l *Logger) { l.Info(v...) }) } -// Infof 全局信息日志 func Infof(format string, v ...any) { - if globalLogger != nil { - globalLogger.Infof(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Infof(format, v...) }) } -// Warn 全局警告日志 func Warn(v ...any) { - if globalLogger != nil { - globalLogger.Warn(v...) - } + withGlobalLogger(func(l *Logger) { l.Warn(v...) }) } -// Warnf 全局警告日志 func Warnf(format string, v ...any) { - if globalLogger != nil { - globalLogger.Warnf(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Warnf(format, v...) }) } -// Error 全局错误日志 func Error(v ...any) { - if globalLogger != nil { - globalLogger.Error(v...) - } + withGlobalLogger(func(l *Logger) { l.Error(v...) }) } -// Errorf 全局错误日志 func Errorf(format string, v ...any) { - if globalLogger != nil { - globalLogger.Errorf(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Errorf(format, v...) }) } -// Fatal 全局致命错误日志 func Fatal(v ...any) { - if globalLogger != nil { - globalLogger.Fatal(v...) - } + withGlobalLogger(func(l *Logger) { l.Fatal(v...) }) } -// Fatalf 全局致命错误日志 func Fatalf(format string, v ...any) { - if globalLogger != nil { - globalLogger.Fatalf(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Fatalf(format, v...) }) } -// Print 全局打印日志(兼容标准log包) func Print(v ...any) { - if globalLogger != nil { - globalLogger.Print(v...) - } + withGlobalLogger(func(l *Logger) { l.Print(v...) }) } -// Printf 全局打印日志(兼容标准log包) func Printf(format string, v ...any) { - if globalLogger != nil { - globalLogger.Printf(format, v...) - } + withGlobalLogger(func(l *Logger) { l.Printf(format, v...) }) } -// Println 全局打印日志(兼容标准log包) func Println(v ...any) { - if globalLogger != nil { - globalLogger.Println(v...) - } + withGlobalLogger(func(l *Logger) { l.Println(v...) }) } // GetLogger 获取全局日志器实例 diff --git a/utils/net.go b/utils/net.go index 5e48db6..238a841 100644 --- a/utils/net.go +++ b/utils/net.go @@ -56,6 +56,7 @@ import ( "net" "net/http" "os" + "path/filepath" "strconv" "strings" "time" @@ -202,6 +203,30 @@ func createHTTPClient(timeout time.Duration) *http.Client { } } +func readHTTPResponse(resp *http.Response) ([]byte, error) { + respBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if err := checkHTTPStatus(resp, respBytes); err != nil { + return nil, err + } + + return respBytes, nil +} + +func checkHTTPStatus(resp *http.Response, body []byte) error { + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + respBytes := body + if respBytes == nil && resp.Body != nil { + respBytes, _ = io.ReadAll(resp.Body) + } + return fmt.Errorf("http status %d: %s", resp.StatusCode, string(respBytes)) + } + + return nil +} + // HttpGet 发送HTTP GET请求 // url: 请求地址 // timeout: 超时时间(可选,默认30秒),可以传入多个,只使用第一个 @@ -224,7 +249,7 @@ func HttpGet(url string, timeout ...time.Duration) ([]byte, error) { } defer resp.Body.Close() - return io.ReadAll(resp.Body) + return readHTTPResponse(resp) } // HttpPostJSON 发送HTTP POST JSON请求 @@ -232,13 +257,13 @@ func HttpGet(url string, timeout ...time.Duration) ([]byte, error) { // header: 请求头 // data: 请求数据(将被序列化为JSON) // 返回: 响应体和错误信息 -func HttpPostJSON(url string, header map[string]string, data map[string]any) ([]byte, error) { +func HttpPostJSON(url string, header map[string]string, data map[string]any, timeout ...time.Duration) ([]byte, error) { jsonBytes, err := json.Marshal(data) if err != nil { return nil, fmt.Errorf("marshal json failed: %w", err) } - return HttpPost(url, header, jsonBytes) + return HttpPost(url, header, jsonBytes, timeout...) } // HttpPost 发送HTTP POST请求 @@ -274,16 +299,7 @@ func HttpPost(url string, header map[string]string, data []byte, timeout ...time } defer resp.Body.Close() - respBytes, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(respBytes)) - } - - return respBytes, nil + return readHTTPResponse(resp) } // HttpRequest 执行HTTP请求 @@ -291,11 +307,14 @@ func HttpPost(url string, header map[string]string, data []byte, timeout ...time // timeout: 超时时间(可选,默认30秒),可以传入多个,只使用第一个 // 返回: 响应体和错误信息 func HttpRequest(r *http.Request, timeout ...time.Duration) ([]byte, error) { + if r == nil { + return nil, fmt.Errorf("http request is nil") + } + timeoutDuration := getTimeoutDuration(timeout, DefaultHTTPTimeout) - // 如果请求还没有设置context,添加一个带超时的context - if r.Context() == context.Background() || r.Context() == nil { - ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration) + if _, ok := r.Context().Deadline(); !ok { + ctx, cancel := context.WithTimeout(r.Context(), timeoutDuration) defer cancel() r = r.WithContext(ctx) } @@ -307,7 +326,7 @@ func HttpRequest(r *http.Request, timeout ...time.Duration) ([]byte, error) { } defer resp.Body.Close() - return io.ReadAll(resp.Body) + return readHTTPResponse(resp) } // DownloadFile 下载文件 @@ -333,6 +352,10 @@ func DownloadFile(url, saveTo string, fb func(length, downLen int64), timeout .. } defer resp.Body.Close() + if err := checkHTTPStatus(resp, nil); err != nil { + return err + } + if resp.Body == nil { return fmt.Errorf("response body is nil for %s", url) } @@ -344,6 +367,10 @@ func DownloadFile(url, saveTo string, fb func(length, downLen int64), timeout .. fsize = -1 } + if err := os.MkdirAll(filepath.Dir(saveTo), 0755); err != nil { + return fmt.Errorf("create dir for %s error: %w", saveTo, err) + } + // 创建文件 file, err := os.Create(saveTo) if err != nil {