提交 49ecfeba authored 作者: mooncake's avatar mooncake

update

上级 02b6ff25
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.log
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# idea
.idea/
.vscode/
*.iml
*.ipr
*.iws
__debug*
cmd/*/__debug*
SHELL := /bin/bash
PROJECT_NAME := "olog"
PKG := "$(PROJECT_NAME)"
PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/ | grep -v /api/ | grep -v /cmd/)
.PHONY: fmt
fmt:
@go mod tidy
@gofmt -s -w .
.PHONY: ci-lint
# Check the code specification against the rules in the .golangci.yml file
ci-lint:
@gofmt -s -w .
golangci-lint run ./...
.PHONY: cover
# Generate test coverage
cover:
go test -short -coverprofile=cover.out -covermode=atomic ${PKG_LIST}
go tool cover -html=cover.out
.PHONY: graph
# Generate interactive visual function dependency graphs
graph:
@echo "generating graph ......"
@cp -f cmd/operator/main.go .
go-callvis -skipbrowser -format=svg -nostd -file=operator operator
@rm -f main.go operator.gv
.PHONY: docs
# Generate swagger docs, only for ⓵ Web services created based on sql
docs:
@bash scripts/swag-docs.sh $(HOST)
.PHONY: build
# Build operator for linux amd64 binary
build: docs
@echo "building 'operator', linux binary file will be put into binary/ "
@#CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags="-m -l" -tags=jsoniter -o binary/operator main.go
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags="-m -l" -tags=jsoniter -o binary/operator main.go
@du -sh binary/*
@md5 binary/operator
.PHONY: build-docker
build-docker: docs
@echo "building 'operator', linux binary file will be put into binary/ "
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags="-m -l" -o binary/operator main.go
@du -sh binary/*
@md5 binary/operator
@cp binary/operator app/operator/operator
@cp -rf assets app/operator/assets
@cp -rf configs/operator.yml app/operator/conf/operator.yml
@cd app/operator && docker build -t tush/operator:latest .
.PHONY: build-mac
# Build operator for linux amd64 binary
build-mac:
@echo "building 'operator', mac binary file will be put into binary/ "
@CGO_ENABLED=0 go build -tags=jsoniter -ldflags="-s -w" -o binary/operator-mac main.go
@md5 binary/operator-mac
.PHONY: run
run: docs build-mac
@cp binary/operator-mac app/operator/operator
@bash scripts/run.sh
.PHONY: test
test:
# @go test -v internal/modules/operator/controller/app_module_test.go | tee tmp/unitTest/operator.test.log
# @go test -v internal/modules/operator/controller/agent_test.go | tee tmp/unitTest/operator.test.log
# @go test -v internal/modules/operator/controller/user_test.go | tee tmp/unitTest/operator.test.log
# @go test -v internal/modules/operator/controller/site_test.go | tee tmp/unitTest/operator.test.log
# @go test -v internal/modules/operator/controller/intake_test.go | tee tmp/unitTest/operator.test.log
@go test -v internal/modules/operator/controller/income_test.go | tee tmp/unitTest/operator.test.log
.PHONY: dk
dk:
@echo "building '$(PROJECT_NAME)', linux binary file will be put into binary/ "
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags="-m -l" -o binary/$(PROJECT_NAME) main.go
@du -sh binary/*
@md5 binary/*
@cp binary/$(PROJECT_NAME) app/$(PROJECT_NAME)
@cd app/$(PROJECT_NAME) && docker build -t tush/$(PROJECT_NAME):latest .
@cd app/k8s && kubectl delete -f $(PROJECT_NAME).yaml && kubectl apply -f $(PROJECT_NAME).yaml
@cd app/k8s && kubectl delete -f $(PROJECT_NAME).svc.yaml && kubectl apply -f $(PROJECT_NAME).svc.yaml
@docker image prune -f
.PHONY: stop
stop:
@bash scripts/stop.sh
.PHONY: run-nohup
# Run service with nohup in local, if you want to stop the server, pass the parameter stop, e.g. make run-nohup CMD=stop
run-nohup:
@bash scripts/run-nohup.sh $(CMD)
.PHONY: run-docker
# Deploy service in local docker, if you want to update the service, run the make run-docker command again
run-docker: image-build-local
@bash scripts/deploy-docker.sh
.PHONY: binary-package
# Packaged binary files
binary-package: build
@bash scripts/binary-package.sh
.PHONY: deploy-binary
# Deploy binary to remote linux server, e.g. make deploy-binary USER=root PWD=123456 IP=192.168.1.10
deploy-binary: binary-package
@expect scripts/deploy-binary.sh $(USER) $(PWD) $(IP)
.PHONY: image-build-local
# Build image for local docker, tag=latest, use binary files to build
image-build-local: build
@bash scripts/image-build-local.sh
.PHONY: image-build
# Build image for remote repositories, use binary files to build, e.g. make image-build REPO_HOST=addr TAG=latest
image-build:
@bash scripts/image-build.sh $(REPO_HOST) $(TAG)
.PHONY: image-build2
# Build image for remote repositories, phase II build, e.g. make image-build2 REPO_HOST=addr TAG=latest
image-build2:
@bash scripts/image-build2.sh $(REPO_HOST) $(TAG)
.PHONY: image-push
# Push docker image to remote repositories, e.g. make image-push REPO_HOST=addr TAG=latest
image-push:
@bash scripts/image-push.sh $(REPO_HOST) $(TAG)
.PHONY: deploy-k8s
# Deploy service to k8s
deploy-k8s:
@bash scripts/deploy-k8s.sh
.PHONY: update-config
# Update internal/config code base on yaml file
update-config:
@operator config --server-dir=.
.PHONY: clean
# Clean binary file, cover.out, template file
clean:
@rm -vrf cmd/operator/operator*
@rm -vrf cover.out
@rm -vrf main.go operator.gv
@rm -vrf internal/ecode/*.go.gen*
@rm -vrf internal/routers/*.go.gen*
@rm -vrf internal/handler/*.go.gen*
@rm -vrf internal/service/*.go.gen*
@rm -rf operator-binary.tar.gz
@echo "clean finished"
# Show help
help:
@echo ''
@echo 'Usage:'
@echo ' make <target>'
@echo ''
@echo 'Targets:'
@awk '/^[a-zA-Z\-_0-9]+:/ { \
helpMessage = match(lastLine, /^# (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")-1); \
helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \
printf "\033[1;36m %-22s\033[0m %s\n", helpCommand,helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
.DEFAULT_GOAL := all
package olog
type Config struct {
Format string `yaml:"format" json:"format" mapstructure:"format"`
IsSave bool `yaml:"isSave" json:"isSave" mapstructure:"isSave"`
Level string `yaml:"level" json:"level" mapstructure:"level"`
FileConfig FileConfig `yaml:"logFileConfig" json:"logFileConfig" mapstructure:"logFileConfig"`
}
type FileConfig struct {
Filename string `yaml:"filename" json:"filename" mapstructure:"filename"`
MaxSize int `yaml:"maxSize" json:"maxSize" mapstructure:"maxSize"`
MaxBackups int `yaml:"maxBackups" json:"maxBackups" mapstructure:"maxBackups"`
MaxAge int `yaml:"maxAge" json:"maxAge" mapstructure:"maxAge"`
IsCompression bool `yaml:"isCompression" json:"isCompression" mapstructure:"isCompression"`
}
module olog
go 1.24.3
require (
github.com/stretchr/testify v1.11.1
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.76.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
package olog
import (
"fmt"
"go.uber.org/zap"
"google.golang.org/grpc/grpclog"
)
type grpcLogger struct {
zLog *zap.Logger
verbosity int
}
// ReplaceGRPCLoggerV2 replace grpc logger v2
func ReplaceGRPCLoggerV2(l *zap.Logger) {
zLog := l.WithOptions(zap.AddCallerSkip(5)).With(zap.Bool("grpc_system", true))
zzl := &grpcLogger{
zLog: zLog,
verbosity: 0,
}
grpclog.SetLoggerV2(zzl)
}
func (l *grpcLogger) Info(args ...interface{}) {
l.zLog.Info(fmt.Sprint(args...))
}
func (l *grpcLogger) Infoln(args ...interface{}) {
l.zLog.Info(fmt.Sprint(args...))
}
func (l *grpcLogger) Infof(format string, args ...interface{}) {
l.zLog.Info(fmt.Sprintf(format, args...))
}
func (l *grpcLogger) Warning(args ...interface{}) {
l.zLog.Warn(fmt.Sprint(args...))
}
func (l *grpcLogger) Warningln(args ...interface{}) {
l.zLog.Warn(fmt.Sprint(args...))
}
func (l *grpcLogger) Warningf(format string, args ...interface{}) {
l.zLog.Warn(fmt.Sprintf(format, args...))
}
func (l *grpcLogger) Error(args ...interface{}) {
l.zLog.Error(fmt.Sprint(args...))
}
func (l *grpcLogger) Errorln(args ...interface{}) {
l.zLog.Error(fmt.Sprint(args...))
}
func (l *grpcLogger) Errorf(format string, args ...interface{}) {
l.zLog.Error(fmt.Sprintf(format, args...))
}
func (l *grpcLogger) Fatal(args ...interface{}) {
l.zLog.Fatal(fmt.Sprint(args...))
}
func (l *grpcLogger) Fatalln(args ...interface{}) {
l.zLog.Fatal(fmt.Sprint(args...))
}
func (l *grpcLogger) Fatalf(format string, args ...interface{}) {
l.zLog.Fatal(fmt.Sprintf(format, args...))
}
func (l *grpcLogger) V(level int) bool {
return l.verbosity <= level
}
package olog
import (
"testing"
"go.uber.org/zap"
)
func TestReplaceGRPCLoggerV2(t *testing.T) {
ReplaceGRPCLoggerV2(Get())
l := &grpcLogger{
zLog: Get().WithOptions(zap.AddCallerSkip(1)),
verbosity: 0,
}
l.V(0)
l.Info("test info")
l.Infof("test %s", "info")
l.Infoln("test info")
l.Warning("test warning")
l.Warningf("test %s", "warning")
l.Warningln("test warning")
l.Error("test error")
l.Errorf("test %s", "error")
l.Errorln("test error")
//l.Fatal("test fatal")
//l.Fatalf("test %s", "fatal")
//l.Fatalln("test fatal")
}
package olog
import (
"encoding/json"
"fmt"
"io"
"os"
"strings"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
const (
formatConsole = "console"
formatJSON = "json"
levelDebug = "DEBUG"
levelInfo = "INFO"
levelWarn = "WARN"
levelError = "ERROR"
)
var defaultLogger *zap.Logger
var defaultSugaredLogger *zap.SugaredLogger
var defaultZapWriter *ZapWriter
func getLogger() *zap.Logger {
checkNil()
return defaultLogger.WithOptions(zap.AddCallerSkip(1))
}
func getSugaredLogger() *zap.SugaredLogger {
checkNil()
return defaultSugaredLogger.WithOptions(zap.AddCallerSkip(1))
}
func Init(cfg Config) (err error) {
var loggerOpts []Option
loggerOpts = append(loggerOpts, WithLevel(cfg.Level), WithFormat(cfg.Format))
if cfg.IsSave {
opt := WithSave(
cfg.IsSave,
WithFileName(cfg.FileConfig.Filename),
WithFileMaxSize(cfg.FileConfig.MaxSize),
WithFileMaxBackups(cfg.FileConfig.MaxBackups),
WithFileMaxAge(cfg.FileConfig.MaxAge),
WithFileIsCompression(cfg.FileConfig.IsCompression),
)
loggerOpts = append(loggerOpts, opt)
} else {
opt := WithSave(cfg.IsSave)
loggerOpts = append(loggerOpts, opt)
}
_, err = InitWithOptions(loggerOpts...)
if err != nil {
return err
}
Info("[olog] initialized")
return nil
}
// InitWithOptions initial log settings
// print the debug level log in the terminal, example: InitWithOptions()
// print the info level log in the terminal, example: InitWithOptions(WithLevel("info"))
// print the json format, debug level log in the terminal, example: InitWithOptions(WithFormat("json"))
// log with hooks, example: InitWithOptions(WithHooks(func(zapcore.Entry) error{return nil}))
// output the log to the file out.log, using the default cut log-related parameters, debug-level log, example: InitWithOptions(WithSave())
// output the log to the specified file, custom set the log file cut log parameters, json format, debug level log, example:
// InitWithOptions(
//
// WithFormat("json"),
// WithSave(true,
//
// WithFileName("my.log"),
// WithFileMaxSize(5),
// WithFileMaxBackups(5),
// WithFileMaxAge(10),
// WithFileIsCompression(true),
// ))
func InitWithOptions(opts ...Option) (*zap.Logger, error) {
o := defaultOptions()
o.apply(opts...)
isSave := o.isSave
levelName := o.level
encoding := o.encoding
var err error
var zapLog *zap.Logger
var str string
if !isSave {
zapLog, err = log2Terminal(levelName, encoding)
if err != nil {
panic(err)
}
str = fmt.Sprintf("[olog] config is output to 'terminal', format=%s, level=%s", encoding, levelName)
} else {
zapLog = log2File(encoding, levelName, o.fileConfig)
str = fmt.Sprintf("[olog] config is output to 'file', format=%s, level=%s, file=%s", encoding, levelName, o.fileConfig.filename)
}
if len(o.hooks) > 0 {
zapLog = zapLog.WithOptions(zap.Hooks(o.hooks...))
}
defaultLogger = zapLog
defaultSugaredLogger = defaultLogger.Sugar()
Info(str)
defaultZapWriter = InitZapWriter(defaultLogger)
return defaultLogger, err
}
func log2Terminal(levelName string, encoding string) (*zap.Logger, error) {
js := fmt.Sprintf(`{
"level": "%s",
"encoding": "%s",
"outputPaths": ["stdout"],
"errorOutputPaths": ["stdout"]
}`, levelName, encoding)
var config zap.Config
err := json.Unmarshal([]byte(js), &config)
if err != nil {
return nil, err
}
config.EncoderConfig = zap.NewProductionEncoderConfig()
if encoding == formatConsole {
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder // logging color
} else {
config.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // logging levels in the log file using upper case letters
}
config.EncoderConfig.EncodeTime = timeFormatter // default time format
return config.Build()
}
func log2File(encoding string, levelName string, fo *fileOptions) *zap.Logger {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder // modify Time Encoder
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // logging levels in the log file using upper case letters
var encoder zapcore.Encoder
if encoding == formatConsole { // console format
encoder = zapcore.NewConsoleEncoder(encoderConfig)
} else { // json format
encoder = zapcore.NewJSONEncoder(encoderConfig)
}
lbj := &lumberjack.Logger{
Filename: fo.filename, // file name
MaxSize: fo.maxSize, // maximum file size (MB)
MaxBackups: fo.maxBackups, // maximum number of old files
MaxAge: fo.maxAge, // maximum number of days for old documents
Compress: fo.isCompression, // whether to compress and archive old files
LocalTime: true,
}
mw := io.MultiWriter(lbj, os.Stdout)
ws := zapcore.AddSync(mw)
core := zapcore.NewCore(encoder, ws, getLevelSize(levelName))
// add the function call information log to the log.
return zap.New(core, zap.AddCaller())
}
// DEBUG(default), INFO, WARN, ERROR
func getLevelSize(levelName string) zapcore.Level {
levelName = strings.ToUpper(levelName)
switch levelName {
case levelDebug:
return zapcore.DebugLevel
case levelInfo:
return zapcore.InfoLevel
case levelWarn:
return zapcore.WarnLevel
case levelError:
return zapcore.ErrorLevel
}
return zapcore.DebugLevel
}
func timeFormatter(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}
// GetWithSkip get defaultLogger, set the skipped caller value, customize the number of lines of code displayed
func GetWithSkip(skip int) *zap.Logger {
checkNil()
return defaultLogger.WithOptions(zap.AddCallerSkip(skip))
}
// Get logger
func Get() *zap.Logger {
checkNil()
return defaultLogger
}
func GetZapWriter() *ZapWriter {
checkNil()
return defaultZapWriter
}
func checkNil() {
if defaultLogger == nil {
_, err := InitWithOptions() // default output to console
if err != nil {
panic(err)
}
}
}
func InitZapWriter(logger *zap.Logger) *ZapWriter {
return &ZapWriter{
logger: logger,
level: logger.Level(),
}
}
type ZapWriter struct {
logger *zap.Logger
level zapcore.Level // 日志级别(如 Info、Error)
}
// 实现 io.Writer 接口
func (w *ZapWriter) Write(p []byte) (n int, err error) {
msg := strings.TrimSuffix(string(p), "\n") // 去除 Gin 日志自带的换行符
switch w.level {
case zapcore.ErrorLevel:
w.logger.Error(msg)
default:
w.logger.Info(msg)
}
return len(p), nil
}
type ConfLog struct {
Level string
Path string
Max_size int
Max_backups int
Max_days int
Compress bool
}
package olog
import (
"fmt"
"os"
"strings"
"testing"
"time"
"go.uber.org/zap/zapcore"
)
func printInfo() {
defer func() {
recover()
}()
Debug("this is debug")
Debugf("this is debugf %d", 2)
Info("this is info")
Infof("this is infof %d", 2)
Warn("this is warn")
Warnf("this is warnf %d", 2)
Error("this is error")
Errorf("this is errorf %d", 2)
WithFields(Int("key", 2)).Info("this is info")
//Fatal("this is fatal")
//Fatalf("this is fatal %d", 2)
_ = Sync()
type people struct {
Name string `json:"name"`
Age int `json:"age"`
}
p := &people{"Mr Zhang", 11}
ps := []people{{"Mr Zhang", 11}, {"Mr Li", 12}}
pMap := map[string]*people{"123": p, "456": p}
Info("this is info object", Any("object1", p), Any("object2", ps), Any("object3", pMap)) // this sentence cannot be printed using debug
Panic("this is panic")
}
func TestInit(t *testing.T) {
type args struct {
opts []Option
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "terminal console debug",
args: args{},
wantErr: false,
},
{
name: "terminal json info",
args: args{[]Option{
WithFormat("json"), WithLevel("info"),
}},
wantErr: false,
},
{
name: "terminal json warn",
args: args{[]Option{
WithFormat("json"), WithLevel("warn"),
}},
wantErr: false,
},
{
name: "with hooks info",
args: args{[]Option{
WithFormat("json"),
WithLevel("info"),
WithHooks(func(entry zapcore.Entry) error {
if strings.Contains(entry.Message, "this is error") {
fmt.Println("it contains error message")
}
return nil
}),
}},
wantErr: false,
},
{
name: "file json debug",
args: args{[]Option{
WithFormat("json"), WithLevel("unknown"),
WithSave(
true,
WithFileName(os.TempDir()+"/testLog/my.log"),
WithFileMaxSize(5),
WithFileMaxBackups(5),
WithFileMaxAge(10),
WithFileIsCompression(true),
WithLocalTime(true),
),
}},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := InitWithOptions(tt.args.opts...)
if (err != nil) != tt.wantErr {
t.Errorf("Init() error = %v, wantErr %v", err, tt.wantErr)
return
}
printInfo()
})
}
time.Sleep(time.Second)
_ = os.RemoveAll("my.log")
}
func BenchmarkString(b *testing.B) {
for i := 0; i < b.N; i++ {
Info("this is info", String("string", "hello golang"))
}
}
func BenchmarkInt(b *testing.B) {
for i := 0; i < b.N; i++ {
Info("benchmark type int", Int("int", i))
}
}
func BenchmarkAny(b *testing.B) {
for i := 0; i < b.N; i++ {
Info("benchmark type any", Any(fmt.Sprintf("object_%d", i), map[string]int{"Mr Zhang": 11}))
}
}
func Test_getLevelSize(t *testing.T) {
_ = getLevelSize(levelDebug)
_ = getLevelSize(levelInfo)
_ = getLevelSize(levelWarn)
_ = getLevelSize(levelWarn)
_ = getLevelSize(levelError)
_ = getLevelSize("unknown")
defaultLogger = nil
_ = GetWithSkip(5)
_ = Get()
}
package olog
import (
"strings"
"go.uber.org/zap"
)
// Debug level information
func Debug(msg string, fields ...Field) {
getLogger().Debug(msg, fields...)
}
// Info level information
func Info(msg string, fields ...Field) {
getLogger().Info(msg, fields...)
}
// Warn level information
func Warn(msg string, fields ...Field) {
getLogger().Warn(msg, fields...)
}
// Error level information
func Error(msg string, fields ...Field) {
getLogger().Error(msg, fields...)
}
// Panic level information
func Panic(msg string, fields ...Field) {
getLogger().Panic(msg, fields...)
}
// Fatal level information
func Fatal(msg string, fields ...Field) {
getLogger().Fatal(msg, fields...)
}
// Debugf format level information
func Debugf(format string, a ...interface{}) {
getSugaredLogger().Debugf(format, a...)
}
// Infof format level information
func Infof(format string, a ...interface{}) {
getSugaredLogger().Infof(format, a...)
}
// Warnf format level information
func Warnf(format string, a ...interface{}) {
getSugaredLogger().Warnf(format, a...)
}
// Errorf format level information
func Errorf(format string, a ...interface{}) {
getSugaredLogger().Errorf(format, a...)
}
// Fatalf format level information
func Fatalf(format string, a ...interface{}) {
getSugaredLogger().Fatalf(format, a...)
}
// Sync flushing any buffered log entries, applications should take care to call Sync before exiting.
func Sync() error {
_ = getSugaredLogger().Sync()
err := getLogger().Sync()
if err != nil && !strings.Contains(err.Error(), "/dev/stdout") {
return err
}
return nil
}
// WithFields carrying field information
func WithFields(fields ...Field) *zap.Logger {
return GetWithSkip(0).With(fields...)
}
package olog
import (
"strings"
"go.uber.org/zap/zapcore"
)
var (
defaultLevel = "debug" // output log levels debug, info, warn, error, default is debug
defaultEncoding = formatConsole
defaultIsSave = false // false:output to terminal, true:output to file, default is false
defaultFilename = "out.log" // file name
defaultMaxSize = 100 // maximum file size (MB)
defaultMaxBackups = 10000 // maximum number of old files
defaultMaxAge = 180 // maximum number of days for old documents
defaultIsCompression = true // whether to compress and archive old files
defaultIsLocalTime = true // whether to use local time
)
type options struct {
level string
encoding string
isSave bool
fileConfig *fileOptions
hooks []func(zapcore.Entry) error
}
func defaultOptions() *options {
return &options{
level: defaultLevel,
encoding: defaultEncoding,
isSave: defaultIsSave,
}
}
func (o *options) apply(opts ...Option) {
for _, opt := range opts {
opt(o)
}
}
// Option set the logger options.
type Option func(*options)
// WithLevel setting the log level
func WithLevel(levelName string) Option {
return func(o *options) {
levelName = strings.ToUpper(levelName)
switch levelName {
case levelDebug, levelInfo, levelWarn, levelError:
o.level = levelName
default:
o.level = levelDebug
}
}
}
// WithFormat set the output log format, console or json
func WithFormat(format string) Option {
return func(o *options) {
if strings.ToLower(format) == formatJSON {
o.encoding = formatJSON
}
}
}
// WithSave save log to file
func WithSave(isSave bool, opts ...FileOption) Option {
return func(o *options) {
if isSave {
o.isSave = true
fo := defaultFileOptions()
fo.apply(opts...)
o.fileConfig = fo
}
}
}
// WithHooks set the log hooks
func WithHooks(hooks ...func(zapcore.Entry) error) Option {
return func(o *options) {
o.hooks = hooks
}
}
// ------------------------------------------------------------------------------------------
type fileOptions struct {
filename string
maxSize int
maxBackups int
maxAge int
isCompression bool
isLocalTime bool
}
func defaultFileOptions() *fileOptions {
return &fileOptions{
filename: defaultFilename,
maxSize: defaultMaxSize,
maxBackups: defaultMaxBackups,
maxAge: defaultMaxAge,
isCompression: defaultIsCompression,
isLocalTime: defaultIsLocalTime,
}
}
func (o *fileOptions) apply(opts ...FileOption) {
for _, opt := range opts {
opt(o)
}
}
// FileOption set the file options.
type FileOption func(*fileOptions)
// WithFileName set log filename
func WithFileName(filename string) FileOption {
return func(f *fileOptions) {
if filename != "" {
f.filename = filename
}
}
}
// WithFileMaxSize set maximum file size (MB)
func WithFileMaxSize(maxSize int) FileOption {
return func(f *fileOptions) {
if maxSize > 0 {
f.maxSize = maxSize
}
}
}
// WithFileMaxBackups set maximum number of old files
func WithFileMaxBackups(maxBackups int) FileOption {
return func(f *fileOptions) {
if f.maxBackups > 0 {
f.maxBackups = maxBackups
}
}
}
// WithFileMaxAge set maximum number of days for old documents
func WithFileMaxAge(maxAge int) FileOption {
return func(f *fileOptions) {
if f.maxAge > 0 {
f.maxAge = maxAge
}
}
}
// WithFileIsCompression set whether to compress log files
func WithFileIsCompression(isCompression bool) FileOption {
return func(f *fileOptions) {
f.isCompression = isCompression
}
}
// WithLocalTime set whether to use local time
func WithLocalTime(isLocalTime bool) FileOption {
return func(f *fileOptions) {
f.isLocalTime = isLocalTime
}
}
package olog
import (
"fmt"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// Field type
type Field = zapcore.Field
// Int type
func Int(key string, val int) Field {
return zap.Int(key, val)
}
// Int32 type
func Int32(key string, val int32) Field {
return zap.Int32(key, val)
}
// Int64 type
func Int64(key string, val int64) Field {
return zap.Int64(key, val)
}
// Uint type
func Uint(key string, val uint) Field {
return zap.Uint(key, val)
}
// Uint32 type
func Uint32(key string, val uint32) Field {
return zap.Uint32(key, val)
}
// Uint64 type
func Uint64(key string, val uint64) Field {
return zap.Uint64(key, val)
}
// Uintptr type
func Uintptr(key string, val uintptr) Field {
return zap.Uintptr(key, val)
}
// Float64 type
func Float64(key string, val float64) Field {
return zap.Float64(key, val)
}
// Bool type
func Bool(key string, val bool) Field {
return zap.Bool(key, val)
}
// String type
func String(key string, val string) Field {
return zap.String(key, val)
}
// ByteString type
func ByteString(key string, val []byte) Field {
return zap.ByteString(key, val)
}
// Stringer type
func Stringer(key string, val fmt.Stringer) Field {
return zap.Stringer(key, val)
}
// Time type
func Time(key string, val time.Time) Field {
return zap.Time(key, val)
}
// Duration type
func Duration(key string, val time.Duration) Field {
return zap.Duration(key, val)
}
// Err type
func Err(err error) Field {
return zap.Error(err)
}
// Any type, if it is a composite type such as object, slice, map, etc., use Any
func Any(key string, val interface{}) Field {
return zap.Any(key, val)
}
package olog
import (
"errors"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestAny(t *testing.T) {
field := Any("key", []int{1, 2, 3})
assert.NotNil(t, field)
}
func TestBool(t *testing.T) {
field := Bool("key", true)
assert.NotNil(t, field)
}
func TestDuration(t *testing.T) {
field := Duration("key", time.Second)
assert.NotNil(t, field)
}
func TestErr(t *testing.T) {
field := Err(errors.New("err"))
assert.NotNil(t, field)
}
func TestFloat64(t *testing.T) {
field := Float64("key", 3.14)
assert.NotNil(t, field)
}
func TestInt(t *testing.T) {
field := Int("key", 1)
assert.NotNil(t, field)
}
func TestInt32(t *testing.T) {
field := Int32("key", 1)
assert.NotNil(t, field)
}
func TestInt64(t *testing.T) {
field := Int64("key", 1)
assert.NotNil(t, field)
}
func TestString(t *testing.T) {
field := String("key", "bar")
assert.NotNil(t, field)
}
func TestByteString(t *testing.T) {
field := ByteString("key", []byte("bar"))
assert.NotNil(t, field)
}
func TestStringer(t *testing.T) {
field := Stringer("key", new(st))
assert.NotNil(t, field)
}
func TestTime(t *testing.T) {
field := Time("key", time.Now())
assert.NotNil(t, field)
}
func TestUint(t *testing.T) {
field := Uint("key", 1)
assert.NotNil(t, field)
}
func TestUint32(t *testing.T) {
field := Uint32("key", 1)
assert.NotNil(t, field)
}
func TestUint64(t *testing.T) {
field := Uint64("key", 1)
assert.NotNil(t, field)
}
func TestUintptr(t *testing.T) {
testData := 1
field := Uintptr("key", uintptr(testData))
assert.NotNil(t, field)
}
type st struct{}
func (s *st) String() string {
return "string"
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论