Compare commits

..

No commits in common. "8213cc3729fa54f33b196d91c2e1b020db5994a4" and "9d7fea4d82a52e14b2b32b73e284fd3349ac0e27" have entirely different histories.

7 changed files with 142 additions and 198 deletions

View File

@ -12,6 +12,9 @@ import (
"strings" "strings"
"time" "time"
"unicode" "unicode"
"git.hexq.cn/tiglog/golib/crypto/gmd5"
"github.com/rs/xid"
) )
// 是否是字符串 // 是否是字符串
@ -23,10 +26,10 @@ func IsString(v interface{}) bool {
// 随机字符串 // 随机字符串
func RandString(n int) string { func RandString(n int) string {
letterRunes := []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") letterRunes := []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
rd := rand.New(rand.NewSource(time.Now().UnixNano())) rand.Seed(time.Now().UnixNano())
b := make([]rune, n) b := make([]rune, n)
for i := range b { for i := range b {
b[i] = letterRunes[rd.Intn(len(letterRunes))] b[i] = letterRunes[rand.Intn(len(letterRunes))]
} }
return string(b) return string(b)
} }
@ -122,6 +125,44 @@ func Reverse(str string) string {
return string(runes[n:]) return string(runes[n:])
} }
// 唯一字符串
// 返回字符串长度为 20
func GenId() string {
guid := xid.New()
return guid.String()
}
// 可变长度的唯一字符串
// 长度太短,可能就不唯一了
// 长度大于等于 16 为最佳
// 长度小于20时为 GenId 的值 md5 后的前缀因此理论上前6位也能在大多数情况
// 下唯一
func Uniq(l int) string {
if l <= 0 {
panic("wrong length param")
}
ret := GenId()
hl := len(ret)
if l < hl {
t, err := gmd5.EncryptString(ret)
if err != nil {
return ret[hl-l:]
}
return t[:l]
}
mhac_len := 6
pl := len(ret)
var hash string
for l > pl {
hash = GenId()
hash = hash[mhac_len:]
ret += hash
pl += len(hash)
}
// log.Println("ret=", ret, ", pl=", pl, ", l=", l)
return ret[0:l]
}
func GetCjkRange(code int) string { func GetCjkRange(code int) string {
var result string var result string
if code >= 0x4E00 && code <= 0x9FFF { if code >= 0x4E00 && code <= 0x9FFF {

View File

@ -46,6 +46,79 @@ func TestUcFirst(t *testing.T) {
gtest.Equal(t, "HelloWorld", r3) gtest.Equal(t, "HelloWorld", r3)
} }
func TestGenId(t *testing.T) {
s1 := helper.GenId()
s2 := helper.GenId()
s3 := helper.GenId()
s4 := helper.GenId()
fmt.Println("gen id: ", s4)
gtest.NotNil(t, s1)
gtest.NotNil(t, s2)
gtest.NotNil(t, s3)
gtest.NotNil(t, s4)
gtest.NotEqual(t, s1, s2)
gtest.NotEqual(t, s1, s3)
gtest.NotEqual(t, s1, s4)
// fmt.Println(s1)
// fmt.Println(s2)
// fmt.Println(s3)
// fmt.Println(s4)
}
func TestUniq(t *testing.T) {
s1 := helper.Uniq(1)
fmt.Println("s1=", s1)
gtest.True(t, 1 == len(s1))
s12 := helper.Uniq(6)
s13 := helper.Uniq(6)
s14 := helper.Uniq(6)
s15 := helper.Uniq(6)
fmt.Println("s12..15", s12, s13, s14, s15)
gtest.NotNil(t, s12)
gtest.NotNil(t, s13)
gtest.NotNil(t, s14)
gtest.NotNil(t, s15)
gtest.NotEqual(t, s12, s13)
gtest.NotEqual(t, s12, s14)
gtest.NotEqual(t, s12, s15)
s2 := helper.Uniq(16)
s3 := helper.Uniq(16)
s4 := helper.Uniq(16)
s5 := helper.Uniq(16)
gtest.NotNil(t, s2)
gtest.NotNil(t, s3)
gtest.NotNil(t, s4)
gtest.NotNil(t, s5)
gtest.NotEqual(t, s2, s3)
gtest.NotEqual(t, s2, s4)
gtest.NotEqual(t, s2, s5)
s6 := helper.Uniq(32)
fmt.Println("s6=", s6)
s7 := helper.Uniq(32)
s8 := helper.Uniq(32)
s9 := helper.Uniq(32)
gtest.NotNil(t, s6)
gtest.NotNil(t, s7)
gtest.NotNil(t, s8)
gtest.NotNil(t, s9)
// fmt.Println("s6789=", s6, s7, s8, s9)
s60 := helper.Uniq(64)
fmt.Println("s60=", s60)
s70 := helper.Uniq(64)
s80 := helper.Uniq(64)
s90 := helper.Uniq(64)
gtest.NotNil(t, s60)
gtest.NotNil(t, s70)
gtest.NotNil(t, s80)
gtest.NotNil(t, s90)
// fmt.Println(s60, s70, s80, s90)
}
func TestSnake(t *testing.T) { func TestSnake(t *testing.T) {
s1 := "XxYy" s1 := "XxYy"
r1 := helper.SnakeString(s1) r1 := helper.SnakeString(s1)

View File

@ -1,51 +0,0 @@
//
// uniq_helper.go
// Copyright (C) 2023 tiglog <me@tiglog.com>
//
// Distributed under terms of the MIT license.
//
package helper
import (
"git.hexq.cn/tiglog/golib/crypto/gmd5"
"github.com/rs/xid"
)
// 唯一字符串
// 返回字符串长度为 20
func GenId() string {
guid := xid.New()
return guid.String()
}
// 可变长度的唯一字符串
// 长度太短,可能就不唯一了
// 长度大于等于 16 为最佳
// 长度小于20时为 GenId 的值 md5 后的前缀因此理论上前6位也能在大多数情况
// 下唯一
func Uniq(l int) string {
if l <= 0 {
panic("wrong length param")
}
ret := GenId()
hl := len(ret)
if l < hl {
t, err := gmd5.EncryptString(ret)
if err != nil {
return ret[hl-l:]
}
return t[:l]
}
mhac_len := 6
pl := len(ret)
var hash string
for l > pl {
hash = GenId()
hash = hash[mhac_len:]
ret += hash
pl += len(hash)
}
// log.Println("ret=", ret, ", pl=", pl, ", l=", l)
return ret[0:l]
}

View File

@ -1,89 +0,0 @@
//
// uniq_helper_test.go
// Copyright (C) 2023 tiglog <me@tiglog.com>
//
// Distributed under terms of the MIT license.
//
package helper_test
import (
"fmt"
"testing"
"git.hexq.cn/tiglog/golib/gtest"
"git.hexq.cn/tiglog/golib/helper"
)
func TestGenId(t *testing.T) {
s1 := helper.GenId()
s2 := helper.GenId()
s3 := helper.GenId()
s4 := helper.GenId()
fmt.Println("gen id: ", s4)
gtest.NotNil(t, s1)
gtest.NotNil(t, s2)
gtest.NotNil(t, s3)
gtest.NotNil(t, s4)
gtest.NotEqual(t, s1, s2)
gtest.NotEqual(t, s1, s3)
gtest.NotEqual(t, s1, s4)
// fmt.Println(s1)
// fmt.Println(s2)
// fmt.Println(s3)
// fmt.Println(s4)
}
func TestUniq(t *testing.T) {
s1 := helper.Uniq(1)
fmt.Println("s1=", s1)
gtest.True(t, 1 == len(s1))
s12 := helper.Uniq(6)
s13 := helper.Uniq(6)
s14 := helper.Uniq(6)
s15 := helper.Uniq(6)
fmt.Println("s12..15", s12, s13, s14, s15)
gtest.NotNil(t, s12)
gtest.NotNil(t, s13)
gtest.NotNil(t, s14)
gtest.NotNil(t, s15)
gtest.NotEqual(t, s12, s13)
gtest.NotEqual(t, s12, s14)
gtest.NotEqual(t, s12, s15)
s2 := helper.Uniq(16)
s3 := helper.Uniq(16)
s4 := helper.Uniq(16)
s5 := helper.Uniq(16)
gtest.NotNil(t, s2)
gtest.NotNil(t, s3)
gtest.NotNil(t, s4)
gtest.NotNil(t, s5)
gtest.NotEqual(t, s2, s3)
gtest.NotEqual(t, s2, s4)
gtest.NotEqual(t, s2, s5)
s6 := helper.Uniq(32)
fmt.Println("s6=", s6)
s7 := helper.Uniq(32)
s8 := helper.Uniq(32)
s9 := helper.Uniq(32)
gtest.NotNil(t, s6)
gtest.NotNil(t, s7)
gtest.NotNil(t, s8)
gtest.NotNil(t, s9)
// fmt.Println("s6789=", s6, s7, s8, s9)
s60 := helper.Uniq(64)
fmt.Println("s60=", s60)
s70 := helper.Uniq(64)
s80 := helper.Uniq(64)
s90 := helper.Uniq(64)
gtest.NotNil(t, s60)
gtest.NotNil(t, s70)
gtest.NotNil(t, s80)
gtest.NotNil(t, s90)
// fmt.Println(s60, s70, s80, s90)
}

View File

@ -10,6 +10,7 @@ package logger
import ( import (
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"go.uber.org/zap" "go.uber.org/zap"
@ -31,7 +32,6 @@ type Logger struct {
l *zap.Logger l *zap.Logger
// https://pkg.go.dev/go.uber.org/zap#example-AtomicLevel // https://pkg.go.dev/go.uber.org/zap#example-AtomicLevel
al *zap.AtomicLevel al *zap.AtomicLevel
fields map[string]Field
} }
func New(out io.Writer, level Level, opts ...Option) *Logger { func New(out io.Writer, level Level, opts ...Option) *Logger {
@ -39,20 +39,16 @@ func New(out io.Writer, level Level, opts ...Option) *Logger {
out = os.Stderr out = os.Stderr
} }
var al = zap.NewAtomicLevelAt(level) al := zap.NewAtomicLevelAt(level)
var cfg zap.Config cfg := zap.NewProductionEncoderConfig()
if level == DebugLevel { cfg.EncodeTime = zapcore.RFC3339TimeEncoder
cfg = zap.NewDevelopmentConfig()
} else {
cfg = zap.NewProductionConfig()
}
core := zapcore.NewCore( core := zapcore.NewCore(
zapcore.NewJSONEncoder(cfg.EncoderConfig), zapcore.NewJSONEncoder(cfg),
zapcore.AddSync(out), zapcore.AddSync(out),
al, al,
) )
return &Logger{l: zap.New(core, opts...), al: &al, fields: make(map[string]Field)} return &Logger{l: zap.New(core, opts...), al: &al}
} }
// SetLevel 动态更改日志级别 // SetLevel 动态更改日志级别
@ -66,37 +62,28 @@ func (l *Logger) SetLevel(level Level) {
type Field = zap.Field type Field = zap.Field
func mergeFields(fields []Field) []Field {
var mfields = []Field{}
for _, field := range std.fields {
mfields = append(mfields, field)
}
mfields = append(mfields, fields...)
return mfields
}
func (l *Logger) Debug(msg string, fields ...Field) { func (l *Logger) Debug(msg string, fields ...Field) {
l.l.Debug(msg, mergeFields(fields)...) l.l.Debug(msg, fields...)
} }
func (l *Logger) Info(msg string, fields ...Field) { func (l *Logger) Info(msg string, fields ...Field) {
l.l.Info(msg, mergeFields(fields)...) l.l.Info(msg, fields...)
} }
func (l *Logger) Warn(msg string, fields ...Field) { func (l *Logger) Warn(msg string, fields ...Field) {
l.l.Warn(msg, mergeFields(fields)...) l.l.Warn(msg, fields...)
} }
func (l *Logger) Error(msg string, fields ...Field) { func (l *Logger) Error(msg string, fields ...Field) {
l.l.Error(msg, mergeFields(fields)...) l.l.Error(msg, fields...)
} }
func (l *Logger) Panic(msg string, fields ...Field) { func (l *Logger) Panic(msg string, fields ...Field) {
l.l.Panic(msg, mergeFields(fields)...) l.l.Panic(msg, fields...)
} }
func (l *Logger) Fatal(msg string, fields ...Field) { func (l *Logger) Fatal(msg string, fields ...Field) {
l.l.Fatal(msg, mergeFields(fields)...) l.l.Fatal(msg, fields...)
} }
func (l *Logger) Sync() error { func (l *Logger) Sync() error {
@ -110,12 +97,12 @@ func ReplaceDefault(l *Logger) { std = l }
func SetLevel(level Level) { std.SetLevel(level) } func SetLevel(level Level) { std.SetLevel(level) }
func With(field Field) { func WithTarget(target string) Field {
std.fields[field.Key] = field return String("target", target)
} }
func WithTarget(target string) { func WithRequestId(req *http.Request) Field {
With(String("target", target)) return String("reqId", req.Header.Get("X-Request-ID"))
} }
func Debug(msg string, fields ...Field) { std.Debug(msg, fields...) } func Debug(msg string, fields ...Field) { std.Debug(msg, fields...) }

View File

@ -36,27 +36,10 @@ func outer() error {
} }
func TestLogToFile(t *testing.T) { func TestLogToFile(t *testing.T) {
log := logger.New(logger.NewRotateBySize("./var/log/test.log"), logger.DebugLevel) log := logger.New(logger.NewProductionRotateBySize("./var/log/test.log"), logger.DebugLevel)
defer log.Sync() defer log.Sync()
gtest.NotNil(t, logger.Default()) gtest.NotNil(t, logger.Default())
err := outer() err := outer()
log.Error("hello world", logger.Any("err", err)) log.Error("hello world", logger.Any("err", err))
log.Info("info1 中华人民共和国") log.Info("中华人民共和国")
log.Debug("debug1 中华人民共和国")
}
func TestProdLog(t *testing.T) {
log := logger.New(logger.NewRotateBySize("./var/log/test.log"), logger.InfoLevel)
defer log.Sync()
log.Info("info2 中华人民共和国")
log.Debug("debug2 应该没有")
}
func TestWithGlobalField(t *testing.T) {
log := logger.New(logger.NewRotateBySize("./var/log/test.log"), logger.DebugLevel)
defer log.Sync()
logger.With(logger.String("reqId", "foo_IDD"))
log.Debug("debug3 中华人民共和国")
logger.With(logger.String("reqId", "bar_IID"))
log.Debug("debug3 救民于水火")
} }

View File

@ -32,16 +32,16 @@ type RotateConfig struct {
} }
// NewProductionRotateByTime 创建按时间轮转的 io.Writer // NewProductionRotateByTime 创建按时间轮转的 io.Writer
func NewRotateByTime(filename string) io.Writer { func NewProductionRotateByTime(filename string) io.Writer {
return RotateByTime(NewRotateConfig(filename)) return NewRotateByTime(NewProductionRotateConfig(filename))
} }
// NewProductionRotateBySize 创建按大小轮转的 io.Writer // NewProductionRotateBySize 创建按大小轮转的 io.Writer
func NewRotateBySize(filename string) io.Writer { func NewProductionRotateBySize(filename string) io.Writer {
return RotateBySize(NewRotateConfig(filename)) return NewRotateBySize(NewProductionRotateConfig(filename))
} }
func NewRotateConfig(filename string) *RotateConfig { func NewProductionRotateConfig(filename string) *RotateConfig {
return &RotateConfig{ return &RotateConfig{
Filename: filename, Filename: filename,
MaxAge: 30, // 日志保留 30 天 MaxAge: 30, // 日志保留 30 天
@ -55,7 +55,7 @@ func NewRotateConfig(filename string) *RotateConfig {
} }
} }
func RotateByTime(cfg *RotateConfig) io.Writer { func NewRotateByTime(cfg *RotateConfig) io.Writer {
opts := []rotatelogs.Option{ opts := []rotatelogs.Option{
rotatelogs.WithMaxAge(time.Duration(cfg.MaxAge) * time.Hour * 24), rotatelogs.WithMaxAge(time.Duration(cfg.MaxAge) * time.Hour * 24),
rotatelogs.WithRotationTime(cfg.RotationTime), rotatelogs.WithRotationTime(cfg.RotationTime),
@ -72,7 +72,7 @@ func RotateByTime(cfg *RotateConfig) io.Writer {
return l return l
} }
func RotateBySize(cfg *RotateConfig) io.Writer { func NewRotateBySize(cfg *RotateConfig) io.Writer {
return &lumberjack.Logger{ return &lumberjack.Logger{
Filename: cfg.Filename, Filename: cfg.Filename,
MaxSize: cfg.MaxSize, MaxSize: cfg.MaxSize,