Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apmongo and apmgin do not work when used together #1573

Open
bck01215 opened this issue Feb 2, 2024 · 4 comments
Open

apmongo and apmgin do not work when used together #1573

bck01215 opened this issue Feb 2, 2024 · 4 comments
Labels

Comments

@bck01215
Copy link

bck01215 commented Feb 2, 2024

Describe the bug
Using apmmongo and apmgin does not allow mongo to send spans

To Reproduce
Steps to reproduce the behavior:

  1. use gin to create handler
  2. call mongo with gin context in handler

Expected behavior
Expect spans to generate from use

@6fears7
Copy link

6fears7 commented Feb 2, 2024

As an example:

What I'd expect to work:

        // r = *gin.Engine
	r.GET("/myendpoint", func(c *gin.Context) {
		ctx := apm.ContextWithTransaction(c, tx) // type: context.Context
		result, tErr := GetMyEndpoint(ctx, mClient, filter, databaseSuffix)

Result:
{"level":"debug","time":"2024-02-02T16:56:13-05:00","message":"sent request with 6 transactions, 0 spans, 0 errors, 0 metricsets"}

What I've done as a workaround and found to work:

        // r = *gin.Engine
	r.GET("/myendpoint", func(c *gin.Context) {
	// manually start trace
		tx := apm.DefaultTracer.StartTransaction("GetMyEndpoint", "request")
		defer tx.End()
		ctx := apm.ContextWithTransaction(c, tx)
		result, tErr := GetMyEndpoint(ctx, mClient, filter, databaseSuffix) // type: context.Context

Result:
{"level":"debug","time":"2024-02-02T16:56:13-05:00","message":"sent request with 6 transactions, 762 spans, 0 errors, 0 metricsets"}


A previous solution (#585) said to use the .Request.Context() but I did not find this to work.

        // r = *gin.Engine
	r.GET("/myendpoint", func(c *gin.Context) {
		result, tErr := GetMyEndpoint(c.Request.Context(), mClient, filter, databaseSuffix)

Result:
{"level":"debug","time":"2024-02-02T16:56:13-05:00","message":"sent request with 6 transactions, 0 spans, 0 errors, 0 metricsets"}

I am going to do some more work to determine if there's something odd on my end, though figured it'd be worth sharing this data regarding the issue.

@dmathieu
Copy link
Member

dmathieu commented Feb 5, 2024

apmgin calls apmhttp to create the transaction, and then sets it as c.Request:

tx, body, req := apmhttp.StartTransactionWithBody(m.tracer, requestName, c.Request)
defer tx.End()
c.Request = req

On its end, apmhttp, when creating the transaction, calls StartTransaction and sets the new context onto the request:

func StartTransactionWithBody(tracer *apm.Tracer, name string, req *http.Request) (*apm.Transaction, *apm.BodyCapturer, *http.Request) {
tx, req := StartTransaction(tracer, name, req)
bc := tracer.CaptureHTTPRequestBody(req)
if bc != nil {
req = RequestWithContext(apm.ContextWithBodyCapturer(req.Context(), bc), req)
}
return tx, bc, req
}

However, it seems that context is only being set if the request body is not nil.
That seems a bit weird. @axw do you know the reason for that?

@6fears7 could you try the last alternative (using c.Request.Context()) which should indeed be the right way to do this, but when the request has a non-nil body? (I'm not saying always having a body is a fix of course, this is just an attempt to confirm my investigation).

@6fears7
Copy link

6fears7 commented Feb 5, 2024

I set up a frontend that submits a POST request to a fake endpoint called "/testgin" with a JSON body of {"gintest": "test"} // 'test' is the collection in Mongo:

On the backend, TestGin retrieves the document from Mongo based off the collectionName:

	r.POST("/testgin", func(c *gin.Context) {
                
                var reqBody map[string]interface{}
		if err := c.ShouldBindJSON(&reqBody); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		collectionName := reqBody["gintest"].(string)

		result, err := ginTester.TestGin(mClient, databaseSuffix, c.Request.Context(), collectionName)
		
		
// {"level":"debug","time":"2024-02-05T15:30:59-05:00","message":"sent request with 1 transaction, 0 spans, 0 errors, 0 metricsets"}

No dice.

@axw
Copy link
Member

axw commented Feb 6, 2024

However, it seems that context is only being set if the request body is not nil.
That seems a bit weird. @axw do you know the reason for that?

StartTransactionWithBody calls StartTransaction, which adds the transaction to the context. The one you're referring to is just for the body capturer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants