Golang中gin框架API请求处于pending状态如何解决

Golang中gin框架API请求处于pending状态如何解决 我在使用 Golang Gin 框架时,如果使用了第三方库 sirupsen/logrus,我的 API 会显示为“挂起”状态。

如果我在服务器应用程序上按下回车键,它就会开始工作。

4 回复

为什么不使用Go内置的结构化日志记录器(slog)?

更多关于Golang中gin框架API请求处于pending状态如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


好的,谢谢。我会按你的建议进行更新。

packs:

sirupsen/logrus

你好!我们需要更多上下文才能提供帮助,如果可以的话,也许分享一些代码;

你尝试过其他的日志库吗?另外,请注意 sirupsen/logrus 目前处于维护模式,其最后一次提交是在一年多以前,我建议使用一些维护更活跃的库,比如 Zerolog 或 phuslu/log。

在 Gin 框架中使用 logrus 时 API 请求处于 pending 状态,通常是由于 logrus 的默认输出配置与 Gin 的并发处理冲突导致的。logrus 默认使用带锁的 os.Stdout,在高并发场景下可能阻塞请求处理。

以下是解决方案和示例代码:

1. 使用带缓冲的日志输出

package main

import (
    "bufio"
    "os"
    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
)

func main() {
    // 创建带缓冲的 writer
    writer := bufio.NewWriter(os.Stdout)
    defer writer.Flush()
    
    // 配置 logrus 使用缓冲输出
    logrus.SetOutput(writer)
    
    r := gin.Default()
    
    r.GET("/ping", func(c *gin.Context) {
        logrus.Info("处理请求")
        c.JSON(200, gin.H{"message": "pong"})
    })
    
    r.Run(":8080")
}

2. 使用异步日志处理器

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
    "gopkg.in/natefinch/lumberjack.v2"
)

func main() {
    // 配置日志轮转(异步写入文件)
    logger := &lumberjack.Logger{
        Filename:   "app.log",
        MaxSize:    100, // MB
        MaxBackups: 3,
        MaxAge:     28, // days
    }
    
    logrus.SetOutput(logger)
    logrus.SetFormatter(&logrus.JSONFormatter{})
    
    r := gin.Default()
    
    r.GET("/api", func(c *gin.Context) {
        // 异步记录日志
        go func() {
            logrus.WithFields(logrus.Fields{
                "path": c.Request.URL.Path,
                "method": c.Request.Method,
            }).Info("请求记录")
        }()
        
        c.JSON(200, gin.H{"status": "success"})
    })
    
    r.Run(":8080")
}

3. 禁用 logrus 的锁机制

package main

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

func main() {
    // 创建无锁的 logger 实例
    logger := logrus.New()
    logger.SetOutput(io.Discard) // 或指定其他输出
    logger.SetLevel(logrus.InfoLevel)
    logger.SetFormatter(&logrus.TextFormatter{
        DisableColors: true,
        FullTimestamp: true,
    })
    
    // 替换标准 logger
    logrus.StandardLogger().ReplaceHooks(make(logrus.LevelHooks))
    
    r := gin.Default()
    
    // 使用自定义的 logger 中间件
    r.Use(func(c *gin.Context) {
        c.Next()
        logger.WithFields(logrus.Fields{
            "status": c.Writer.Status(),
            "path":   c.Request.URL.Path,
        }).Info("请求完成")
    })
    
    r.GET("/test", func(c *gin.Context) {
        c.JSON(200, gin.H{"data": "test"})
    })
    
    r.Run(":8080")
}

4. 检查是否存在死锁情况

package main

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

var (
    logMutex sync.Mutex
    logger   = logrus.New()
)

func safeLog(fields logrus.Fields, message string) {
    go func() {
        logMutex.Lock()
        defer logMutex.Unlock()
        logger.WithFields(fields).Info(message)
    }()
}

func main() {
    r := gin.Default()
    
    r.GET("/endpoint", func(c *gin.Context) {
        // 使用线程安全的日志记录
        safeLog(logrus.Fields{
            "endpoint": "/endpoint",
            "ip":       c.ClientIP(),
        }, "请求到达")
        
        c.JSON(200, gin.H{"result": "ok"})
    })
    
    r.Run(":8080")
}

这些解决方案通过调整 logrus 的输出方式、使用异步处理或禁用锁机制,可以解决 Gin 框架中因 logrus 导致的 API 请求 pending 问题。选择哪种方案取决于具体的应用场景和性能要求。

回到顶部