# AWS SDK v2

> Instrument AWS SDK v2 Go applications with the Last9 Go Agent for automatic service call tracing

Source: https://last9.io/docs/integrations/frameworks/go/aws-sdk/

Use the Last9 Go Agent to instrument AWS SDK v2 calls with automatic tracing. Every SDK call — S3, DynamoDB, SQS, SNS, Lambda, and others — produces a span with attributes for the AWS service, operation, region, and request ID. Per-service attributes (e.g. DynamoDB table name, SQS queue URL) are captured automatically.

## Prerequisites

- Go 1.22 or higher
- AWS SDK v2 (`github.com/aws/aws-sdk-go-v2`)
- Last9 account with OTLP credentials

## Installation

1. **Install the Last9 Go Agent**

   ```bash
   go get github.com/last9/go-agent
   ```

2. **Set Environment Variables**

   ```bash
   export OTEL_SERVICE_NAME="your-service"
   export OTEL_EXPORTER_OTLP_ENDPOINT="$last9_otlp_endpoint"
   export OTEL_EXPORTER_OTLP_HEADERS="Authorization=$last9_otlp_auth_header"
   export OTEL_TRACES_SAMPLER="always_on"
   export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"
   ```

3. **Instrument your AWS config**

   Call `last9aws.InstrumentSDK(&cfg)` once after loading your AWS config, before creating any service clients:

   ```go
   package main

   import (
       "context"
       "log"

       "github.com/aws/aws-sdk-go-v2/config"
       "github.com/aws/aws-sdk-go-v2/service/s3"
       "github.com/aws/aws-sdk-go-v2/service/sqs"
       "github.com/aws/aws-sdk-go-v2/service/dynamodb"
       "github.com/last9/go-agent"
       last9aws "github.com/last9/go-agent/integrations/aws"
   )

   func main() {
       if err := agent.Start(); err != nil {
           log.Fatalf("failed to start agent: %v", err)
       }
       defer agent.Shutdown()

       ctx := context.Background()

       cfg, err := config.LoadDefaultConfig(ctx)
       if err != nil {
           log.Fatal(err)
       }

       // Instrument once — all clients created from cfg are automatically traced
       last9aws.InstrumentSDK(&cfg)

       s3Client  := s3.NewFromConfig(cfg)
       sqsClient := sqs.NewFromConfig(cfg)
       dynClient := dynamodb.NewFromConfig(cfg)

       // All SDK calls now produce traces automatically
       _ = s3Client
       _ = sqsClient
       _ = dynClient
   }
   ```

## Example: S3 Operations

```go
import (
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

s3Client := s3.NewFromConfig(cfg)

// GetObject — produces a span: aws.s3.GetObject
result, err := s3Client.GetObject(ctx, &s3.GetObjectInput{
    Bucket: aws.String("my-bucket"),
    Key:    aws.String("data/file.json"),
})

// PutObject — produces a span: aws.s3.PutObject
_, err = s3Client.PutObject(ctx, &s3.PutObjectInput{
    Bucket: aws.String("my-bucket"),
    Key:    aws.String("data/output.json"),
    Body:   reader,
})
```

## Example: SQS Operations

```go
import (
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/service/sqs"
)

sqsClient := sqs.NewFromConfig(cfg)

// SendMessage — span includes queue URL attribute
_, err := sqsClient.SendMessage(ctx, &sqs.SendMessageInput{
    QueueUrl:    aws.String("https://sqs.us-east-1.amazonaws.com/123456789/my-queue"),
    MessageBody: aws.String(`{"event": "order.created"}`),
})

// ReceiveMessage
output, err := sqsClient.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{
    QueueUrl:            aws.String(queueURL),
    MaxNumberOfMessages: 10,
})
```

## Example: DynamoDB Operations

```go
import (
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)

dynClient := dynamodb.NewFromConfig(cfg)

// PutItem — span includes table name attribute
_, err := dynClient.PutItem(ctx, &dynamodb.PutItemInput{
    TableName: aws.String("users"),
    Item: map[string]types.AttributeValue{
        "user_id": &types.AttributeValueMemberS{Value: "abc-123"},
        "name":    &types.AttributeValueMemberS{Value: "Alice"},
    },
})

// GetItem
result, err := dynClient.GetItem(ctx, &dynamodb.GetItemInput{
    TableName: aws.String("users"),
    Key: map[string]types.AttributeValue{
        "user_id": &types.AttributeValueMemberS{Value: "abc-123"},
    },
})
```

## Custom Options

Pass `otelaws.Option` values to extend or override how attributes are recorded:

```go
import "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws"

last9aws.InstrumentSDK(&cfg,
    otelaws.WithAttributeBuilder(myCustomAttributeBuilder),
)
```

## What Gets Traced Automatically

| Attribute                  | Example                               |
| -------------------------- | ------------------------------------- |
| `rpc.system`               | `aws-api`                             |
| `rpc.service`              | `S3`, `DynamoDB`, `SQS`               |
| `rpc.method`               | `GetObject`, `PutItem`, `SendMessage` |
| `aws.region`               | `us-east-1`                           |
| `aws.request_id`           | `abc123...`                           |
| `aws.dynamodb.table_names` | `users` (DynamoDB only)               |
| `aws.sqs.queue_url`        | `https://sqs...` (SQS only)           |

## View Traces

After running your application, navigate to [Trace Explorer](https://app.last9.io/traces) in Last9. Filter by `rpc.system = aws-api` to see all AWS SDK calls.

---

## Troubleshooting

Please get in touch with us on [Discord](https://discord.com/invite/Q3p2EEucx9) or [Email](mailto:support@last9.io) if you have any questions.
