如何在 golang 中为 new relic(Golang New relic 集成)创建通用或全局上下文?

How to create generic or global context in golang for new relic (Golang New relic integration)?

我正在 main.go 中创建新的遗物交易,必须将其传递给处理程序,然后传递给控制器​​,依此类推。有没有一种方法可以全局定义它,然后可以在任何处理程序、控制器或数据库事务中访问?

import(
    "github.com/gin-gonic/gin"
    newrelic "github.com/newrelic/go-agent"
)

// main.go
func newrelicHandler() (gin.HandlerFunc, newrelic.Application) {
    newrelicConfig := newrelic.NewConfig("NEW_RELIC_APP_NAME", "NEW_RELIC_APP_KEY")
    app, err := newrelic.NewApplication(newrelicConfig)
    if err != nil {
        return func(c *gin.Context) {
            c.Next()
        }, app
    }
    return func(c *gin.Context) {
        txn := app.StartTransaction(c.Request.URL.Path, c.Writer, c.Request)
        c.Set("newRelicTransaction", txn)
        apm, ok := c.Get("newRelicTransaction")
        defer txn.End()
        c.Next()
    }, app
}

func main() {
    r := gin.New()
    x, app := newrelicHandler()
    r.Use(x)
}


// test/handler.go

func (t *TestHandler) Display(c *gin.Context) {
    apmTxn, ok := c.Get("newRelicTransaction")

    test, err := t.testCtrl.Display(apmTxn)
    if err != nil {
        return err
    }

    c.JSON(http.StatusOK, gin.H{"message": "success"})
}


// test/controller.go

func (t *TestCtrl) Display(txn interface{}) {
    apmTxn, ok := txn.(newrelic.Transaction)
    if !ok {
        fmt.Println("ERR")
    }
    segment := newrelic.StartSegment(apmTxn, "SomeSegmentName")
    // get data
    segment.End()
    return 
}


避免使用全局上下文,而是在入口点创建一个,然后将其作为参数传递给任何需要它的函数。

您可以使用 Gin 框架提供的 nrgin 包。

并且在main()函数中

  • 创建 newrelic 实例 - newrelic.NewApplication(cfg)
  • 调用传入newrelic实例的-nrgin.Middleware(app)函数。这会将 Gin 事务上下文键 - newRelicTransaction 添加到上下文中。
  • 将步骤 2 中的函数注册为所有路由的中间件 - router.Use(nrgin.Middleware(app))

然后您可以将相同的上下文对象传递给可以接受类型 context.Context 参数的其他函数,因为 gin.Context 只是实现了 Go 的 context 接口。

示例代码

import "github.com/newrelic/go-agent/_integrations/nrgin/v1"

func main() {
    cfg := newrelic.NewConfig("Gin App", mustGetEnv("NEW_RELIC_LICENSE_KEY"))
    
    app, err := newrelic.NewApplication(cfg)
    if nil != err {
        fmt.Println(err)
    }

    router := gin.Default()
    router.Use(nrgin.Middleware(app))

    router.GET("/example-get", GetController)

    router.Run(":80")
}

func GetController(c *gin.Context) {
    if txn := nrgin.Transaction(c); nil != txn {
        txn.SetName("custom-name")
    }

    databaseGet(c)

    c.Writer.WriteString("example response...")
}

func databaseGet(c context.Context) {
    if txn := nrgin.Transaction(c); nil != txn {
        txn.SetName("custom-name")
    }

    c.Writer.WriteString("example response...")
}