diff --git a/.gitignore b/.gitignore index e87b67d..a0b56cd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ __debug* *.copy binds.json critical -log/ +./log/ tmp.json -data/* \ No newline at end of file +data/* +*.gz \ No newline at end of file diff --git a/ZeroBot/bot.go b/ZeroBot/bot.go index 266d4eb..a92ad1d 100644 --- a/ZeroBot/bot.go +++ b/ZeroBot/bot.go @@ -95,7 +95,7 @@ func Run(op *Config) { // RunAndBlock 主函数初始化并阻塞 // -// preblock 在所有 Driver 连接后,调用最后一个 Driver 的 Listen 阻塞前执行本函数 +// 除最后一个Driver都用go实现非阻塞 func RunAndBlock(op *Config, preblock func()) { if !atomic.CompareAndSwapUintptr(&isrunning, 0, 1) { log.Warnln("[bot] 已忽略重复调用的 RunAndBlock") @@ -125,6 +125,7 @@ func RunAndBlock(op *Config, preblock func()) { if preblock != nil { preblock() } + // listen是for死循环 会阻塞 op.Driver[i].Listen(listenCallback) } } diff --git a/ZeroBot/context.go b/ZeroBot/context.go index 3d5587b..af5e5c4 100644 --- a/ZeroBot/context.go +++ b/ZeroBot/context.go @@ -22,10 +22,15 @@ type Ctx struct { // lazy message once sync.Once message string - err error + Err error } // func (ctx ) +func (ctx *Ctx) GetMatcherMetadata() MatcherMetadata { + return MatcherMetadata{ + PluginName: ctx.ma.Engine.MetaData.Name, + } +} // GetMatcher ... func (ctx *Ctx) GetMatcher() *Matcher { @@ -117,7 +122,7 @@ func (ctx *Ctx) SendChain(msg ...message.MessageSegment) message.MessageID { } func (ctx *Ctx) SendError(text string, err error) message.MessageID { - ctx.err = err + ctx.Err = err name := ctx.ma.Engine.MetaData.Name if name == "" { name = "default" diff --git a/ZeroBot/matcher.go b/ZeroBot/matcher.go index aa18b09..099d97b 100644 --- a/ZeroBot/matcher.go +++ b/ZeroBot/matcher.go @@ -12,6 +12,11 @@ type ( Handler func(ctx *Ctx) ) +type MatcherMetadata struct { + PluginName string + MatcherName string +} + // Matcher 是 ZeroBot 匹配和处理事件的最小单元 type Matcher struct { // Temp 是否为临时Matcher,临时 Matcher 匹配一次后就会删除当前 Matcher @@ -31,7 +36,8 @@ type Matcher struct { // Handler 处理事件的函数 Handler Handler // Engine 注册 Matcher 的 Engine,Engine可为一系列 Matcher 添加通用 Rule 和 其他钩子 - Engine *Engine + Engine *Engine + matcherMetadata *MatcherMetadata } var ( diff --git a/log/error b/log/error new file mode 120000 index 0000000..3806e4e --- /dev/null +++ b/log/error @@ -0,0 +1 @@ +log/error-20240905.log \ No newline at end of file diff --git a/main.go b/main.go index 542c585..77ee195 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "MiniBot/utils" _ "MiniBot/utils/db" _ "MiniBot/utils/log" - "fmt" // ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- // _ "MiniBot/plugin/asill" @@ -53,5 +52,4 @@ func main() { }() } zero.RunAndBlock(&config.Config.Z, utils.GlobalInitMutex.Unlock) - fmt.Println("能运行到这?") } diff --git a/plugin/monitor/prometheus.go b/plugin/monitor/prometheus.go index c82a5ad..9422b5c 100644 --- a/plugin/monitor/prometheus.go +++ b/plugin/monitor/prometheus.go @@ -2,6 +2,8 @@ package monitor import ( "MiniBot/service/web" + zero "ZeroBot" + "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" @@ -35,4 +37,25 @@ func init() { r := web.GetWebEngine() r.GET("/metrics", gin.WrapH(promhttp.Handler())) + zero.GolbaleMiddleware.Before( + func(ctx *zero.Ctx) { + ctx.State["time"] = time.Now() + }, + ) + zero.GolbaleMiddleware.After( + func(ctx *zero.Ctx) { + startTime := ctx.State["time"].(time.Time) + status := "ok" + if ctx.Err != nil { + status = "err" + ctx.Err = nil + } + pluginName := ctx.GetMatcherMetadata().PluginName + if pluginName == "" { + pluginName = "default" + } + RequestsTotal.WithLabelValues(pluginName, "", status).Inc() + ResponseTime.WithLabelValues(pluginName, "", status).Observe(float64(time.Since(startTime).Microseconds()) / 1000) + }, + ) } diff --git a/plugin/score/sign_in.go b/plugin/score/sign_in.go index 55e87ee..920b45f 100644 --- a/plugin/score/sign_in.go +++ b/plugin/score/sign_in.go @@ -11,8 +11,9 @@ import ( "errors" "fmt" "io" + "io/fs" "math" - "math/rand" + "math/rand/v2" "net/http" "os" "path/filepath" @@ -42,6 +43,7 @@ const ( ) var ( + cachePath string rankArray = [...]int{0, 10, 20, 50, 100, 200, 350, 550, 750, 1000, 1200} metaData = &zero.MetaData{ @@ -58,7 +60,7 @@ var ( ) func init() { - cachePath := filepath.Join(path.GetDataPath(), "cache") + cachePath = filepath.Join(path.GetDataPath(), "cache") sdb = initialize() file.CreateIfNotExist(cachePath) @@ -122,7 +124,7 @@ func init() { } // 更新钱包 rank := getrank(level) - add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高 + add := 1 + rand.IntN(10) + rank*5 // 等级越高获得的钱越高 go func() { err = wallet.UpdateWalletByCtx(ctx, add) if err != nil { @@ -320,19 +322,33 @@ func initPic(picFile string, uid int64) (avatar []byte, err error) { request, _ := http.NewRequest("GET", url, nil) request.Header.Add("referer", referer) response, err = http.DefaultClient.Do(request) - data := []byte{} - if err == nil { - if response.StatusCode != http.StatusOK { - s := fmt.Sprintf("status code: %d", response.StatusCode) - err = errors.New(s) + + if response.StatusCode != http.StatusOK { + + s := fmt.Sprintf("status code: %d", response.StatusCode) + err = errors.New(s) + } + + var data []byte + if err != nil { + var files []fs.DirEntry + files, err = os.ReadDir(cachePath) + if err != nil { return } + randomIndex := rand.IntN(len(files)) + selectedFile := files[randomIndex] + + data, err = os.ReadFile(filepath.Join(cachePath, selectedFile.Name())) + } else { data, err = io.ReadAll(response.Body) - response.Body.Close() } + if err != nil { return } + response.Body.Close() + return avatar, os.WriteFile(picFile, data, 0644) } diff --git a/utils/log/log.go b/utils/log/log.go new file mode 100644 index 0000000..04c05b8 --- /dev/null +++ b/utils/log/log.go @@ -0,0 +1,106 @@ +package log + +import ( + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "time" + + rotatelogs "github.com/lestrrat/go-file-rotatelogs" + "github.com/sirupsen/logrus" +) + +func init() { + logLevel := logrus.InfoLevel + + logrus.SetLevel(logLevel) + + // 设置输出格式为自定义的TextFormatter + logrus.SetFormatter(&logrus.TextFormatter{ + DisableColors: false, // 禁用颜色 + FullTimestamp: true, // 显示完整时间戳 + TimestampFormat: "2006-01-02T15:04:05.000", // 时间戳格式,精确到毫秒 + CallerPrettyfier: func(f *runtime.Frame) (string, string) { + return "", fmt.Sprintf(" %s:%d", filepath.Base(f.File), f.Line) + }, + }) + + logFolder := "./log" + err := os.MkdirAll(logFolder, 0755) + if err != nil { + logrus.Fatalf("Error creating directory") + } + + levelList := []logrus.Level{} + for i := 0; i <= int(logLevel); i++ { + levelList = append(levelList, logrus.Level(i)) + } + criticalHook := FileHook{ + writer: writer("./log", "critical", 10), + levels: levelList, + } + logrus.AddHook(&criticalHook) + + errHook := FileHook{ + writer: writer("./log", "error", 10), + levels: []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}, + } + + logrus.AddHook(&errHook) + +} + +/* +log文件设置 format:log/level2006-01-02.log +*/ +func writer(logPath string, level string, save int) *rotatelogs.RotateLogs { + logFullPath := filepath.Join(logPath, level) + // var cstSh, _ = time.LoadLocation("Asia/Shanghai") //上海 + // fileSuffix := time.Now().In(cstSh).Format("2006-01-02") + ".log" + + logier, err := rotatelogs.New( + logFullPath+"-"+"%Y%m%d"+".log", + rotatelogs.WithLinkName(logFullPath), // 生成软链,指向最新日志文件 + rotatelogs.WithRotationCount(save), // 文件最大保存份数 负数到0说明保存无限 + rotatelogs.WithRotationTime(time.Hour*24), // 日志切割时间间隔 + ) + + if err != nil { + panic(err) + } + return logier +} + +type FileHook struct { + writer io.Writer + levels []logrus.Level +} + +func (hook *FileHook) Levels() []logrus.Level { + return hook.levels +} + +func (hook *FileHook) Fire(entry *logrus.Entry) error { + // 创建一个TextFormatter(不带颜色)来输出到文件 + formatter := &logrus.TextFormatter{ + DisableColors: true, // 禁用颜色 + FullTimestamp: true, // 显示完整时间戳 + TimestampFormat: "2006-01-02T15:04:05.000", + } + + // 格式化日志条目 + line, err := formatter.Format(entry) + if err != nil { + return err + } + + // 写入文件 + _, err = hook.writer.Write(line) + if err != nil { + return err + } + + return nil +}