完成日志输出到文件、终端多处的处理

This commit is contained in:
2024-11-13 16:11:59 +08:00
parent 9b643f4352
commit 28291598bb
28 changed files with 175 additions and 330 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/logs
*.mp3

View File

@@ -6,7 +6,7 @@ package cmd
import (
"game-driver/config"
"game-driver/internal"
"game-driver/pkg/logger"
"log"
"os"
"github.com/spf13/cobra"
@@ -56,11 +56,11 @@ func initConfig() {
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
logger.Infof("Using config file: %s", viper.ConfigFileUsed())
log.Printf("Using config file: %s", viper.ConfigFileUsed())
}
err := viper.Unmarshal(&config.C)
if err != nil {
logger.Panicln("unmarshal config failed: ", err)
log.Panicln("unmarshal config failed: ", err)
}
}

View File

@@ -1,13 +1,6 @@
package config
type config struct {
Location string
Point int
Relay string
Mqtt MqttConfig
Aliyun AliyunConfig
Game GameConfig
}
import "gopkg.in/natefinch/lumberjack.v2"
type MqttConfig struct {
Url string
@@ -24,4 +17,19 @@ type GameConfig struct {
MaxTimeout int
}
type Logger struct {
File *lumberjack.Logger
Level string
}
type config struct {
Location string
Point int
Relay string
Log Logger
Mqtt MqttConfig
Aliyun AliyunConfig
Game GameConfig
}
var C config

14
go.mod
View File

@@ -9,10 +9,12 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
go.bug.st/serial v1.6.2
go.uber.org/zap v1.27.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.63.45 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.51 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/ebitengine/oto/v3 v3.3.1 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
@@ -38,13 +40,11 @@ require (
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

22
go.sum
View File

@@ -3,8 +3,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1376/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.45 h1:H74VbmrHgZcb7MN9ud8panaIXtY1nLgHZRWjJv2gyKU=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.45/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.51 h1:ezfQdoOrqK7xa0+t8uw7ih2TFA/dm/bTH+U0/0Y++7g=
github.com/aliyun/alibaba-cloud-sdk-go v1.63.51/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1 h1:LjItoNZuu5xHlsByFo+kr3nGa4LRIESCGWhfurayxBg=
github.com/aliyun/alibabacloud-nls-go-sdk v1.1.1/go.mod h1:4BDMUKpEaP/Ct79w0ozR0nbnEj49g1k3mrgX/IKG5I4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -137,8 +137,8 @@ golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -147,18 +147,18 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -178,6 +178,8 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -3,9 +3,9 @@ package common
import (
"context"
"fmt"
"game-driver/pkg/logger"
"github.com/eclipse/paho.golang/autopaho"
"github.com/eclipse/paho.golang/paho"
"go.uber.org/zap"
"sync"
"sync/atomic"
)
@@ -30,14 +30,14 @@ func (d *Device) Lock() {
defer d.OnChange()
d.mu.Lock()
d.status.Store(1)
logger.Infoln("设备上锁")
zap.S().Infoln("设备上锁")
}
func (d *Device) Unlock() {
defer d.OnChange()
d.status.Store(0)
d.mu.Unlock()
logger.Infoln("设备解锁")
zap.S().Infoln("设备解锁")
}
func (d *Device) Status() int {

View File

@@ -4,9 +4,9 @@ import (
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/audio"
"game-driver/pkg/logger"
"game-driver/pkg/utils"
"github.com/gopxl/beep/v2/speaker"
"go.uber.org/zap"
"sync"
)
@@ -17,10 +17,10 @@ func PlayBgm() leaf.HandlerFunc {
bgm, err := utils.LinkAudio(pm.BGM)
if err != nil {
logger.Errorln("背景音乐数据解析异常:", err)
zap.S().Errorln("背景音乐数据解析异常:", err)
}
if bgm != nil {
logger.Infoln("背景音乐解析成功")
zap.S().Infoln("背景音乐解析成功")
// 等待组
var wait sync.WaitGroup
defer wait.Wait()
@@ -34,13 +34,13 @@ func PlayBgm() leaf.HandlerFunc {
go func() {
defer wait.Done()
logger.Infoln("开始播放背景音乐")
defer logger.Infoln("结束背景音乐播放")
zap.S().Infoln("开始播放背景音乐")
defer zap.S().Infoln("结束背景音乐播放")
ctrl, closer, e := audio.PlayBgmMP3(bgm)
defer closer()
if e != nil {
logger.Errorln("播放背景音乐异常:", e)
zap.S().Errorln("播放背景音乐异常:", e)
return
}
@@ -55,7 +55,7 @@ func PlayBgm() leaf.HandlerFunc {
}
}()
} else {
logger.Errorln("背景音乐解析为空")
zap.S().Errorln("背景音乐解析为空")
}
c.Next()

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
)
type JSONKey string
@@ -17,7 +17,7 @@ func PayloadJSON[T schema.JsonModel]() leaf.HandlerFunc {
pm := new(T)
err := json.Unmarshal(c.Payload, pm)
if err != nil {
logger.Panicln("报文解析错误", err)
zap.S().Panicln("报文解析错误", err)
}
leaf.WithValue[*T](c, PayloadJSONKey, pm)
c.Next()

View File

@@ -2,13 +2,13 @@ package middleware
import (
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
)
func RunLog() leaf.HandlerFunc {
return func(c *leaf.Context) {
logger.Infof("收到消息, topic: %s, payload: %s", c.Topic, c.Payload)
defer logger.Infof("处理结束")
zap.S().Infof("收到消息, topic: %s, payload: %s", c.Topic, c.Payload)
defer zap.S().Infof("处理结束")
c.Next()
}

View File

@@ -3,8 +3,8 @@ package middleware
import (
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"game-driver/pkg/relay"
"go.uber.org/zap"
)
// RelayMaster 继电器中间件
@@ -15,10 +15,10 @@ func RelayMaster(r *relay.Device) leaf.HandlerFunc {
r.On(1)
defer r.Off(1)
logger.Infoln("开启电源")
defer logger.Infoln("关闭电源")
zap.S().Infoln("开启电源")
defer zap.S().Infoln("关闭电源")
} else {
logger.Infoln("继电器未开启/不需要电源控制")
zap.S().Infoln("继电器未开启/不需要电源控制")
}
c.Next()
}

View File

@@ -3,7 +3,7 @@ package middleware
import (
"game-driver/internal/common"
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
)
// EmergencyStop 紧急停止中间件
@@ -17,15 +17,15 @@ func EmergencyStop(stopper common.Stopper) leaf.HandlerFunc {
// 发送结束信号
defer close(a)
logger.Infoln("监听停止信号")
zap.S().Infoln("监听停止信号")
go func() {
defer logger.Infoln("结束停止信号监听")
defer zap.S().Infoln("结束停止信号监听")
select {
case <-a:
case <-stopper.Done():
{
logger.Infoln("停止信号触发")
zap.S().Infoln("停止信号触发")
cancel()
leaf.WithValue[leaf.EndType](c, leaf.EndKey, leaf.EndStop)
}

View File

@@ -3,8 +3,8 @@ package middleware
import (
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"game-driver/pkg/tts"
"go.uber.org/zap"
"sync"
"time"
)
@@ -40,8 +40,8 @@ func TickerAction() leaf.HandlerFunc {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
logger.Infoln("开始 Ticker 计时")
defer logger.Infoln("结束 Ticker 计时")
zap.S().Infoln("开始 Ticker 计时")
defer zap.S().Infoln("结束 Ticker 计时")
for over := false; !over; {
select {

View File

@@ -3,7 +3,7 @@ package middleware
import (
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
"sync"
"time"
)
@@ -36,15 +36,15 @@ func TimeoutOver(maxTimeout int) leaf.HandlerFunc {
go func() {
defer wait.Done()
logger.Infoln("超时 Timer 监控开始")
defer logger.Infoln("超时 Timer 监控结束")
zap.S().Infoln("超时 Timer 监控开始")
defer zap.S().Infoln("超时 Timer 监控结束")
// 结束标志
select {
case <-a:
case <-timer.C: // 定时器结束
{
logger.Infoln("超时 Timer 触发")
zap.S().Infoln("超时 Timer 触发")
cancel()
leaf.WithValue[leaf.EndType](c, leaf.EndKey, leaf.EndTimer)
}

View File

@@ -3,7 +3,7 @@ package middleware
import (
"game-driver/internal/common"
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
"sync"
)
@@ -12,15 +12,15 @@ func Unique(stopper common.Stopper) leaf.HandlerFunc {
var lock sync.Mutex
return func(c *leaf.Context) {
if !lock.TryLock() {
logger.Infoln("尝试加锁失败,执行停止任务")
zap.S().Infoln("尝试加锁失败,执行停止任务")
stopper.Stop()
lock.Lock()
}
logger.Infoln("加锁完成")
zap.S().Infoln("加锁完成")
defer func() {
lock.Unlock()
logger.Infoln("解锁完成")
zap.S().Infoln("解锁完成")
}()
c.Next()

View File

@@ -3,7 +3,7 @@ package routes
import (
"game-driver/internal/common"
"game-driver/leaf"
"game-driver/pkg/logger"
"go.uber.org/zap"
)
func Command(d *common.Device) leaf.HandlerFunc {
@@ -17,7 +17,7 @@ func Command(d *common.Device) leaf.HandlerFunc {
case "status":
d.PublishStatus()
default:
logger.Infof("接收到无效指令: %s\n", cmd)
zap.S().Infof("接收到无效指令: %s\n", cmd)
}
}
}

View File

@@ -4,9 +4,9 @@ import (
"game-driver/internal/middleware"
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"game-driver/pkg/utils"
"game-driver/pkg/video"
"go.uber.org/zap"
)
func OnlyVideo(c *leaf.Context) {
@@ -18,7 +18,7 @@ func OnlyVideo(c *leaf.Context) {
if url, ok := payload.Game["video"]; ok {
local, err := utils.LinkVideo(url.(string))
if err != nil {
logger.Errorln("视频文件获取异常: ", err)
zap.S().Errorln("视频文件获取异常: ", err)
return
}
_ = video.Play(c, local)

View File

@@ -5,12 +5,12 @@ import (
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/audio"
"game-driver/pkg/logger"
"game-driver/pkg/relay"
"game-driver/pkg/tts"
"game-driver/pkg/utils"
"game-driver/pkg/video"
"github.com/gopxl/beep/v2/speaker"
"go.uber.org/zap"
"sync"
"time"
)
@@ -34,7 +34,7 @@ func WaitAction(c *leaf.Context) {
payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey)
if payload.Start != 0 && payload.End != 0 && time.Unix(payload.Start, 0).After(time.Unix(payload.End, 0)) {
logger.Infoln("开始时间大于结束时间")
zap.S().Infoln("开始时间大于结束时间")
return
}
@@ -81,7 +81,7 @@ func WaitAction(c *leaf.Context) {
}()
case schema.WaitWeb:
default:
logger.Infof("不支持的类型: %d\n", item.Type)
zap.S().Infof("不支持的类型: %d\n", item.Type)
}
}
}
@@ -89,7 +89,7 @@ func WaitAction(c *leaf.Context) {
func audioAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel) {
if item.Start != 0 && time.Unix(item.Start, 0).Before(time.Unix(root.Start, 0)) {
logger.Infoln("开始时间小于根任务开始时间")
zap.S().Infoln("开始时间小于根任务开始时间")
return
}
@@ -100,7 +100,7 @@ func audioAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
data, err := utils.LinkAudio(item.Data)
if err != nil {
logger.Errorln("音频数据获取异常: ", err)
zap.S().Errorln("音频数据获取异常: ", err)
return
}
@@ -108,13 +108,13 @@ func audioAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
case <-c.Done():
case <-timerAction(item.Start):
{
logger.Infoln("播放待机音乐")
defer logger.Infoln("结束待机音乐")
zap.S().Infoln("播放待机音乐")
defer zap.S().Infoln("结束待机音乐")
ctrl, closer, e := audio.PlayBgmMP3(data)
defer closer()
if e != nil {
logger.Errorln("播放待机音乐异常", e)
zap.S().Errorln("播放待机音乐异常", e)
return
}
@@ -132,7 +132,7 @@ func audioAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
func ttsAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel) {
if item.Start != 0 && time.Unix(item.Start, 0).Before(time.Unix(root.Start, 0)) {
logger.Infoln("开始时间小于根任务开始时间")
zap.S().Infoln("开始时间小于根任务开始时间")
return
}
@@ -143,7 +143,7 @@ func ttsAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel
reader, err := tts.DefaultTTS.Get(item.Data)
if err != nil {
logger.Errorln("语音合成异常: ", err)
zap.S().Errorln("语音合成异常: ", err)
return
}
@@ -151,8 +151,8 @@ func ttsAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel
case <-c.Done():
case <-timerAction(item.Start):
{
logger.Infoln("循环播放待机 TTS 语音")
defer logger.Infoln("结束待机 TTS 语音")
zap.S().Infoln("循环播放待机 TTS 语音")
defer zap.S().Infoln("结束待机 TTS 语音")
for {
audio.PlayWav(c, reader)
@@ -168,7 +168,7 @@ func ttsAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel
func relayAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel) {
if item.Start != 0 && time.Unix(item.Start, 0).Before(time.Unix(root.Start, 0)) {
logger.Infoln("开始时间小于根任务开始时间")
zap.S().Infoln("开始时间小于根任务开始时间")
return
}
@@ -179,7 +179,7 @@ func relayAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
device, err := relay.New(item.Data, nil)
if err != nil {
logger.Errorln("继电器初始化异常: ", err)
zap.S().Errorln("继电器初始化异常: ", err)
return
}
defer device.Close()
@@ -188,8 +188,8 @@ func relayAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
case <-c.Done():
case <-timerAction(item.Start):
{
logger.Infoln("待机继电器供电")
defer logger.Infoln("待机继电器断电")
zap.S().Infoln("待机继电器供电")
defer zap.S().Infoln("待机继电器断电")
device.On(1)
<-c.Done()
@@ -200,7 +200,7 @@ func relayAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
func videoAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeModel) {
if item.Start != 0 && time.Unix(item.Start, 0).Before(time.Unix(root.Start, 0)) {
logger.Infoln("开始时间小于根任务开始时间")
zap.S().Infoln("开始时间小于根任务开始时间")
return
}
@@ -211,7 +211,7 @@ func videoAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
local, err := utils.LinkVideo(item.Data)
if err != nil {
logger.Errorln("视频文件获取异常: ", err)
zap.S().Errorln("视频文件获取异常: ", err)
return
}
@@ -219,8 +219,8 @@ func videoAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
case <-c.Done():
case <-timerAction(item.Start):
{
logger.Infoln("循环播放待机视频")
defer logger.Infoln("结束待机视频")
zap.S().Infoln("循环播放待机视频")
defer zap.S().Infoln("结束待机视频")
utils.BlankOpen()
defer utils.BlankClose()
@@ -228,7 +228,7 @@ func videoAction(c *leaf.Context, item schema.WaitItemModel, root schema.TimeMod
for {
err := video.Play(c, local)
if err != nil {
logger.Infof("视频播放异常: %s", err)
zap.S().Infof("视频播放异常: %s", err)
return
}
select {

View File

@@ -9,7 +9,7 @@ import (
"game-driver/internal/routes"
"game-driver/internal/schema"
"game-driver/leaf"
"game-driver/pkg/logger"
"game-driver/logger"
"game-driver/pkg/tts"
"game-driver/pkg/utils"
"github.com/eclipse/paho.golang/autopaho"
@@ -25,12 +25,12 @@ import (
func buildMqtt(c config.MqttConfig, r *leaf.Engine, subTopics ...string) autopaho.ClientConfig {
u, err := url.Parse(c.Url)
if err != nil {
logger.Panicln("mqtt url parse error: ", err)
zap.S().Panicln("mqtt url parse error: ", err)
}
subscriptions := make([]paho.SubscribeOptions, 0)
for _, topic := range subTopics {
logger.Infoln("订阅主题: ", topic)
zap.S().Infoln("订阅主题: ", topic)
subscriptions = append(subscriptions, paho.SubscribeOptions{Topic: topic, QoS: 0})
}
@@ -40,17 +40,17 @@ func buildMqtt(c config.MqttConfig, r *leaf.Engine, subTopics ...string) autopah
CleanStartOnInitialConnection: false,
SessionExpiryInterval: 60,
OnConnectionUp: func(cm *autopaho.ConnectionManager, _ *paho.Connack) {
logger.Infoln("MQTT 连接成功")
zap.S().Infoln("MQTT 连接成功")
if _, err := cm.Subscribe(context.Background(), &paho.Subscribe{
Subscriptions: subscriptions,
}); err != nil {
logger.Errorf("failed to subscribe (%s). This is likely to mean no messages will be received.", err)
zap.S().Errorf("failed to subscribe (%s). This is likely to mean no messages will be received.", err)
return
}
logger.Infoln("订阅完成")
zap.S().Infoln("订阅完成")
},
OnConnectError: func(err error) {
logger.Infof("MQTT 连接异常: %s\n", err)
zap.S().Infof("MQTT 连接异常: %s\n", err)
},
ClientConfig: paho.ClientConfig{
ClientID: "TestSubscriber",
@@ -60,12 +60,12 @@ func buildMqtt(c config.MqttConfig, r *leaf.Engine, subTopics ...string) autopah
return true, nil
},
},
OnClientError: func(err error) { logger.Errorf("client error: %s\n", err) },
OnClientError: func(err error) { zap.S().Errorf("client error: %s\n", err) },
OnServerDisconnect: func(d *paho.Disconnect) {
if d.Properties != nil {
logger.Warnf("server requested disconnect: %s\n", d.Properties.ReasonString)
zap.S().Warnf("server requested disconnect: %s\n", d.Properties.ReasonString)
} else {
logger.Warnf("server requested disconnect; reason code: %d\n", d.ReasonCode)
zap.S().Warnf("server requested disconnect; reason code: %d\n", d.ReasonCode)
}
},
},
@@ -75,6 +75,10 @@ func buildMqtt(c config.MqttConfig, r *leaf.Engine, subTopics ...string) autopah
}
func Run() {
logger.InitLogger()
// 应用退出时刷新所有缓冲日志
defer logger.Sync()
topicPrefix := fmt.Sprintf("server/%s/%v/", config.C.Location, config.C.Point)
publishTopic := fmt.Sprintf("device/%s/%v/status", config.C.Location, config.C.Point)
@@ -82,14 +86,12 @@ func Run() {
defer cancel()
router := leaf.Default(ctx)
// 应用推出时刷新所有缓冲日志
defer logger.DefaultLogger.Sync()
log, _ := zap.NewStdLogAt(logger.DefaultLogger.ZapLogger(), zap.DebugLevel)
log, _ := zap.NewStdLogAt(zap.L(), zap.DebugLevel)
router.SetDebugLogger(log)
router.DefaultHandler(func(c *leaf.Context) {
logger.Infof("未处理消息topic: %s\n payload: %s\n", c.Topic, c.Payload)
zap.S().Infof("未处理消息topic: %s\n payload: %s\n", c.Topic, c.Payload)
})
// 构建 MQTT 连接
@@ -98,7 +100,7 @@ func Run() {
// 连接 MQTT
cm, err := autopaho.NewConnection(ctx, mqttBuild)
if err != nil {
logger.Panicln("连接 MQTT 异常: ", err)
zap.S().Panicln("连接 MQTT 异常: ", err)
}
// 构建语音合成对象
@@ -106,10 +108,10 @@ func Run() {
// 构建继电器对象
//r, err := relay.New(config.C.Relay, func(msg string) {
// logger.Infoln("串口返回: ", msg)
// zap.S().Infoln("串口返回: ", msg)
//})
//if err != nil {
// logger.Panicln("串口连接异常: ", err)
// zap.S().Panicln("串口连接异常: ", err)
//}
//defer r.Close()
@@ -154,13 +156,13 @@ func Run() {
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
logger.Infoln("接收到关闭命令 - 正在关闭程序")
zap.S().Infoln("接收到关闭命令 - 正在关闭程序")
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if e := cm.Disconnect(ctx); e != nil {
logger.Errorln("断开连接异常", e)
zap.S().Errorln("断开连接异常", e)
}
logger.Infoln("关闭完成")
zap.S().Infoln("关闭完成")
}

View File

@@ -5,7 +5,7 @@
package leaf
import (
"game-driver/pkg/logger"
"go.uber.org/zap"
"io"
)
@@ -35,7 +35,7 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc {
return func(c *Context) {
defer func() {
if err := recover(); err != nil {
logger.Infoln("执行出错: ", err)
zap.S().Errorln("执行出错: ", err)
handle(c, err)
}
}()

38
logger/logger.go Normal file
View File

@@ -0,0 +1,38 @@
package logger
import (
"game-driver/config"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"log"
"os"
)
func InitLogger() {
// 解析日志级别
level, err := zapcore.ParseLevel(config.C.Log.Level)
if err != nil {
log.Panicln("日志级别配置错误: ", err)
}
// 默认开发模式
nc := zap.NewDevelopmentEncoderConfig()
// console 格式输出
cn := zapcore.NewConsoleEncoder(nc)
// 多个输出
mws := zapcore.NewMultiWriteSyncer(zapcore.AddSync(config.C.Log.File), zapcore.AddSync(os.Stdout))
// 核心配置
core := zapcore.NewCore(cn, mws, level)
// 构建 logger
logger := zap.New(core, zap.AddCaller())
// 替换全局 logger
zap.ReplaceGlobals(logger)
}
func Sync() {
zap.L().Sync()
}

View File

@@ -1,6 +1,5 @@
/*
Copyright © 2024 慕枫Go <mapleafgo@163.com>
*/
package main

View File

@@ -1,10 +1,10 @@
package audio
import (
"game-driver/pkg/logger"
"github.com/gopxl/beep/v2"
"github.com/gopxl/beep/v2/mp3"
"github.com/gopxl/beep/v2/speaker"
"go.uber.org/zap"
"io"
)
@@ -16,7 +16,7 @@ func PlayBgmMP3(r io.ReadCloser, opts ...beep.LoopOption) (*beep.Ctrl, func() er
loop2, err := beep.Loop2(streamer, opts...)
if err != nil {
logger.Infoln("循环播放异常: ", err)
zap.S().Infoln("循环播放异常: ", err)
return nil, streamer.Close, err
}

View File

@@ -2,11 +2,11 @@ package audio
import (
"context"
"game-driver/pkg/logger"
"github.com/gopxl/beep/v2"
"github.com/gopxl/beep/v2/mp3"
"github.com/gopxl/beep/v2/speaker"
"github.com/gopxl/beep/v2/wav"
"go.uber.org/zap"
"io"
"time"
)
@@ -18,7 +18,7 @@ func init() {
if err != nil {
panic("扬声器初始化异常: " + err.Error())
}
logger.Infoln("扬声器初始化完成")
zap.S().Infoln("扬声器初始化完成")
}
func PlayWav(c context.Context, r io.Reader) {

View File

@@ -1,207 +0,0 @@
package logger
import (
"go.uber.org/zap"
)
type Logger struct {
zl *zap.Logger
zs zap.SugaredLogger
}
func NewLogger() *Logger {
logger, _ := zap.NewDevelopment()
sugar := logger.WithOptions(zap.AddCallerSkip(1)).Sugar()
return &Logger{
zl: logger,
zs: *sugar,
}
}
// ZapLogger 返回 zap 原始的 zap.Logger
func (l *Logger) ZapLogger() *zap.Logger {
return l.zl
}
// Sync 刷新所有缓冲的日志条目
func (l *Logger) Sync() error {
return l.zs.Sync()
}
var DefaultLogger = NewLogger()
// Debug logs the provided arguments at [DebugLevel].
// Spaces are added between arguments when neither is a string.
func Debug(args ...interface{}) {
DefaultLogger.zs.Log(zap.DebugLevel, args...)
}
// Info logs the provided arguments at [InfoLevel].
// Spaces are added between arguments when neither is a string.
func Info(args ...interface{}) {
DefaultLogger.zs.Log(zap.InfoLevel, args...)
}
// Warn logs the provided arguments at [WarnLevel].
// Spaces are added between arguments when neither is a string.
func Warn(args ...interface{}) {
DefaultLogger.zs.Log(zap.WarnLevel, args...)
}
// Error logs the provided arguments at [ErrorLevel].
// Spaces are added between arguments when neither is a string.
func Error(args ...interface{}) {
DefaultLogger.zs.Log(zap.ErrorLevel, args...)
}
// DPanic logs the provided arguments at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
// Spaces are added between arguments when neither is a string.
func DPanic(args ...interface{}) {
DefaultLogger.zs.Log(zap.DPanicLevel, args...)
}
// Panic constructs a message with the provided arguments and panics.
// Spaces are added between arguments when neither is a string.
func Panic(args ...interface{}) {
DefaultLogger.zs.Log(zap.PanicLevel, args...)
}
// Fatal constructs a message with the provided arguments and calls os.Exit.
// Spaces are added between arguments when neither is a string.
func Fatal(args ...interface{}) {
DefaultLogger.zs.Log(zap.FatalLevel, args...)
}
// Debugf formats the message according to the format specifier
// and logs it at [DebugLevel].
func Debugf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.DebugLevel, template, args...)
}
// Infof formats the message according to the format specifier
// and logs it at [InfoLevel].
func Infof(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.InfoLevel, template, args...)
}
// Warnf formats the message according to the format specifier
// and logs it at [WarnLevel].
func Warnf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.WarnLevel, template, args...)
}
// Errorf formats the message according to the format specifier
// and logs it at [ErrorLevel].
func Errorf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.ErrorLevel, template, args...)
}
// DPanicf formats the message according to the format specifier
// and logs it at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
func DPanicf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.DPanicLevel, template, args...)
}
// Panicf formats the message according to the format specifier
// and panics.
func Panicf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.PanicLevel, template, args...)
}
// Fatalf formats the message according to the format specifier
// and calls os.Exit.
func Fatalf(template string, args ...interface{}) {
DefaultLogger.zs.Logf(zap.FatalLevel, template, args...)
}
// Debugw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
//
// When debug-level logging is disabled, this is much faster than
//
// s.With(keysAndValues).Debug(msg)
func Debugw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.DebugLevel, msg, keysAndValues...)
}
// Infow logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func Infow(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.InfoLevel, msg, keysAndValues...)
}
// Warnw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func Warnw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.WarnLevel, msg, keysAndValues...)
}
// Errorw logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func Errorw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.ErrorLevel, msg, keysAndValues...)
}
// DPanicw logs a message with some additional context. In development, the
// logger then panics. (See DPanicLevel for details.) The variadic key-value
// pairs are treated as they are in With.
func DPanicw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.DPanicLevel, msg, keysAndValues...)
}
// Panicw logs a message with some additional context, then panics. The
// variadic key-value pairs are treated as they are in With.
func Panicw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.PanicLevel, msg, keysAndValues...)
}
// Fatalw logs a message with some additional context, then calls os.Exit. The
// variadic key-value pairs are treated as they are in With.
func Fatalw(msg string, keysAndValues ...interface{}) {
DefaultLogger.zs.Logw(zap.FatalLevel, msg, keysAndValues...)
}
// Debugln logs a message at [DebugLevel].
// Spaces are always added between arguments.
func Debugln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.DebugLevel, args...)
}
// Infoln logs a message at [InfoLevel].
// Spaces are always added between arguments.
func Infoln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.InfoLevel, args...)
}
// Warnln logs a message at [WarnLevel].
// Spaces are always added between arguments.
func Warnln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.WarnLevel, args...)
}
// Errorln logs a message at [ErrorLevel].
// Spaces are always added between arguments.
func Errorln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.ErrorLevel, args...)
}
// DPanicln logs a message at [DPanicLevel].
// In development, the logger then panics. (See [DPanicLevel] for details.)
// Spaces are always added between arguments.
func DPanicln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.DPanicLevel, args...)
}
// Panicln logs a message at [PanicLevel] and panics.
// Spaces are always added between arguments.
func Panicln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.PanicLevel, args...)
}
// Fatalln logs a message at [FatalLevel] and calls os.Exit.
// Spaces are always added between arguments.
func Fatalln(args ...interface{}) {
DefaultLogger.zs.Logln(zap.FatalLevel, args...)
}

View File

@@ -8,7 +8,7 @@ import (
"game-driver/leaf"
"game-driver/pkg/audio"
"game-driver/pkg/errorsx"
"game-driver/pkg/logger"
"go.uber.org/zap"
"io"
"log"
"time"
@@ -49,7 +49,7 @@ func (tts *AliTTS) Sound(text string) {
if err == nil && buf != nil {
audio.PlayWav(tts.ctx, buf)
} else {
logger.Errorln("AliTTS 请求异常: ", err)
zap.S().Errorln("AliTTS 请求异常: ", err)
}
}

View File

@@ -3,7 +3,7 @@ package utils
import (
"bytes"
"fmt"
"game-driver/pkg/logger"
"go.uber.org/zap"
"io"
"net/http"
"net/url"
@@ -33,7 +33,7 @@ func open(u string) io.ReadCloser {
p, _ := strings.CutPrefix(u, "file://")
f, e := os.Open(p)
if e != nil {
logger.Infof("音频文件 [%v] 打开错误: %v\n", u, e)
zap.S().Infof("音频文件 [%v] 打开错误: %v\n", u, e)
return nil
}
return f
@@ -42,7 +42,7 @@ func open(u string) io.ReadCloser {
func get(u string) io.ReadCloser {
resp, e := http.Get(u)
if e != nil {
logger.Infof("音频文件 [%v] 下载失败: %v\n", u, e)
zap.S().Infof("音频文件 [%v] 下载失败: %v\n", u, e)
return nil
}
return resp.Body

View File

@@ -3,7 +3,7 @@ package video
import (
"bufio"
"context"
"game-driver/pkg/logger"
"go.uber.org/zap"
"io"
"os/exec"
"sync"
@@ -11,7 +11,7 @@ import (
func Play(ctx context.Context, file string) error {
if file == "" {
logger.Infoln("video file is empty")
zap.S().Infoln("video file is empty")
return nil
}
cmd := exec.CommandContext(ctx, "ffplay", "-autoexit", "-fs", file)
@@ -40,7 +40,7 @@ func Play(ctx context.Context, file string) error {
}
break
}
logger.Infoln(string(line))
zap.S().Infoln(string(line))
}
}
}()

View File

@@ -10,7 +10,7 @@
```
驱动安装
```bash
libdirectfb-dev
sudo apt install libdirectfb-dev
```
3. 当前用户加入播放音频与视频的组中
```bash