Skip to content

Build, JSON and runtime notes

Start with your first Lambda for the short path.

Add tracing

When you need traces, install the Tracer module and configure an OTLP collector:

CGO_ENABLED=0 go get github.com/rambow-cloud/powertools-lambda-go/[email protected]

The maintained repository example composes Tracer and Logger:

package main

import (
    "context"
    stdlog "log"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/rambow-cloud/powertools-lambda-go/logger"
    "github.com/rambow-cloud/powertools-lambda-go/tracer"
)

type Event struct {
    Name string `json:"name"`
}
type Response struct {
    Message string `json:"message"`
}

func main() {
    appLog := logger.New(
        logger.WithServiceName("hello"),
        logger.WithErrorHandler(func(err error) {
            stdlog.Printf("logging failed: %v", err)
        }),
    )
    tr, err := tracer.New(
        tracer.WithServiceName("hello"),
        tracer.WithCaptureResponse(false),
        tracer.WithErrorHandler(func(err error) {
            stdlog.Printf("tracing failed: %v", err)
        }),
    )
    if err != nil {
        stdlog.Fatal(err)
    }
    handler := func(ctx context.Context, event Event) (Response, error) {
        requestLog := appLog.WithContext(ctx)
        if err := requestLog.Info("Handling request", logger.Fields{"name": event.Name}); err != nil {
            stdlog.Printf("logging failed: %v", err)
        }
        return tracer.Capture(ctx, tr, "greet", func(ctx context.Context) (Response, error) {
            _ = tr.PutAnnotation(ctx, "Operation", "greet")
            return Response{Message: "Hello, " + event.Name}, nil
        })
    }
    // Put the tracer outside the logger wrapper so logs receive the active span context.
    lambda.Start(tracer.WrapHandler(tr, logger.WrapHandler(appLog, handler)))
}

Put Tracer outside Logger so logs can read the active span. Both wrappers share the same invocation identity. This example disables response capture; follow the Tracer guide for child spans and exporter configuration.

Configure observability

These settings are useful starting points for the deployed function:

Environment variable Example Purpose
POWERTOOLS_SERVICE_NAME orders Default service name when no explicit option overrides it
POWERTOOLS_LOG_LEVEL INFO Structured log threshold
POWERTOOLS_LOGGER_LOG_EVENT false Keep full event logging disabled
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4318 OTLP/HTTP collector endpoint
POWERTOOLS_TRACER_CAPTURE_RESPONSE false Disable handler response metadata

The example explicitly sets its service name to hello. Change that option or omit it to use the environment default.

A collector must actually be running at the configured OTLP endpoint. The library does not install a Lambda layer. To send traces to AWS X-Ray, deploy an appropriate collector extension with the awsxray exporter and its required execution-role permissions; follow X-Ray through OpenTelemetry.

Build and package

For the copied Logger-only program, build in your application directory:

CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -tags lambda.norpc -o bootstrap .

Use GOARCH=amd64 for x86_64. Deploy the executable as bootstrap with provided.al2023; the deployment ZIP must retain executable permissions.

To build and package both architectures of the maintained Logger/Tracer example, use the repository's packaging helper. Obtain a checkout:

git clone --branch v1.2.0 https://github.com/rambow-cloud/powertools-lambda-go.git
cd powertools-lambda-go

Run the following commands from the repository root:

$env:CGO_ENABLED = '0'
./scripts/build.ps1
export CGO_ENABLED=0
GOOS=linux GOARCH=amd64 go build -trimpath -tags lambda.norpc -o dist/amd64/bootstrap ./examples/basic
GOOS=linux GOARCH=arm64 go build -trimpath -tags lambda.norpc -o dist/arm64/bootstrap ./examples/basic
go run ./tools/package

The packaging tool verifies static Linux ELF binaries, architecture metadata, and an executable bootstrap ZIP entry with mode 0755.

Lambda architecture Artifact
x86_64 dist/lambda-amd64.zip
arm64 dist/lambda-arm64.zip

Deploy the matching ZIP using your infrastructure tooling with runtime provided.al2023. Invoke with {"name":"Ada"}; the example returns {"message":"Hello, Ada"}. Deployment and cloud invocation are separate from local builds and CI.

Local verification

The default runtime acceptance environment uses Docker. Follow the maintained local integration runner and local acceptance scope.

Outside Lambda, tracing is disabled unless you explicitly supply tracer.WithLocalTracing(true). A local collector is still required to export spans. POWERTOOLS_DEV=true enables readable local logs and disables tracing.

Continue with Logger, Tracer, or Metrics.

JSON decoding and encoding

Maintained packages and examples use encoding/json/v2 and encoding/json/jsontext directly. Go 1.27 provides these APIs without an experiment flag. JSON object member names must be unique, UTF-8 and escaped Unicode must be valid, and struct fields match JSON names case-sensitively. Give application structs explicit json tags that match their input.

Nil slices and maps encode as [] and {}. omitempty omits empty JSON values; use omitzero when a field's Go zero value should be absent. Map member order is unspecified unless an operation explicitly requires ordering. Strings do not escape HTML by default. Byte arrays and slices use Base64; time.Duration requires an explicit supported format. Custom encoding can implement MarshalJSONTo(*jsontext.Encoder) error; decoding can implement UnmarshalJSONFrom(*jsontext.Decoder) error. See the JSON v2 API for the complete current behavior. json.RawMessage and json.Number from encoding/json remain usable value types; maintained serialization calls use v2 APIs.

These rules describe JSON serialization owned by Powertools. Invocation input/output serialization performed by aws-lambda-go follows that SDK's encoding contract.