Instead of many thin logs that are hard to correlate, emit one comprehensive log per operation with all relevant context.
This makes debugging dramatically faster — one query returns everything about a specific order, user, or request.
# ❌ Scattered thin logs
sentry_sdk.logger.info("Starting checkout")
sentry_sdk.logger.info("Validating cart")
sentry_sdk.logger.info("Processing payment")
sentry_sdk.logger.info("Checkout complete")
# ✅ One wide event with full context
sentry_sdk.logger.info(
"Checkout completed",
attributes={
"order_id": order.id,
"user_id": user.id,
"user_tier": user.subscription,
"cart_value": cart.total,
"item_count": len(cart.items),
"payment_method": "stripe",
"duration_ms": (time.time() - start_time) * 1000,
}
)Add attributes that help you prioritize and debug:
- User context — tier, account age, lifetime value
- Transaction data — order value, item count
- Feature state — active feature flags
- Request metadata — endpoint, method, duration
This lets you filter logs by high-value customers or specific features.
sentry_sdk.logger.info(
"API request completed",
attributes={
# User context
"user_id": user.id,
"user_tier": user.plan, # "free" | "pro" | "enterprise"
"account_age_days": user.age_days,
# Request data
"endpoint": "/api/orders",
"method": "POST",
"duration_ms": 234,
# Business context
"order_value": 149.99,
# Join lists into a string — array values aren't stored as attributes
"feature_flags": ",".join(["new-checkout", "discount-v2"]),
}
)Pick a naming convention and stick with it across your codebase. Inconsistent names make queries impossible.
Recommended: Use snake_case for custom attributes to match Python conventions.
# ❌ Inconsistent naming
{"user": "123"}
{"userId": "123"}
{"user_id": "123"}
{"UserID": "123"}
# ✅ Consistent snake_case
{
"user_id": "123",
"order_id": "456",
"cart_value": 99.99,
"item_count": 3,
}