22 / 67 · 06 Observability-Driven Testing · Structured Logging Best Practices← prev⊞ allnext →☰ Read as one page
4.3Implementing Structured Logging (Python)
# structured_logging_setup.py
import structlog
import logging
# Configure structlog for JSON output
structlog.configure(
processors=[
structlog.contextvars.merge_contextvars, # thread-safe context
structlog.processors.add_log_level, # add "level" field
structlog.processors.StackInfoRenderer(), # include stack traces
structlog.dev.set_exc_info, # attach exception info
structlog.processors.TimeStamper(fmt="iso"), # ISO 8601 timestamps
structlog.processors.JSONRenderer(), # output as JSON
],
wrapper_class=structlog.make_filtering_bound_logger(logging.INFO),
context_class=dict,
logger_factory=structlog.PrintLoggerFactory(),
)
log = structlog.get_logger()
def process_order(user_id: str, order_id: str, items: list):
# Bind context that will appear in ALL subsequent log entries
log_ctx = log.bind(user_id=user_id, order_id=order_id, item_count=len(items))
log_ctx.info("order_processing_started")
try:
total = calculate_total(items)
log_ctx.info("order_total_calculated", total_cents=total)
payment_result = charge_payment(user_id, total)
log_ctx.info("payment_processed",
payment_id=payment_result.id,
payment_method=payment_result.method)
reserve_inventory(items)
log_ctx.info("inventory_reserved")
log_ctx.info("order_processing_completed", duration_ms=elapsed())
except PaymentTimeoutError as e:
log_ctx.error("payment_timeout",
downstream_service="payment-service",
timeout_seconds=e.timeout,
retry_count=e.retries)
raise
except InsufficientInventoryError as e:
log_ctx.warning("inventory_insufficient",
missing_items=e.missing_items,
available=e.available)
raise
Node.js/TypeScript Example
// structured-logger.ts
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
base: {
service: 'order-service',
version: process.env.APP_VERSION,
environment: process.env.NODE_ENV,
},
});
export function processOrder(userId: string, orderId: string, items: Item[]) {
const orderLog = logger.child({ userId, orderId, itemCount: items.length });
orderLog.info('order_processing_started');
try {
const total = calculateTotal(items);
orderLog.info({ totalCents: total }, 'order_total_calculated');
const payment = chargePayment(userId, total);
orderLog.info({ paymentId: payment.id, method: payment.method }, 'payment_processed');
orderLog.info('order_processing_completed');
} catch (err) {
orderLog.error({ err, downstreamService: 'payment-service' }, 'order_processing_failed');
throw err;
}
}