AWS X-Ray
Hands-On
Demo

In this demo, we will:
- Set up IAM roles for X-Ray integration
- Create Lambda functions with X-Ray tracing
- Configure API Gateway with X-Ray tracing
- Deploy a DynamoDB table and enable tracing
- Create a multi-tier application workflow
- Generate traffic and analyze traces
- Use X-Ray Service Map to visualize architecture
- Clean up resources
Agenda
Step 1: Set up IAM Roles for X-Ray Integration


AWSLambdaBasicExecutionRole

AWSXRayDaemonWriteAccess

AmazonDynamoDBFullAccess

LambdaXRayRole





{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:*:*:function:GetProductFunction"
}
]
}

LambdalnvokePolicy
Step 2: Create DynamoDB Table for Application Data


ProductCatalog
ProductId
Create table

Table settings

Capacity calculator

Read/write capacity settings

Warm throughput

Secondary indexes

Encryption at rest

Deletion protection

Tags

The ProductCatalog table was created successfully

Explore table items

Create item

{
"ProductId": {
"S": "PROD-001"
},
"ProductName": {
"S": "Wireless Mouse"
},
"Price": {
"N": "29.99"
},
"Category": {
"S": "Electronics"
},
"Stock": {
"N": "150"
}
}

{
"ProductId": {
"S": "PROD-002"
},
"ProductName": {
"S": "Mechanical Keyboard"
},
"Price": {
"N": "89.99"
},
"Category": {
"S": "Electronics"
},
"Stock": {
"N": "75"
}
}

ProductCatalog
Step 3: Create Lambda Functions with X-Ray Tracing


GetProductFunction

Change default execution role

Additional configurations

Logging configuration

Lambda service traces

Save

import json
import boto3
import random
import time
# Initialize DynamoDB client
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('ProductCatalog')
def lambda_handler(event, context):
# Simulate variable processing time
process_time = random.uniform(0.1, 0.5)
try:
# Extract product ID from event
if 'pathParameters' not in event or 'productId' not in event['pathParameters']:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Product ID is required'}),
'headers': {
'Content-Type': 'application/json'
}
}
product_id = event['pathParameters']['productId']
print(f"Fetching product: {product_id}")
# Simulate validation processing
time.sleep(process_time)
# Query DynamoDB
response = table.get_item(Key={'ProductId': product_id})
if 'Item' not in response:
print(f"Product not found: {product_id}")
return {
'statusCode': 404,
'body': json.dumps({'error': 'Product not found'}),
'headers': {
'Content-Type': 'application/json'
}
}
print(f"Product found: {product_id}")
# Simulate post-processing
time.sleep(0.1)
return {
'statusCode': 200,
'body': json.dumps(response['Item'], default=str),
'headers': {
'Content-Type': 'application/json'
}
}
except Exception as e:
print(f"Error: {str(e)}")
import traceback
traceback.print_exc()
return {
'statusCode': 500,
'body': json.dumps({'error': 'Internal server error', 'details': str(e)}),
'headers': {
'Content-Type': 'application/json'
}
}

ProcessOrderFunction
Create 2nd function

Change default execution role

Additional configurations

Logging configuration

Lambda service traces


import json
import boto3
import random
import time
from datetime import datetime
# Initialize clients
dynamodb = boto3.resource('dynamodb')
lambda_client = boto3.client('lambda')
table = dynamodb.Table('ProductCatalog')
def lambda_handler(event, context):
# Parse request body
try:
if 'body' in event:
body = json.loads(event['body'])
else:
body = event
product_id = body.get('productId')
quantity = body.get('quantity', 1)
print(f"Processing order - Product: {product_id}, Quantity: {quantity}")
except Exception as e:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Invalid request body'}),
'headers': {
'Content-Type': 'application/json'
}
}
try:
# Call GetProductFunction to validate product exists
invoke_response = lambda_client.invoke(
FunctionName='GetProductFunction',
InvocationType='RequestResponse',
Payload=json.dumps({
'pathParameters': {'productId': product_id}
})
)
response_payload = json.loads(invoke_response['Payload'].read())
if response_payload['statusCode'] != 200:
return {
'statusCode': 404,
'body': json.dumps({'error': 'Product not found'}),
'headers': {
'Content-Type': 'application/json'
}
}
product = json.loads(response_payload['body'])
# Simulate inventory check with random delay
time.sleep(random.uniform(0.2, 0.6))
if product.get('Stock', 0) < quantity:
return {
'statusCode': 400,
'body': json.dumps({'error': 'Insufficient stock'}),
'headers': {
'Content-Type': 'application/json'
}
}
# Simulate order processing
time.sleep(random.uniform(0.3, 0.7))
# Occasionally simulate a slow operation
if random.random() > 0.8:
print("Slow operation triggered")
time.sleep(2.0)
order_id = f"ORD-{int(time.time())}"
return {
'statusCode': 200,
'body': json.dumps({
'orderId': order_id,
'productId': product_id,
'quantity': quantity,
'totalPrice': float(product.get('Price', 0)) * quantity,
'status': 'Processing'
}),
'headers': {
'Content-Type': 'application/json'
}
}
except Exception as e:
print(f"Error processing order: {str(e)}")
import traceback
traceback.print_exc()
return {
'statusCode': 500,
'body': json.dumps({'error': 'Order processing failed'}),
'headers': {
'Content-Type': 'application/json'
}
}
Step 4: Configure API Gateway with X-Ray Tracing



ProductServiceAPI
API for product catalog and order processing
Create REST API

Create resource

products
Create resource

{productId}
Create resource

Resources

Create method

Create method

Resources

orders
Create resource

Create method

Lambda function

Create method

Deploy API


prod

Edit Stage

Edit logs and tracing

Step 5: Generate Traffic and Test the Application
# Test retrieving a product
curl -X GET "${API_ENDPOINT}/products/PROD-001"
# Set your API endpoint
API_ENDPOINT=
# Test non-existent product
curl -X GET "${API_ENDPOINT}/products/PROD-999"


# Process an order
curl -X POST "${API_ENDPOINT}/orders" \
-H "Content-Type: application/json" \
-d '{
"productId": "PROD-001",
"quantity": 2
}'
# Test with invalid product
curl -X POST "${API_ENDPOINT}/orders" \
-H "Content-Type: application/json" \
-d '{
"productId": "INVALID-PRODUCT",
"quantity": 1
}'
# Generate 20 requests with varying patterns
for i in {1..20}; do
# Alternate between products
if [ $((i % 2)) -eq 0 ]; then
PRODUCT="PROD-001"
else
PRODUCT="PROD-002"
fi
# GET request
curl -s -X GET "${API_ENDPOINT}/products/${PRODUCT}" > /dev/null &
# POST request
curl -s -X POST "${API_ENDPOINT}/orders" \
-H "Content-Type: application/json" \
-d "{\"productId\": \"${PRODUCT}\", \"quantity\": $((RANDOM % 5 + 1))}" > /dev/null &
# Small delay between requests
sleep 0.5
done
echo "Traffic generation complete. Wait for all requests to finish..."
wait
echo "All requests completed."
Step 6: Analyze Traces in X-Ray Console






























Heading 1
Heading 2
Heading 3
Regular Text
Learn the fundamentals and find valuable information to get the most out of AWS.
Formatted Text
Code Text
cat > test_memorydb.py << EOF
import redis
import json
import sys
from datetime import datetime
# Check for command line argument
if len(sys.argv) != 2:
print("Usage: python3 test_memorydb.py <your-cluster-endpoint>")
print("Example: python3 test_memorydb.py memorydb-demo-cluster.abc123.memorydb.us-east-1.amazonaws.com")
sys.exit(1)
cluster_endpoint = sys.argv[1]
# Configure connection
try:
r = redis.Redis(
host=cluster_endpoint,
port=6379,
ssl=True,
decode_responses=True
)
# Test connection
r.ping()
print(f"✓ Successfully connected to MemoryDB cluster: {cluster_endpoint}")
except redis.ConnectionError as e:
print(f"✗ Failed to connect to {cluster_endpoint}")
print(f"Error: {e}")
print("\nPlease check:")
print(" - Cluster endpoint is correct")
print(" - Security group allows port 6379 from this instance")
print(" - Instance and cluster are in the same VPC")
sys.exit(1)
# Session management example
def create_session(user_id, username):
session_data = {
'user_id': user_id,
'username': username,
'login_time': datetime.now().isoformat()
}
# Store session with 30-minute expiration
r.setex(f'session:{user_id}', 1800, json.dumps(session_data))
print(f"✓ Session created for {username}")
def get_session(user_id):
session = r.get(f'session:{user_id}')
if session:
return json.loads(session)
return None
# Test the functions
print("\n--- Testing Session Management ---")
create_session('user001', 'alice')
session = get_session('user001')
print(f"✓ Retrieved session: {session}")
# Cache example with automatic expiration
print("\n--- Testing Cache with TTL ---")
r.setex('cache:api_response', 300, json.dumps({'data': 'cached response'}))
print(f"✓ Cache created with TTL: {r.ttl('cache:api_response')} seconds")
# Additional tests for data persistence
print("\n--- Testing Data Persistence ---")
r.set('persistent:data', 'This will survive a failover')
print(f"✓ Persistent data stored")
# Test various data structures
print("\n--- Testing Redis Data Structures ---")
# Hash
r.hset('user:1001', mapping={
'name': 'Alice',
'email': 'alice@example.com',
'lastLogin': datetime.now().isoformat()
})
print(f"✓ Hash created: {r.hgetall('user:1001')}")
# List
r.lpush('recent:logins', 'user001', 'user002', 'user003')
print(f"✓ List created: {r.lrange('recent:logins', 0, -1)}")
# Set
r.sadd('active:users', 'alice', 'bob', 'charlie')
print(f"✓ Set created with {r.scard('active:users')} members")
print("\n✓ All tests completed successfully!")
EOF
🙏
Thanks
for
Watching
AWS X-Ray - Hands-On Demo
By Deepak Dubey
AWS X-Ray - Hands-On Demo
AWS X-Ray - Hands-On Demo
- 39