go17/book/config/config.go
2024-11-23 15:17:11 +08:00

229 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"sync"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/pkgerrors"
"gopkg.in/natefinch/lumberjack.v2"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 定义程序配置
// dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
// 凡是可以提出出配置的
// 程序的配置对象
type Config struct {
App *App `json:"app"`
MySQL *MySQL `json:"mysql"`
Log *Log `json:"log"`
}
// &{0x102317ec0 0x10231c8a0}
//
// String() string, fmt.Strigger接口
//
// fmt.
func (c *Config) String() string {
v, _ := json.Marshal(c)
return string(v)
}
// app:
//
// host: 127.0.0.1
// port: 8080
type App struct {
Host string `json:"host"`
Port int `json:"port"`
}
func (c *App) Address() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
// mysql:
//
// host: 127.0.0.1
// port: 3306
// database: test
// username: "root"
// password: "123456"
// debug: true
type MySQL struct {
Host string `json:"host"`
Port int `json:"port"`
Database string `json:"database"`
Username string `json:"username"`
Password string `json:"password"`
Debug bool `json:"debug"`
db *gorm.DB
lock sync.Mutex
}
// 初始化数据库, 能过与数据库交互的 连接池对象: db
// 复用, 只要有就用 之前的没有才初始化新的db对象
func (c *MySQL) DB() *gorm.DB {
c.lock.Lock()
defer c.lock.Unlock()
if c.db == nil {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
c.Username,
c.Password,
c.Host,
c.Port,
c.Database,
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
if c.Debug {
db = db.Debug()
}
c.db = db
}
return c.db
}
// 怎么配置
// 是否要打印到控制台
// 是否要打印到文件里,是否要轮转 100M 5
type Log struct {
// 0 为打印日志全路径, 默认打印2层路径
CallerDeep int `toml:"caller_deep" json:"caller_deep" yaml:"caller_deep" env:"CALLER_DEEP"`
// 日志的级别, 默认Debug
Level zerolog.Level `toml:"level" json:"level" yaml:"level" env:"LEVEL"`
// 控制台日志配置
Console Console `toml:"console" json:"console" yaml:"console" envPrefix:"CONSOLE_"`
// 日志文件配置
File File `toml:"file" json:"file" yaml:"file" envPrefix:"FILE_"`
root *zerolog.Logger
lock sync.Mutex
}
type Console struct {
Enable bool `toml:"enable" json:"enable" yaml:"enable" env:"ENABLE"`
NoColor bool `toml:"no_color" json:"no_color" yaml:"no_color" env:"NO_COLOR"`
}
func (c *Console) ConsoleWriter() io.Writer {
output := zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
w.NoColor = c.NoColor
w.TimeFormat = time.RFC3339
})
output.FormatLevel = func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("%-6s", i))
}
output.FormatMessage = func(i interface{}) string {
return fmt.Sprintf("%s", i)
}
output.FormatFieldName = func(i interface{}) string {
return fmt.Sprintf("%s:", i)
}
output.FormatFieldValue = func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("%s", i))
}
return output
}
type File struct {
// 是否开启文件记录
Enable bool `toml:"enable" json:"enable" yaml:"enable" env:"ENABLE"`
// 文件的路径
FilePath string `toml:"file_path" json:"file_path" yaml:"file_path" env:"PATH"`
// 单位M, 默认100M
MaxSize int `toml:"max_size" json:"max_size" yaml:"max_size" env:"MAX_SIZE"`
// 默认保存 6个文件
MaxBackups int `toml:"max_backups" json:"max_backups" yaml:"max_backups" env:"MAX_BACKUPS"`
// 保存多久
MaxAge int `toml:"max_age" json:"max_age" yaml:"max_age" env:"MAX_AGE"`
// 是否压缩
Compress bool `toml:"compress" json:"compress" yaml:"compress" env:"COMPRESS"`
}
func (f *File) FileWriter() io.Writer {
return &lumberjack.Logger{
Filename: f.FilePath,
MaxSize: f.MaxSize,
MaxAge: f.MaxAge,
MaxBackups: f.MaxBackups,
Compress: f.Compress,
}
}
func (l *Log) Logger() *zerolog.Logger {
l.lock.Lock()
defer l.lock.Unlock()
if l.root == nil {
var writers []io.Writer
if l.Console.Enable {
writers = append(writers, l.Console.ConsoleWriter())
}
if l.File.Enable {
if l.File.FilePath == "" {
l.File.FilePath = "logs/app.log"
}
writers = append(writers, l.File.FileWriter())
}
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
// logger对象配置一些上下文信息: 2024-11-23T15:11:42+08:00
// 带上中间信息Any
// book/controller/book.go:60
root := zerolog.New(io.MultiWriter(writers...)).With().Timestamp().Any("服务", "book-api")
if l.CallerDeep > 0 {
zerolog.CallerMarshalFunc = l.CallerMarshalFunc
root = root.Caller()
}
// 带有这些上下文信息的Logger对象 提前出来作为全局Logger对象供全局使用
l.SetRoot(root.Logger().Level(l.Level))
}
return l.root
}
func (m *Log) SetRoot(v zerolog.Logger) {
m.root = &v
}
func (m *Log) CallerMarshalFunc(pc uintptr, file string, line int) string {
if m.CallerDeep == 0 {
return file
}
short := file
count := 0
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
count++
}
if count >= m.CallerDeep {
break
}
}
file = short
return file + ":" + strconv.Itoa(line)
}