awslabs / aws-lambda-go-api-proxy

lambda-go-api-proxy makes it easy to port APIs written with Go frameworks such as Gin (https://gin-gonic.github.io/gin/ ) to AWS Lambda and Amazon API Gateway.
Apache License 2.0
1.04k stars 197 forks source link

Is it possible to use it with X-Ray? #68

Open maslick opened 4 years ago

maslick commented 4 years ago

I have the following setup.

package main

import (
    "context"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/awslabs/aws-lambda-go-api-proxy/gin"
    "github.com/maslick/api-less/src"
)

type LambdaController struct {
    src.RestController
}

func (ctrl *LambdaController) LambdaHandler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    router := ctrl.InitRouter()
    return ginadapter.New(router).ProxyWithContext(ctx, req)
}

func main() {
    service := &Service{Repo: &Repo{config()}}
    controller := RestController{Service: service}
    ctrl := LambdaController{controller}
    lambda.Start(ctrl.LambdaHandler)
}
import (
    "github.com/gin-gonic/gin"
)

type RestController struct {
    Service IService
}

func (api *RestController) InitRouter() *gin.Engine {
    router := gin.New()
    public := router.Group("/")
    public.GET("/users", api.Service.findAllUsers)
    return router
}

func (api *RestController) findAllUsers(c *gin.Context) {
    employees, err := api.Service.findAllUsers(c.Copy())
    if err != nil {
        c.String(500, err.Error())
        return
    }
    c.JSON(http.StatusOK, response)
}
import (
    "context"
)

type IService interface {
    FindAllUsers(ctx context.Context) ([]User, error)
}

type Service struct {
    Repo   IRepo
}

func (s *Service) findAllUsers(ctx context.Context) ([]User, error) {
    return s.Repo.FindAllUsers(ctx)
}
import (
    "context"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
    "github.com/aws/aws-xray-sdk-go/xray"
)

type IRepo interface {
    FindAllUsers(ctx context.Context) ([]User, error)
}

type Repo struct {
    db *dynamodb.DynamoDB
}

func config() *dynamodb.DynamoDB {
    region := GetEnv("REGION", "eu-central-1")
    config := &aws.Config{
        Region: aws.String(region),
    }

    sess := session.Must(session.NewSession(config))
    svc := dynamodb.New(sess)
    xray.AWS(svc.Client)
    return svc
}

func (r *Repo) FindAllUsers(ctx context.Context) ([]User, error) {
    var users []User
    input := &dynamodb.ScanInput{
        TableName: &tableName,
    }
    result, _ := r.db.ScanWithContext(ctx, input)

    for _, i := range result.Items {
        item := User{}
        _ = dynamodbattribute.UnmarshalMap(i, &item)
        users = append(users, item)
    }

    return users, nil
}

Is it possible to use XRay with aws-lambda-go-api-proxy? I get the following error in Cloudwatch:

2020-07-05T12:28:20Z [ERROR] Suppressing AWS X-Ray context missing panic: failed to begin subsegment named 'dynamodb': segment cannot be found.
2020-07-05T12:28:20Z [ERROR] Suppressing AWS X-Ray context missing panic: failed to begin subsegment named 'attempt': segment cannot be found.
2020-07-05T12:28:20Z [ERROR] Suppressing AWS X-Ray context missing panic: failed to begin subsegment named 'unmarshal': segment cannot be found.

Any ideas? Thanks in advance!

maslick commented 4 years ago

Answering my own question, I had to use c.Request.Context() instead of c.Copy():

func (api *RestController) findAllUsers(c *gin.Context) {
    employees, err := api.Service.findAllUsers(c.Request.Context())
    if err != nil {
        c.String(500, err.Error())
        return
    }
    c.JSON(http.StatusOK, response)
}

After this everything works! 🥇