Skip to content

Latest commit

 

History

History
239 lines (175 loc) · 7.88 KB

File metadata and controls

239 lines (175 loc) · 7.88 KB
title description
Tracer
Core utility

import Note from "../../src/components/Note"

Tracer is an opinionated thin wrapper for AWS X-Ray Python SDK.

Tracer showcase

Key features

  • Capture cold start as annotation, and responses as well as full exceptions as metadata
  • Run functions locally with SAM CLI without code change to disable tracing
  • Explicitly disable tracing via env var POWERTOOLS_TRACE_DISABLED="true"
  • Support tracing async methods
  • Auto patch supported modules, or a tuple of explicit modules supported by AWS X-Ray

Initialization

Your AWS Lambda function must have permission to send traces to AWS X-Ray - Here is an example using AWS Serverless Application Model (SAM)

Resources:
    HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
        ...
        Runtime: python3.8
        Tracing: Active # highlight-line
        Environment:
            Variables:
                POWERTOOLS_SERVICE_NAME: example

You can either explicitly pass using service param or via POWERTOOLS_SERVICE_NAME environment variable. The service name is utilized for exceptions, metadata, and namespace data.

from aws_lambda_powertools import Tracer
# POWERTOOLS_SERVICE_NAME defined
tracer = Tracer() # highlight-line

# Explicit definition
tracer = Tracer(service="booking")

Lambda handler

You can trace your Lambda function handler via capture_lambda_handler.

When using this decorator, Tracer performs these additional tasks to ease operations:

  • Creates a ColdStart annotation to easily filter traces that have had an initialization overhead
  • Adds any response, or full exceptions generated by the handler as metadata
from aws_lambda_powertools import Tracer
tracer = Tracer()

@tracer.capture_lambda_handler # highlight-line
def handler(event, context):
    charge_id = event.get('charge_id')
    payment = collect_payment(charge_id)
    ...

Annotations

Annotations are key-values indexed by AWS X-Ray on a per trace basis. You can use them to filter traces as well as to create Trace Groups.

You can add annotations using put_annotation method from Tracer.

from aws_lambda_powertools import Tracer
tracer = Tracer()

@tracer.capture_lambda_handler
def handler(event, context):
    ...
    tracer.put_annotation(key="PaymentStatus", value="SUCCESS") # highlight-line

Metadata

Metadata are non-indexed values that can add additional context for an operation.

You can add metadata using put_metadata method from Tracer.

from aws_lambda_powertools import Tracer
tracer = Tracer()

@tracer.capture_lambda_handler
def handler(event, context):
    ...
    ret = some_logic()
    tracer.put_metadata(key="payment_response", value=ret) # highlight-line

Synchronous functions

You can trace a synchronous function using the capture_method.

@tracer.capture_method
def collect_payment(charge_id):
    ret = requests.post(PAYMENT_ENDPOINT) # logic
    tracer.put_annotation("PAYMENT_STATUS", "SUCCESS") # custom annotation
    return ret
...

Asynchronous functions

We do not support async Lambda handler - Lambda handler itself must be synchronous

You can trace an asynchronous function using the capture_method. The decorator will detect whether your function is asynchronous, and adapt its behaviour accordingly.

import asyncio
from aws_lambda_powertools import Tracer
tracer = Tracer()

# highlight-start
@tracer.capture_method
async def collect_payment():
    ...
# highlight-end

@tracer.capture_lambda_handler
def handler(evt, ctx): # highlight-line
    asyncio.run(collect_payment())

Tracing aiohttp requests

This snippet assumes you have aiohttp as a dependency

You can use aiohttp_trace_config function to create a valid aiohttp trace_config object. This is necessary since X-Ray utilizes aiohttp trace hooks to capture requests end-to-end.

import asyncio
import aiohttp

from aws_lambda_powertools import Tracer
from aws_lambda_powertools.tracing import aiohttp_trace_config # highlight-line
tracer = Tracer()

async def aiohttp_task():
    async with aiohttp.ClientSession(trace_configs=[aiohttp_trace_config()]) as session: # highlight-line
        async with session.get("https://httpbin.org/json") as resp:
            resp = await resp.json()
            return resp

Escape hatch mechanism

You can use tracer.provider attribute to access all methods provided by AWS X-Ray xray_recorder object.

This is useful when you need a feature available in X-Ray that is not available in the Tracer utility, for example thread-safe, or context managers.

Concurrent asynchronous functions

As of now, X-Ray SDK will raise an exception when async functions are run and traced concurrently.

A safe workaround mechanism is to use in_subsegment_async available via Tracer escape hatch (tracer.provider).

import asyncio

from aws_lambda_powertools import Tracer
tracer = Tracer()

async def another_async_task():
    # highlight-start
    async with tracer.provider.in_subsegment_async("## another_async_task") as subsegment:
        subsegment.put_annotation(key="key", value="value")
        subsegment.put_metadata(key="key", value="value", namespace="namespace")
        ...
    # highlight-end

async def another_async_task_2():
    ...

@tracer.capture_method
async def collect_payment(charge_id):
    asyncio.gather(another_async_task(), another_async_task_2()) # highlight-line
    ...

Reusing Tracer across your code

Tracer keeps a copy of its configuration after the first initialization. This is useful for scenarios where you want to use Tracer in more than one location across your code base.

When reusing Tracer in Lambda Layers, or in multiple modules, do not set auto_patch=False, because import order matters.

This can result in the first Tracer config being inherited by new instances, and their modules not being patched.
# handler.py
from aws_lambda_powertools import Tracer
tracer = Tracer(service="payment")

@tracer.capture_lambda_handler
def handler(event, context):
    charge_id = event.get('charge_id')
    payment = collect_payment(charge_id)
...
from aws_lambda_powertools import Tracer
# highlight-start
# new instance using existing configuration
tracer = Tracer(service="payment")
# highlight-end

Testing your code

You can safely disable Tracer when unit testing your code using POWERTOOLS_TRACE_DISABLED environment variable.

POWERTOOLS_TRACE_DISABLED=1 python -m pytest

Tips

  • Use annotations on key operations to slice and dice traces, create unique views, and create metrics from it via Trace Groups
  • Use a namespace when adding metadata to group data more easily
  • Annotations and metadata are added to the current subsegment opened. If you want them in a specific subsegment, use a context manager via the escape hatch mechanism