GoFiber 从零系列(一):项目创建&配置文件&gorm-mysql
GoFiber 从零系列(二):热加载/热更新 && 日志系统 && 验证入参
热加载/热更新
安装插件
go install github.com/pilu/fresh@latest
在项目终端 输入fresh
fresh
日志系统
添加pkg/logging/file.go, pkg/logging/log.go
- file.go
package logging
import (
"os"
"time"
"fmt"
"log"
)
var (
LogSavePath = "runtime/logs/"
LogSaveName = "log"
LogFileExt = "log"
TimeFormat = "20060102"
)
func getLogFilePath() string {
return fmt.Sprintf("%s", LogSavePath)
}
func getLogFileFullPath() string {
prefixPath := getLogFilePath()
suffixPath := fmt.Sprintf("%s%s.%s", LogSaveName, time.Now().Format(TimeFormat), LogFileExt)
return fmt.Sprintf("%s%s", prefixPath, suffixPath)
}
func openLogFile(filePath string) *os.File {
_, err := os.Stat(filePath)
switch {
case os.IsNotExist(err):
mkDir()
case os.IsPermission(err):
log.Fatalf("Permission :%v", err)
}
handle, err := os.OpenFile(filePath, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Fail to OpenFile :%v", err)
}
return handle
}
func mkDir() {
dir, _ := os.Getwd()
err := os.MkdirAll(dir + "/" + getLogFilePath(), os.ModePerm)
if err != nil {
panic(err)
}
}
- log.go
package logging
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
type Level int
var (
F *os.File
DefaultPrefix = ""
DefaultCallerDepth = 2
logger *log.Logger
logPrefix = ""
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
const (
DEBUG Level = iota
INFO
WARNING
ERROR
FATAL
)
func init() {
filePath := getLogFileFullPath()
F = openLogFile(filePath)
logger = log.New(F, DefaultPrefix, log.LstdFlags)
}
func Debug(v ...interface{}) {
setPrefix(DEBUG)
logger.Println(v)
}
func Info(v ...interface{}) {
setPrefix(INFO)
logger.Println(v)
}
func Warn(v ...interface{}) {
setPrefix(WARNING)
logger.Println(v)
}
func Error(v ...interface{}) {
setPrefix(ERROR)
logger.Println(v)
}
func Fatal(v ...interface{}) {
setPrefix(FATAL)
logger.Fatalln(v)
}
func setPrefix(level Level) {
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
if ok {
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Clean(file), line)
} else {
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
}
logger.SetPrefix(logPrefix)
}
修改routers/router.go
添加日志中间件,且输出到文件系统
package routers
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/requestid"
controller "github.com/jinpikaFE/go_fiber/controllers"
"github.com/jinpikaFE/go_fiber/pkg/logging"
"github.com/jinpikaFE/go_fiber/pkg/setting"
)
func InitRouter() *fiber.App {
app := fiber.New(fiber.Config{
ReadTimeout: setting.ReadTimeout,
WriteTimeout: setting.WriteTimeout,
})
app.Use(requestid.New())
app.Use(logger.New(logger.Config{
Format: "[INFO-${locals:requestid}]${time} pid: ${pid} status:${status} - ${method} path: ${path} queryParams: ${queryParams} body: ${body}\n resBody: ${resBody}\n error: ${error}\n",
Output: logging.F,
}))
apiv1 := app.Group("/v1")
{
apiv1.Get("/test", controller.GetTests)
apiv1.Post("/test", controller.AddTest)
apiv1.Put("/test/:id", controller.EditTest)
apiv1.Delete("/test/:id", controller.DelTest)
}
return app
}
在抛出错误的地方进行日志抛出
示例:
if err := c.BodyParser(test); err != nil {
code = 500
message = "ERROR"
logging.Error(err)
}
验证入参
go get github.com/go-playground/validator/v10
新建pkg/valodates/valdates.go
package valodates
import "github.com/go-playground/validator/v10"
var validate = validator.New()
type ErrorResponse struct {
FailedField string
Tag string
Value string
}
func ValidateStruct(valod interface{}) []*ErrorResponse {
var errors []*ErrorResponse
err := validate.Struct(valod)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
var element ErrorResponse
element.FailedField = err.StructNamespace()
element.Tag = err.Tag()
element.Value = err.Param()
errors = append(errors, &element)
}
}
return errors
}
- 使用
// 入参验证
errors := valodates.ValidateStruct(*test)
if errors != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": code,
"message": message,
"data": errors,
})
}