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

huangapple go评论86阅读模式
英文:

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

问题

我正在创建一个新的遗物事务(new relic transaction)在 main.go 中,并且必须将其传递给处理程序(handler),然后传递给控制器(controller)等等。有没有一种方法可以在全局范围内定义它,然后可以在任何处理程序、控制器或数据库事务中访问它?

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 
}

以上是你提供的代码的翻译。

英文:

I am creating new relic transaction in main.go and have to pass it along to handler and then to controller and so on. Is there a way i can define this globally and then can be accessed in any handler, controller or and db transaction?

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 
}

答案1

得分: 2

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

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

main()函数中:

  • 创建一个newrelic实例 - newrelic.NewApplication(cfg)
  • 调用nrgin.Middleware(app)函数,并将newrelic实例作为参数传递进去。这将在上下文中添加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...")
}
英文:

Avoid using a global context, rather create one at the entrypoint and then just pass it as an argument to any function that needs it.

You can make use of the nrgin package provided by the Gin framework.

And in the main() function

  • Create an instance of newrelic - newrelic.NewApplication(cfg)
  • Call the - nrgin.Middleware(app) function passing in the newrelic instance. This will add the Gin transaction context key - newRelicTransaction to the context.
  • Register the function in step 2 as a middleware for all your routes - router.Use(nrgin.Middleware(app))

You can then pass this same context object to your other functions that can accept a parameter of type context.Context since gin.Context is simply implementing the context interface of Go.

Example code

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...")
}

huangapple
  • 本文由 发表于 2021年10月11日 17:20:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/69523822.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定