国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Go學(xué)習第十八章——Gin日志與第三方工具Logrus

這篇具有很好參考價值的文章主要介紹了Go學(xué)習第十八章——Gin日志與第三方工具Logrus。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Gin日志功能

1 基礎(chǔ)介紹

1.1 快速入門

在使用Gin框架的過程中,日志是一個重要的組成部分,它可以記錄框架和應(yīng)用程序的運行情況,幫助開發(fā)者排查問題和監(jiān)控應(yīng)用程序的性能。Gin框架提供了方便的方法來設(shè)置和使用日志。

  1. 默認日志 Gin框架默認使用的是標準庫的log包,將日志輸出到控制臺??梢酝ㄟ^gin.Default()方法來創(chuàng)建一個帶有默認中間件的路由引擎。
// 使用Gin.Default自帶一個日志中間件
router := gin.Default()

// Logger()就是
func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

以上代碼創(chuàng)建的路由引擎將會使用默認的日志中間件,該中間件會將請求的信息以及處理時間記錄到控制臺。

  1. 自定義日志輸出 如果想要自定義日志的輸出方式,可以通過gin.New()方法來創(chuàng)建一個不帶默認中間件的路由引擎,并使用gin.Logger()方法設(shè)置自定義的日志中間件。
router := gin.New()
router.Use(gin.Logger())

以上代碼創(chuàng)建了一個不帶默認中間件的路由引擎,并設(shè)置了自定義的日志中間件。

不過上面這里,直接又調(diào)用了gin自帶的日志中間件,后面會講解如何自定義日志。

1.2 日志基礎(chǔ)使用

  1. 使用日志 在實際項目中,可以在處理請求的函數(shù)中使用日志記錄相關(guān)信息。
func handler(c *gin.Context) {
	log.Println("Handling request...")
	c.JSON(http.StatusOK, gin.H{"message": "Hello, world!"})
}

以上代碼在處理請求的函數(shù)中使用了log包的Println函數(shù)記錄了一條信息。

  1. 日志格式化 Gin框架中提供了方便的方法來格式化日志的輸出??梢允褂胠og包的Printf函數(shù)來格式化日志信息。
func handler(c *gin.Context) {
	log.Printf("Handling request: %s", c.Request.URL.Path)
	c.JSON(http.StatusOK, gin.H{"message": "Hello, world!"})
}

以上代碼使用Printf函數(shù)格式化了日志輸出,打印了請求的URL路徑。

1.3 將日志輸出到文件

日志文件 除了輸出到控制臺,還可以將日志輸出到文件中。

  1. gin.DefaultWriter = io.MultiWriter(f) 將日志寫入文件,但是控制臺不顯示
  2. gin.DefaultWriter = io.MultiWriter(f, os.Stdout)同時將日志寫入文件和控制臺
func main() {
  // 輸出到文件
  f, _ := os.Create("gin.log")
  //gin.DefaultWriter = io.MultiWriter(f)
  // 如果需要同時將日志寫入文件和控制臺,請使用以下代碼。
  gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
  router := gin.Default()
  router.GET("/", func(c *gin.Context) {
    c.JSON(200, gin.H{"msg": "/"})
  })
  router.Run()
}

以上代碼將日志輸出到名為"logfile.log"的文件中。

還有一種方式,可以做一個中間件,用來將日志寫入文件,并且控制臺也顯示:

使用log包的SetOutput函數(shù)將日志輸出到指定的文件。

func main() {
    router := gin.Default()
    router.GET("/", handler)
    router.Run(":8000")
}

func handler(c *gin.Context) {
    file, _ := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    log.SetOutput(file)
    log.Printf("Handling request: %s", c.Request.URL.Path)
    c.JSON(http.StatusOK, gin.H{"message": "Hello, world!"})
}

2 定義路由格式

啟動gin,它會顯示所有的路由,默認格式如下

[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] GET    /hello                    --> main.main.func2 (3 handlers)

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

我們也可以進行修改,自定義這個輸出格式:

gin.DebugPrintRouteFunc是Gin框架提供的一個全局變量,用于自定義路由信息的調(diào)試輸出格式和行為。該變量是一個函數(shù)類型,聲明如下:

type DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int)

該函數(shù)類型接收以下參數(shù):

  • httpMethod:HTTP方法,表示請求使用了哪種HTTP方法(GET、POST、PUT、DELETE等)。
  • absolutePath:請求路徑,包括了路由組前綴和被路由匹配的路徑。
  • handlerName:處理函數(shù)的名稱,用于標識該路由綁定的處理函數(shù)。
  • nuHandlers:處理函數(shù)的數(shù)量,即路由綁定的處理函數(shù)個數(shù)。

用戶可以通過定義一個自定義的DebugPrintRouteFunc函數(shù),并將其賦值給gin.DebugPrintRouteFunc變量來定制網(wǎng)站路由信息的輸出。

func main() {
	gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
		fmt.Printf("[小智] %v - url:%v --> handlerName:%v (%v handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
	}

	router := gin.Default()

	router.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{"msg": "/"})
	})

	router.GET("/hello", func(c *gin.Context) {
		c.JSON(200, gin.H{"msg": "/"})
	})

	router.Run()
}

輸出結(jié)果:

[小智] GET - url:/ --> handlerName:main.main.func2 (3 handlers)
[小智] GET - url:/hello --> handlerName:main.main.func3 (3 handlers)

3 修改日志級別

Gin框架提供了四種日志級別:

  • gin.DebugMode:啟用DEBUG級別日志,顯示所有日志信息。
  • gin.ReleaseMode:啟用INFO級別日志,僅顯示INFO、WARN和ERROR級別的日志信息。
  • gin.TestMode:禁用日志,不顯示任何日志信息。

可以通過gin.DebugModegin.ReleaseModegin.TestMode方法設(shè)置不同的日志級別。

// 設(shè)置為DEBUG級別日志
gin.SetMode(gin.DebugMode)

// 設(shè)置為INFO級別日志
gin.SetMode(gin.ReleaseMode)

// 禁用日志
gin.SetMode(gin.TestMode)

我這里選擇了一個設(shè)置,再次運行,下面的內(nèi)容就少了很多,特別是設(shè)置INFO之后,完美~~

4 修改日志格式

默認的是這樣的

[GIN] 2023/10/28 - 23:21:00 | 200 |  0s |  127.0.0.1 | GET  "/"

如果覺得不好看,我們可以自定義

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
)

func LoggerWithFormatter(params gin.LogFormatterParams) string {
  return fmt.Sprintf(
    "[ 小智 ] %s  | %d | \t %s | %s | %s \t  %s\n",
    params.TimeStamp.Format("2006/01/02 - 15:04:05"),
    params.StatusCode,  // 狀態(tài)碼
    params.ClientIP,  // 客戶端ip
    params.Latency,  // 請求耗時
    params.Method,  // 請求方法
    params.Path,  // 路徑
  )
}

func main() {
  router := gin.New()
  router.Use(gin.LoggerWithFormatter(LoggerWithFormatter))
  router.Run()

}

也可以這樣

func LoggerWithFormatter(params gin.LogFormatterParams) string {
  return fmt.Sprintf(
    "[ 小智 ] %s  | %d | \t %s | %s | %s \t  %s\n",
    params.TimeStamp.Format("2006/01/02 - 15:04:05"),
    params.StatusCode,
    params.ClientIP,
    params.Latency,
    params.Method,
    params.Path,
  )
}

func main() {
  router := gin.New()
  router.Use(
    gin.LoggerWithConfig(
      gin.LoggerConfig{Formatter: LoggerWithFormatter},
    ),
  )
  router.Run()

}

但是你會發(fā)現(xiàn)自己這樣輸出之后,沒有顏色了,不太好看,我們可以輸出有顏色的log

func LoggerWithFormatter(params gin.LogFormatterParams) string {
  var statusColor, methodColor, resetColor string
  statusColor = params.StatusCodeColor()
  methodColor = params.MethodColor()
  resetColor = params.ResetColor()
  return fmt.Sprintf(
    "[ 小智 ] %s  | %s %d  %s | \t %s | %s | %s %-7s %s \t  %s\n",
    params.TimeStamp.Format("2006/01/02 - 15:04:05"),
    statusColor, params.StatusCode, resetColor,
    params.ClientIP,
    params.Latency,
    methodColor, params.Method, resetColor,
    params.Path,
  )
}

我們進行運行,然后看一下結(jié)果~~

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

第三方日志工具logrus

1 快速入門

1.1 安裝

可以使用Go的包管理工具go get來安裝Logrus:

go get github.com/sirupsen/logrus

安裝完成后,可以在項目的代碼中引入Logrus的包:

import log "github.com/sirupsen/logrus"

1.2 使用

下面是一個簡單的入門案例,展示了如何使用Logrus進行基本的日志輸出:

package main

import (
	log "github.com/sirupsen/logrus"
	"os"
)

func main() {
	// 設(shè)置日志輸出格式為JSON格式
	log.SetFormatter(&log.JSONFormatter{})

	// 設(shè)置日志輸出到標準輸出
	log.SetOutput(os.Stdout)
    
    // 得到當前的日志級別
    fmt.Println("修改前",log.GetLevel()) 

	// 設(shè)置日志級別為debug
	log.SetLevel(log.DebugLevel)
    
    // 得到當前的日志級別
    fmt.Println("修后",log.GetLevel())

	// 輸出不同級別的日志信息
	log.Debug("This is a debug message")
	log.Info("This is an info message")
	log.Warn("This is a warning message")
	log.Error("This is an error message")
}

輸出結(jié)果:

{"level":"debug","msg":"This is a debug message","time":"2023-10-29T09:51:48+08:00"}
{"level":"info","msg":"This is an info message","time":"2023-10-29T09:51:48+08:00"}
{"level":"warning","msg":"This is a warning message","time":"2023-10-29T09:51:48+08:00"}
{"level":"error","msg":"This is an error message","time":"2023-10-29T09:51:48+08:00"}

在這個例子中,我們首先設(shè)置了日志輸出的格式為JSON格式,然后將日志輸出到標準輸出。接著,我們設(shè)置了日志級別為debug,這意味著只有debug級別及以上的日志信息才會被輸出。

最后,我們分別輸出了debug、info、warning和error級別的日志信息??梢栽诳刂婆_中看到對應(yīng)級別的日志信息以及它們的格式。

2 基本功能使用

2.1 設(shè)置日志輸出格式

日志級別一般是和系統(tǒng)環(huán)境掛鉤,例如開發(fā)環(huán)境,肯定就要顯示debug信息,測試環(huán)境也是需要的

線上環(huán)境就不需要這些日志,可能只顯示warnning的日志

Logrus支持多種日志輸出格式,如JSON、文本(默認)、自定義格式等。可以使用logrus提供的SetFormatter方法來設(shè)置日志輸出格式。以下是一些常用的日志輸出格式:

  • JSON格式:
log.SetFormatter(&log.JSONFormatter{})
  • 文本格式(默認格式):
log.SetFormatter(&log.TextFormatter{})
  • 自定義格式:

自定義能夠選擇的類型:

ForceColors:是否強制使用顏色輸出。
DisableColors:是否禁用顏色輸出。
ForceQuote:是否強制引用所有值。
DisableQuote:是否禁用引用所有值。
DisableTimestamp:是否禁用時間戳記錄。
FullTimestamp:是否在連接到 TTY 時輸出完整的時間戳。
TimestampFormat:用于輸出完整時間戳的時間戳格式。

使用方式:

log.SetFormatter(&log.TextFormatter{
	DisableColors: true, 
	FullTimestamp: true,
})

完整代碼:

func main() {
    // JSON格式
    log.SetFormatter(&log.JSONFormatter{})
    log.Errorf("JSON格式")

    // TEXT格式
    log.SetFormatter(&log.TextFormatter{})
    log.Errorf("TEXT格式")

    // 自定義格式
    log.SetFormatter(&log.TextFormatter{
       DisableColors: false,
       FullTimestamp: true,
       ForceColors:   true,
    })
    log.Errorf("自定義格式")

    log.Error("你好")
    log.Info("你好")
    log.Warnln("你好")
    log.Debug("你好")
    log.Println("你好")
}

輸出結(jié)果:

{"level":"error","msg":"JSON格式","time":"2023-10-29T10:23:25+08:00"}             
time="2023-10-29T10:23:25+08:00" level=error msg="TEXT格式"                       
ERRO[2023-10-29T10:23:25+08:00] 自定義格式                                        
ERRO[2023-10-29T10:23:25+08:00] 你好                                              
INFO[2023-10-29T10:23:25+08:00] 你好                                              
WARN[2023-10-29T10:23:25+08:00] 你好                                              
INFO[2023-10-29T10:23:25+08:00] 你好

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

2.2 設(shè)置日志輸出位置

Logrus可以將日志輸出到標準輸出、文件、網(wǎng)絡(luò)等多個位置。默認情況下,日志輸出到標準輸出。

以下是一些常用的日志輸出位置:

  • 標準輸出:
log.SetOutput(os.Stdout)
  • 文件:
  1. 輸出在文件,并且控制臺不輸出
func main() {
	log.SetFormatter(&log.JSONFormatter{})

	file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
	if err == nil {
		log.SetOutput(file)
	} else {
		log.Info("Failed to log to file, using default stderr")
	}

	log.Error("你好")
}
  1. 輸出在文件,并且控制臺也輸出
func main() {
    // 創(chuàng)建一個文件,用于寫入日志
    file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
    if err == nil {
       // 設(shè)置日志輸出到文件和標準輸出
       mw := io.MultiWriter(file, os.Stdout)

       // 設(shè)置日志輸出格式為文本格式
       log.SetFormatter(&log.TextFormatter{})
       // 設(shè)置日志輸出位置為MultiWriter
       log.SetOutput(mw)
       // 設(shè)置日志級別為debug
       log.SetLevel(log.DebugLevel)

       // 輸出日志信息
       log.Debug("This is a debug message")
       log.Info("This is an info message")
       log.Warn("This is a warning message")
       log.Error("This is an error message")

       // 關(guān)閉日志文件
       file.Close()
    } else {
       fmt.Println("Failed to log to file, using default stderr")
    }
}

在這個例子中,我們首先創(chuàng)建了一個文件,用于寫入日志信息。然后,我們創(chuàng)建了一個MultiWriter,并將文件和標準輸出作為參數(shù)傳入MultiWriter的構(gòu)造函數(shù)中。

接著,我們設(shè)置了日志的輸出格式為TextFormatter,并將輸出位置設(shè)置為MultiWriter。最后,我們設(shè)置了日志的級別為debug,并輸出不同級別的日志信息。

通過使用MultiWriter,日志信息將同時輸出到文件和控制臺,控制臺會顯示日志信息,而文件中也會寫入相同的日志內(nèi)容。

  • 網(wǎng)絡(luò):
conn, err := net.Dial("tcp", "localhost:12345")
if err == nil {
    log.SetOutput(conn)
} else {
    log.Info("Failed to connect to log server, using default stderr")
}

2.3 設(shè)置日志級別

Logrus支持多個日志級別,包括debug、info、warning、error、fatal和panic。可以使用SetLevel方法來設(shè)置日志級別:

log.SetLevel(log.DebugLevel)

可以根據(jù)項目需要設(shè)置不同的日志級別。當設(shè)置為不同的日志級別時,只有大于等于該級別的日志信息才會被輸出。

2.4 添加字段到日志信息中

Logrus提供了多種方法來添加自定義字段到日志信息中。可以使用WithFieldWithFields方法來添加字段。

func main() {
	// 給日志添加一個字段
	log1 := log.WithField("user1", "alice")
	log1.Errorf("你好")

	log2 := log.WithFields(log.Fields{
		"user2": "alice",
		"ip":    "127.0.0.1",
	})
	log2.Errorf("你好")

	// 嵌套使用
	log3 := log.WithFields(log.Fields{
		"user3": "alice",
		"ip":    "127.0.0.1",
	}).WithField("user4", "alice")
	log3.Errorf("你好")
}

輸出結(jié)果:

time="2023-10-29T10:16:22+08:00" level=error msg="你好" user1=alice                         
time="2023-10-29T10:16:22+08:00" level=error msg="你好" ip=127.0.0.1 user2=alice            
time="2023-10-29T10:16:22+08:00" level=error msg="你好" ip=127.0.0.1 user3=alice user4=alice

2.5 錯誤處理

Logrus可以記錄和處理錯誤信息??梢允褂?code>WithError方法來添加錯誤信息到日志中。

err := someFunc()
if err != nil {
    log.WithError(err).Error("Error occurred")
}

2.6 格式化參數(shù)

Logrus支持使用格式化字符串和參數(shù)。

log.Infof("The answer is %d", 42)

2.7 顯示行號

沒有行號,無法定位具體的日志位置

logrus.SetReportCaller(true)

輸出結(jié)果:看后面多了一個file,并且最后有個29,就是報錯的那一行

time="2023-10-29T10:35:56+08:00" level=debug msg="This is a debug message" func=main.main file="F:/goproject/studyGin/GinStudy03_Logrus/main.go:26"
time="2023-10-29T10:35:56+08:00" level=info msg="This is an info message" func=main.main file="F:/goproject/studyGin/GinStudy03_Logrus/main.go:27" 
time="2023-10-29T10:35:56+08:00" level=warning msg="This is a warning message" func=main.main file="F:/goproject/studyGin/GinStudy03_Logrus/main.go
:28"
time="2023-10-29T10:35:56+08:00" level=error msg="This is an error message" func=main.main file="F:/goproject/studyGin/GinStudy03_Logrus/main.go:29
"

3 自定義日志格式

logrus默認的樣式我不太喜歡,沒有顏色輸出

需要實現(xiàn)Formatter(entry *logrus.Entry) ([]byte, error) 接口

package main

import (
  "bytes"
  "fmt"
  "github.com/sirupsen/logrus"
  "os"
  "path"
)

// 顏色
const (
  red    = 31
  yellow = 33
  blue   = 36
  gray   = 37
)

type LogFormatter struct{}

// Format 實現(xiàn)Formatter(entry *logrus.Entry) ([]byte, error)接口
func (t *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
  //根據(jù)不同的level去展示顏色
  var levelColor int
  switch entry.Level {
  case logrus.DebugLevel, logrus.TraceLevel:
    levelColor = gray
  case logrus.WarnLevel:
    levelColor = yellow
  case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
    levelColor = red
  default:
    levelColor = blue
  }
  var b *bytes.Buffer
  if entry.Buffer != nil {
    b = entry.Buffer
  } else {
    b = &bytes.Buffer{}
  }
  //自定義日期格式
  timestamp := entry.Time.Format("2006-01-02 15:04:05")
  if entry.HasCaller() {
    //自定義文件路徑
    funcVal := entry.Caller.Function
    fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
    //自定義輸出格式
    fmt.Fprintf(b, "[%s] \x1b[%dm[%s]\x1b[0m %s %s %s\n", timestamp, levelColor, entry.Level, fileVal, funcVal, entry.Message)
  } else {
    fmt.Fprintf(b, "[%s] \x1b[%dm[%s]\x1b[0m %s\n", timestamp, levelColor, entry.Level, entry.Message)
  }
  return b.Bytes(), nil
}

var log *logrus.Logger

func init() {
  log = NewLog()
}

func NewLog() *logrus.Logger {
  mLog := logrus.New()               //新建一個實例
  mLog.SetOutput(os.Stdout)          //設(shè)置輸出類型
  mLog.SetReportCaller(true)         //開啟返回函數(shù)名和行號
  mLog.SetFormatter(&LogFormatter{}) //設(shè)置自己定義的Formatter
  mLog.SetLevel(logrus.DebugLevel)   //設(shè)置最低的Level
  return mLog
}
func main() {
  log.Errorln("你好")
  log.Infof("你好")
  log.Warnln("你好")
  log.Debugf("你好")
}

輸出結(jié)果:

[2023-10-29 10:37:46] [error] main.go:20 main.main 你好  
[2023-10-29 10:37:46] [info] main.go:21 main.main 你好   
[2023-10-29 10:37:46] [warning] main.go:22 main.main 你好
[2023-10-29 10:37:46] [debug] main.go:23 main.main 你好

4 鉤子Hook

4.1 快速入門

logrus最令人心動的功能就是其可擴展的HOOK機制了,通過在初始化時為logrus添加hook,logrus可以實現(xiàn)各種擴展功能。

type Hook interface {
    Levels() []Level
    Fire(*Entry) error
}

logrus支持鉤子函數(shù),使得在特定的條件下自動觸發(fā)操作??梢允褂?code>AddHook方法來添加鉤子函數(shù)。

log.AddHook(&MyHook{})

完整代碼:

// 這個 CustomHook 名字是可以改動的
type CustomHook struct {
}

// 設(shè)置一個field
func (hook *CustomHook) Fire(entry *logrus.Entry) error {
    // 在日志輸出之前執(zhí)行自定義操作,比如發(fā)送到消息隊列、保存到數(shù)據(jù)庫等
    // 這里只是一個示例,實際操作可以根據(jù)需求進行自定義
    entry.Data["custom_field"] = "custom_value"
    return nil
}

// 哪些等級的日志才會生效
func (hook *CustomHook) Levels() []logrus.Level {
    // 指定要被觸發(fā)的日志級別,這里設(shè)置為所有級別
    return logrus.AllLevels
}

func main() {
    // 日志的打開格式是追加,所以不能用os.Create
    logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true, TimestampFormat: "2006-01-02 15:04:05", FullTimestamp: true})
    logrus.AddHook(&CustomHook{})
    logrus.Errorf("hello")
}

輸出結(jié)果:

ERRO[2023-10-29 10:49:33] hello                                         custom_field=custom_value

4.2 場景案例

logrus hook 是一個值得深入學(xué)習的設(shè)計,你可以輕易適用hook來實現(xiàn)多文件寫入。

比如,error級別的日志獨立輸出到error.log文件里,其他都放在一起。

type MyHook struct {
  Writer *os.File
}

func (hook *MyHook) Fire(entry *logrus.Entry) error {
  line, err := entry.String()
  if err != nil {
    fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
    return err
  }
  hook.Writer.Write([]byte(line))
  return nil
}

func (hook *MyHook) Levels() []logrus.Level {
  return []logrus.Level{logrus.ErrorLevel}
}

func main() {
  logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true, TimestampFormat: "2006-01-02 15:04:05", FullTimestamp: true})
  logrus.SetReportCaller(true)
  file, _ := os.OpenFile("err.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  hook := &MyHook{Writer: file}
  logrus.AddHook(hook)
  logrus.Errorf("hello")
}

5 日志分割

5.1 時間分割日志

自定義Write方法

自定義Write方法: logrus允許我們自定義寫日志的方法,可以通過實現(xiàn)io.Writer接口來自定義寫日志的行為。這是在網(wǎng)上找的案例,簡單看看它是咋實現(xiàn)的,后面有這段代碼的實現(xiàn)詳細解析。

import (
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// LogFormatter 日志自定義格式
type LogFormatter struct{}

// Format 格式詳情
func (s *LogFormatter) Format(entry *log.Entry) ([]byte, error) {
	// 獲取當前時間
	timestamp := time.Now().Local().Format("2006-01-02 15:04:05")
	var file string
	var line int
	if entry.Caller != nil {
		// 獲取調(diào)用者的文件名和行號
		file = filepath.Base(entry.Caller.File)
		line = entry.Caller.Line
	}
	// 格式化日志信息
	msg := fmt.Sprintf("[%s] %s [%s:%d] %s\n", strings.ToUpper(entry.Level.String()), timestamp, file, line, entry.Message)
	return []byte(msg), nil
}

// logFileWriter 自定義日志寫入器
type logFileWriter struct {
	file     *os.File
	logPath  string
	fileDate string // 判斷日期切換目錄
	appName  string
}

// Write 將日志內(nèi)容寫入文件
func (p *logFileWriter) Write(data []byte) (n int, err error) {
	if p == nil {
		return 0, errors.New("logFileWriter is nil")
	}
	if p.file == nil {
		return 0, errors.New("file not opened")
	}

	// 判斷是否需要切換日期
	fileDate := time.Now().Format("2006-01-02")
	if p.fileDate != fileDate {
		p.file.Close()
		err = os.MkdirAll(fmt.Sprintf("%s/%s", p.logPath, fileDate), os.ModePerm)
		if err != nil {
			return 0, err
		}
		filename := fmt.Sprintf("%s/%s/%s-%s.log", p.logPath, fileDate, p.appName, fileDate)

		p.file, err = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
		if err != nil {
			return 0, err
		}
	}

	n, e := p.file.Write(data)
	return n, e
}

// 初始化日志配置
func InitLog(logPath string, appName string) {
	fileDate := time.Now().Format("20060102")
	// 創(chuàng)建目錄
	err := os.MkdirAll(fmt.Sprintf("%s/%s", logPath, fileDate), os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}

	filename := fmt.Sprintf("%s/%s/%s-%s.log", logPath, fileDate, appName, fileDate)
	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	if err != nil {
		log.Fatal(err)
	}

	fileWriter := logFileWriter{file, logPath, fileDate, appName}
	log.SetOutput(os.Stdout)
	writers := []io.Writer{
		&fileWriter,
		os.Stdout,
	}
	// 同時寫入文件和終端
	fileAndStdoutWriter := io.MultiWriter(writers...)

	log.SetOutput(fileAndStdoutWriter)
	log.SetReportCaller(true)
	log.SetFormatter(new(LogFormatter))
}

func main() {
	InitLog("./logs", "myApp")

	log.Println("This is a log message.")
	log.Printf("This is another log message. Current time: %s\n", time.Now().Format("15:04:05"))

	log.Fatal("This is a fatal error.")
}

輸出結(jié)果:

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

  1. 首先定義了一個 LogFormatter 結(jié)構(gòu)體,用于自定義日志的格式。

    它實現(xiàn)了 Format 方法,接收一個 log.Entry 參數(shù),該結(jié)構(gòu)體包含了日志的級別、時間戳、調(diào)用者的文件名和行號,以及日志信息。在 Format 方法中,通過 time.Now().Local().Format("2006-01-02 15:04:05") 獲取當前時間,并使用 filepath.Base(entry.Caller.File) 獲取調(diào)用者的文件名,entry.Caller.Line 獲取行號。最后使用 fmt.Sprintf 將這些信息格式化為特定的字符串。

  2. 然后定義了一個 logFileWriter 結(jié)構(gòu)體,實現(xiàn)了 io.Writer 接口的 Write 方法。

    該方法用于將日志寫入文件。在 Write 方法中,首先判斷是否需要切換日期。如果日期發(fā)生變化,需要關(guān)閉之前的日志文件,并創(chuàng)建新的日期目錄和文件。然后將日志寫入文件,并返回寫入的字節(jié)數(shù)和錯誤。

  3. 最后定義了一個 InitLog 函數(shù),用于初始化日志。該函數(shù)接收兩個參數(shù):日志路徑 logPath 和應(yīng)用名稱 appName

    在函數(shù)內(nèi)部,首先根據(jù)當前日期創(chuàng)建日志目錄。然后根據(jù)日志路徑、應(yīng)用名稱和當前日期創(chuàng)建日志文件。接著創(chuàng)建一個 logFileWriter 實例,并將其作為輸出寫入器。同時,還將標準輸出作為另一個寫入器。然后使用 io.MultiWriter 將這兩個寫入器組合起來,實現(xiàn)同時將日志寫入文件和標準輸出。最后,使用 log.SetOutput 將寫入器設(shè)置為日志輸出,并設(shè)置 log.SetReportCaller(true) 啟用調(diào)用者報告功能。最后,將 LogFormatter 設(shè)置為日志的格式化器。

這樣,通過調(diào)用 InitLog 函數(shù)可以初始化日志記錄器,并將日志輸出到文件和標準輸出。日志的格式可以通過修改 LogFormatter 結(jié)構(gòu)體的 Format 方法來自定義。

自定義hook鉤子

自定義 hook: logrus還允許我們自定義hook函數(shù),在日志輸出前或輸出后執(zhí)行額外的操作。

import (
	"fmt"
	"github.com/sirupsen/logrus"
	"os"
	"time"
)

// 定義了一個類型FileDateHook,它包含了需要的字段,如日志文件的文件指針、日志保存路徑、當前的日期和應(yīng)用名稱。
type FileDateHook struct {
	file     *os.File
	logPath  string
	fileDate string //判斷日期切換目錄
	appName  string
}

// 定義了FileDateHook類型的方法Levels。
// 該方法返回了一個包含所有日志級別的切片,表示該鉤子對所有日志級別都生效。
func (hook FileDateHook) Levels() []logrus.Level {
	return logrus.AllLevels
}


/* 定義了FileDateHook類型的方法Fire,它是鉤子觸發(fā)時所執(zhí)行的行為。該方法首先獲取當前時間,并格式化為"2006-01-02_15-04"的字符串。然后通過entry.String()方法獲取日志的字符串表示。接著判斷當前日期與上一次的日期是否相同,如果相同,則向日志文件寫入日志內(nèi)容;如果不同,關(guān)閉上一個日志文件,創(chuàng)建新的目錄并打開一個新的日志文件,并將當前日期和日志內(nèi)容寫入該文件。*/
func (hook FileDateHook) Fire(entry *logrus.Entry) error {
	timer := entry.Time.Format("2006-01-02_15-04")
	line, _ := entry.String()
	if hook.fileDate == timer {
		hook.file.Write([]byte(line))
		return nil
	}
	// 時間不等
	hook.file.Close()
	os.MkdirAll(fmt.Sprintf("%s/%s", hook.logPath, timer), os.ModePerm)
	filename := fmt.Sprintf("%s/%s/%s.log", hook.logPath, timer, hook.appName)

	hook.file, _ = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	hook.fileDate = timer
	hook.file.Write([]byte(line))
	return nil
}

/* 定義了InitFile函數(shù),用于初始化日志文件配置。首先獲取當前日期并創(chuàng)建對應(yīng)的目錄。然后構(gòu)建日志文件的路徑,創(chuàng)		建并打開日志文件,并將文件指針和其他參數(shù)傳遞給FileDateHook,最后通過logrus的AddHook方法將該鉤子添加到日	志記錄器中。*/
func InitFile(logPath, appName string) {
	fileDate := time.Now().Format("2006-01-02_15-04")
	//創(chuàng)建目錄
	err := os.MkdirAll(fmt.Sprintf("%s/%s", logPath, fileDate), os.ModePerm)
	if err != nil {
		logrus.Error(err)
		return
	}

	filename := fmt.Sprintf("%s/%s/%s.log", logPath, fileDate, appName)
	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	if err != nil {
		logrus.Error(err)
		return
	}
	fileHook := FileDateHook{file, logPath, fileDate, appName}
	logrus.AddHook(&fileHook)
}

func main() {
   
	InitFile("logrus_study/log", "XiaoZhi")

	for {
		logrus.Errorf("error")
		time.Sleep(20 * time.Second)
		logrus.Warnln("warnning")
	}
}

在main函數(shù)中,首先調(diào)用InitFile函數(shù)初始化日志文件配置。然后進入一個無限循環(huán),每隔20秒記錄一條帶有"error"級別的日志,并記錄一條帶有"warning"級別的日志。

這段代碼實現(xiàn)了一個簡單的日志記錄功能,根據(jù)日期創(chuàng)建目錄和文件,并將不同日期的日志分別保存到對應(yīng)的文件中。通過FileDateHook和logrus庫的配合使用,可以靈活地對日志進行處理和管理。

5.2 按日志等級分割

package main

import (
  "fmt"
  "github.com/sirupsen/logrus"
  "os"
)
// 定義了4個常量,分別用于表示所有日志、錯誤日志、警告日志和信息日志。
const (
  allLog  = "all"
  errLog  = "err"
  warnLog = "warn"
  infoLog = "info"
)

// 定義了一個類型FileLevelHook,它包含了需要的字段,
// 如所有日志文件、錯誤日志文件、警告日志文件、信息日志文件和保存日志的路徑。
type FileLevelHook struct {
  file     *os.File
  errFile  *os.File
  warnFile *os.File
  infoFile *os.File
  logPath  string
}

// 定義了FileLevelHook類型的方法Levels。
// 該方法返回一個包含所有日志級別的切片,表示該鉤子對所有日志級別都生效。
func (hook FileLevelHook) Levels() []logrus.Level {
  return logrus.AllLevels
}

// 定義了FileLevelHook類型的方法Fire,它是鉤子觸發(fā)時所執(zhí)行的行為。
/* 該方法將entry轉(zhuǎn)換為字符串,然后根據(jù)entry的級別分別向錯誤日志文件、警告日志文件和信息日志文件中寫入日志內(nèi)容。另外,該方法還向所有日志文件中寫入日志內(nèi)容。*/
func (hook FileLevelHook) Fire(entry *logrus.Entry) error {
  line, _ := entry.String()
  switch entry.Level {
  case logrus.ErrorLevel:
    hook.errFile.Write([]byte(line))
  case logrus.WarnLevel:
    hook.warnFile.Write([]byte(line))
  case logrus.InfoLevel:
    hook.infoFile.Write([]byte(line))
  }
  hook.file.Write([]byte(line))
  return nil
}
// 定義了InitLevel函數(shù),用于初始化日志文件配置。
/* 該函數(shù)首先創(chuàng)建保存日志的目錄,然后打開所有日志文件、錯誤日志文件、警告日志文件和信息日志文件,并將它們添加到FileLevelHook中。最后通過logrus的AddHook方法將該鉤子添加到日志記錄器中。*/
func InitLevel(logPath string) {
  err := os.MkdirAll(fmt.Sprintf("%s", logPath), os.ModePerm)
  if err != nil {
    logrus.Error(err)
    return
  }
  allFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, allLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
  errFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, errLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
  warnFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, warnLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
  infoFile, err := os.OpenFile(fmt.Sprintf("%s/%s.log", logPath, infoLog), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
  fileHook := FileLevelHook{allFile, errFile, warnFile, infoFile, logPath}
  logrus.AddHook(&fileHook)
}

func main() {
  InitLevel("logrus_study/log_level")
  logrus.Errorln("你好")
  logrus.Errorln("err")
  logrus.Warnln("warn")
  logrus.Infof("info")
  logrus.Println("print")
}

在main函數(shù)中,首先調(diào)用InitLevel函數(shù)初始化日志文件配置。然后使用logrus記錄了一些不同級別的日志,這些日志將根據(jù)級別分別保存到不同的文件中。

這段代碼實現(xiàn)了一個可以將不同級別的日志分別保存到不同文件的日志記錄器,可以根據(jù)實際需求對不同級別的日志進行細分管理。

Gin 集成 logrus

視頻學(xué)習:Gin 集成 logrus

先創(chuàng)建兩個文件夾,log,middleware,并且兩個文件,log.go,log_middleware.go

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

log_middleware.go文件的代碼:

package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"time"
)

const (
	status200 = 42
	status404 = 43
	status500 = 41

	methodGET = 44
)

func LogMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		raw := c.Request.URL.RawQuery

		// Process request
		c.Next()

		// Log only when path is not being skipped

		// Stop timer
		end := time.Now()
		timeSub := end.Sub(start)
		clientIP := c.ClientIP()
		method := c.Request.Method
		statusCode := c.Writer.Status()
		//bodySize := c.Writer.Size()
		if raw != "" {
			path = path + "?" + raw
		}

		var statusColor string
		switch statusCode {
		case 200:
			statusColor = fmt.Sprintf("\033[%dm %d \033[0m", status200, statusCode)
		case 404:
			statusColor = fmt.Sprintf("\033[%dm %d \033[0m", status404, statusCode)
		}

		var methodColor string
		switch method {
		case "GET":
			methodColor = fmt.Sprintf("\033[%dm %s \033[0m", methodGET, method)

		}

		logrus.Infof("[GIN] %s |%s| %d | %s | %s | %s",
			start.Format("2006-01-02 15:04:06"),
			statusColor,
			timeSub,
			clientIP,
			methodColor,
			path,
		)

	}
}

log.go文件的代碼:

package log

import (
	"bytes"
	"fmt"
	"github.com/sirupsen/logrus"
	"os"
	"time"
)

type FileDateHook struct {
	file     *os.File
	logPath  string
	fileDate string //判斷日期切換目錄
	appName  string
}

func (hook FileDateHook) Levels() []logrus.Level {
	return logrus.AllLevels
}
func (hook FileDateHook) Fire(entry *logrus.Entry) error {
	timer := entry.Time.Format("2006-01-02_15-04")
	line, _ := entry.String()
	if hook.fileDate == timer {
		hook.file.Write([]byte(line))
		return nil
	}
	// 時間不等
	hook.file.Close()
	os.MkdirAll(fmt.Sprintf("%s/%s", hook.logPath, timer), os.ModePerm)
	filename := fmt.Sprintf("%s/%s/%s.log", hook.logPath, timer, hook.appName)

	hook.file, _ = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	hook.fileDate = timer
	hook.file.Write([]byte(line))
	return nil
}

type MyFormatter struct {
}

func (f MyFormatter) Format(entry *logrus.Entry) ([]byte, error) {

	// 設(shè)置buffer 緩沖區(qū)
	var b *bytes.Buffer
	if entry.Buffer == nil {
		b = &bytes.Buffer{}
	} else {
		b = entry.Buffer
	}
	// 設(shè)置格式
	fmt.Fprintf(b, "%s\n", entry.Message)

	return b.Bytes(), nil
}

func InitFile(logPath, appName string) {
	logrus.SetFormatter(&MyFormatter{})

	fileDate := time.Now().Format("2006-01-02_15-04")
	//創(chuàng)建目錄
	err := os.MkdirAll(fmt.Sprintf("%s/%s", logPath, fileDate), os.ModePerm)
	if err != nil {
		logrus.Error(err)
		return
	}

	filename := fmt.Sprintf("%s/%s/%s.log", logPath, fileDate, appName)
	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	if err != nil {
		logrus.Error(err)
		return
	}
	fileHook := FileDateHook{file, logPath, fileDate, appName}

	logrus.AddHook(&fileHook)
}

最后main代碼:

import (
    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
    "studyGin/GinStudy03_Logrus/log"
    "studyGin/GinStudy03_Logrus/middleware"
)

func main() {

    log.InitFile("logrus_study/gin_logrus/logs", "server")
    router := gin.New()
    router.Use(middleware.LogMiddleware())

    router.GET("/", func(c *gin.Context) {
       logrus.Info("來了")
       c.JSON(200, gin.H{"msg": "你好"})
    })
    router.Run(":8081")

}

訪問地址:http://127.0.0.1:8081/

Go學(xué)習第十八章——Gin日志與第三方工具Logrus,golang,學(xué)習,gin,開發(fā)語言,筆記,后端

Over?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-726877.html

到了這里,關(guān)于Go學(xué)習第十八章——Gin日志與第三方工具Logrus的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 第十八章 ObjectScript - 使用例程

    可以將例程視為 ObjectScript 程序。例程可以從頭開始編寫,也可以在編譯類時自動生成。 在 ObjectScript 例程中,標簽定義以下代碼單元之一的起點: Procedures 過程(可選地返回一個值)。過程中定義的變量是該過程私有的,這意味著它們不可用于其他代碼。對于函數(shù)和子例程

    2024年02月10日
    瀏覽(17)
  • Go學(xué)習第十六章——Gin文件上傳與下載

    Go學(xué)習第十六章——Gin文件上傳與下載

    1.1 入門案例(單文件) 1.2 服務(wù)端保存文件的幾種方式 SaveUploadedFile SaveUploadedFile函數(shù)用于將文件保存到指定的路徑下。第一個參數(shù)是文件對象,第二個參數(shù)是保存文件的路徑。 Create+Copy FormFile函數(shù)用于獲取上傳的文件。它返回一個文件對象,其中包含了文件的元數(shù)據(jù)(名稱、

    2024年02月08日
    瀏覽(21)
  • Go學(xué)習第十七章——Gin中間件與路由

    Go學(xué)習第十七章——Gin中間件與路由

    Gin框架允許開發(fā)者在處理請求的過程中,加入用戶自己的鉤子(Hook)函數(shù)。這個鉤子函數(shù)就叫中間件,中間件適合處理一些公共的業(yè)務(wù)邏輯,比如登錄認證、權(quán)限校驗、數(shù)據(jù)分頁、記錄日志、耗時統(tǒng)計等 即比如,如果訪問一個網(wǎng)頁的話,不管訪問什么路徑都需要進行登錄,

    2024年02月07日
    瀏覽(20)
  • 《TCP IP網(wǎng)絡(luò)編程》第十八章

    《TCP IP網(wǎng)絡(luò)編程》第十八章

    線程背景: ????????第 10 章介紹了多進程服務(wù)端的實現(xiàn)方法。多進程模型與 select 和 epoll 相比的確有自身的優(yōu)點,但同時也有問題。如前所述, 創(chuàng)建(復(fù)制)進程的工作本身會給操作系統(tǒng)帶來相當沉重的負擔。而且,每個進程都具有獨立的內(nèi)存空間,所以進程間通信的實

    2024年02月12日
    瀏覽(27)
  • Go學(xué)習第十五章——Gin參數(shù)綁定bind與驗證器

    Go學(xué)習第十五章——Gin參數(shù)綁定bind與驗證器

    在Gin框架中, bind 用于綁定參數(shù),即將請求參數(shù)綁定到結(jié)構(gòu)體中。通過使用 bind ,我們可以方便地將請求參數(shù)與結(jié)構(gòu)體字段進行綁定,從而更方便地處理和驗證參數(shù)。 Gin框架提供了多種綁定方法,包括Query參數(shù)綁定、Form參數(shù)綁定、JSON參數(shù)綁定等。下面分別介紹這些方法的詳

    2024年02月07日
    瀏覽(25)
  • 【新版系統(tǒng)架構(gòu)】第十八章-安全架構(gòu)設(shè)計理論與實踐

    【新版系統(tǒng)架構(gòu)】第十八章-安全架構(gòu)設(shè)計理論與實踐

    信息系統(tǒng)安全設(shè)計重點考慮:系統(tǒng)安全保障體系,信息安全體系架構(gòu) 系統(tǒng)安全保障體系: 安全區(qū)域策略的確定,根據(jù)安全區(qū)域的劃分,主管部門應(yīng)制定針對性的安全策略 統(tǒng)一配置和管理防病毒系統(tǒng),主管部門應(yīng)當建立整體防御策略,以實現(xiàn)統(tǒng)一的配置和管理 網(wǎng)絡(luò)安全管理,

    2024年02月13日
    瀏覽(25)
  • 華為HCIE課堂筆記第十八章 SR技術(shù)

    SR可以通過控制器實現(xiàn)集中算路,并根據(jù)業(yè)務(wù)的不同下發(fā)不同的路徑給到頭端設(shè)備,頭端設(shè)備將路徑標簽通過標簽棧的形式壓入到報文中,沿途的設(shè)備不需要維護路徑信息,僅按照標簽棧中的棧頂進行報文轉(zhuǎn)發(fā)即可。 控制平面:擴展后的IGP協(xié)議,通過IGP分發(fā)標簽 轉(zhuǎn)發(fā)平面:基

    2024年02月19日
    瀏覽(22)
  • Hotspot源碼解析-第十八章-元空間的創(chuàng)建與分配

    元空間就是從C堆中劃出來的一片完整的區(qū)域,為了提升元數(shù)據(jù)的內(nèi)存分配效率,又把元空間按若干個chunk內(nèi)存塊管理起來,其中chunk塊又分為已使用和空間兩種類型,并分別用VirtualSpaceList和ChunkManager來管理,chunk內(nèi)存塊之間以鏈表的形式關(guān)聯(lián)起來,同時為了滿足不同元數(shù)據(jù)占

    2024年02月01日
    瀏覽(15)
  • Docker第十八章 : 構(gòu)建您的第一個Java鏡像

    第十八章 : 構(gòu)建您的第一個Java鏡像 本章知識點: 介紹構(gòu)建java鏡像的基本步驟,以及如何通過阿里云效和阿里云容器鏡像服務(wù),構(gòu)建您的第一個Java鏡像。 導(dǎo)讀 Java入門指南教您如何使用Docker創(chuàng)建容器化的Spring Boot應(yīng)用程序。在本模塊中,您將學(xué)習如何: 使用Maven克隆并運行

    2024年02月22日
    瀏覽(26)
  • 第十八章_Redis緩存預(yù)熱+緩存雪崩+緩存擊穿+緩存穿透

    第十八章_Redis緩存預(yù)熱+緩存雪崩+緩存擊穿+緩存穿透

    緩存預(yù)熱 緩存預(yù)熱就是系統(tǒng)啟動前,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。避免在用戶請求的時候,先查詢數(shù)據(jù)庫,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)。 可以通過@PostConstruct初始化白名單數(shù)據(jù) 緩存雪崩 發(fā)生? redis主機掛了,Redis?全盤崩潰

    2024年02月07日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包