### Install Agent Skill using npx Source: https://context7.com/boristane/agent-skills/llms.txt Installs the Agent Skills logging-best-practices skill using the npx command-line tool. This is a prerequisite for AI agents to utilize the logging guidelines. ```bash npx add-skill boristane/agent-skills ``` -------------------------------- ### JSON Logging Schema Example in TypeScript Source: https://context7.com/boristane/agent-skills/llms.txt This example demonstrates a consistent JSON schema for logging across all services. It shows a sample wide event object with various fields including timestamp, service, request ID, user context, article details, and performance metrics. The example emphasizes emitting single-line JSON and adding data to the wide event instead of logging unstructured strings. ```typescript // All services use the same schema const wideEvent = { timestamp: '2024-09-08T06:14:05.680Z', service: 'articles', request_id: 'req_abc123', message: 'Article created', user: { id: 'user_123', subscription: 'premium' }, article: { id: 'article_456', title: 'My Post' }, duration_ms: 268, status_code: 201, }; // Emit as single-line JSON logger.info(wideEvent); // Never log unstructured strings - add data to wide event instead wideEvent.order = { id: orderId, status: 'created' }; wideEvent.payment = { error: { message: error.message } }; // Now it's queryable: WHERE order.status = 'created' ``` -------------------------------- ### Consistent Schema Example (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Demonstrates a consistent schema structure using TypeScript, ensuring uniformity across services. This helps in simplifying data querying and integration. ```typescript { request_id: 'req_abc', user: { id: 'user_123' }, duration_ms: 268, status_code: 200, } ``` -------------------------------- ### Configuring a Single Pino Logger Instance (TypeScript) Source: https://context7.com/boristane/agent-skills/llms.txt This example demonstrates how to configure a single Pino logger instance at application startup using TypeScript. It sets up logging level, custom formatters, and automatically includes environment context in all log messages. This ensures consistent logging across the application. ```typescript // lib/logger.ts - Single logger configuration import pino from 'pino'; // Configure once at startup export const logger = pino({ level: process.env.LOG_LEVEL || 'info', formatters: { level: (label) => ({ level: label }), }, base: { // Environment context added to ALL logs automatically service: process.env.SERVICE_NAME, version: process.env.SERVICE_VERSION, commit_hash: process.env.COMMIT_SHA, region: process.env.AWS_REGION, environment: process.env.NODE_ENV, }, }); // Usage everywhere else - just import // services/checkout.ts import { logger } from '../lib/logger'; logger.info({ event: 'checkout_completed', orderId }); ``` -------------------------------- ### Structured Logging Example (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Illustrates how to add structured data to wide events for queryable logs, replacing unstructured console logs. This approach enhances debugging capabilities at scale. ```typescript wideEvent.order = { id: orderId, status: 'created' }; wideEvent.payment = { error: { message: error.message } }; // Now it's queryable: WHERE order.status = 'created' ``` -------------------------------- ### Emit Structured Log Event as JSON (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Shows an example of a structured log event object and how to emit it as a single-line JSON string using a logger. This format is universally supported, enables nested objects for complex context, and is easily parsed by log aggregation systems. ```typescript const wideEvent = { timestamp: '2024-09-08T06:14:05.680Z', service: 'articles', requestId: 'req_abc123', message: 'Article created', user: { id: 'user_123', subscription: 'premium' }, article: { id: 'article_456', title: 'My Post' }, duration_ms: 268, status_code: 201, }; // Emit as single-line JSON logger.info(wideEvent); ``` -------------------------------- ### Log Event Emphasizing Business Context for Criticality (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/context.md This TypeScript example highlights how to structure a log event to emphasize critical business context. It includes details like user subscription tier, lifetime value, cart total, and feature flag status to quickly assess the business impact of an error. This helps in prioritizing and understanding the severity of issues. ```typescript const wideEvent = { requestId: 'req_123', method: 'POST', path: '/checkout', status_code: 500, // Business context that changes response priority user: { id: 'user_456', subscription: 'enterprise', // High-value customer account_age_days: 1247, // Long-term customer lifetime_value_cents: 4850000, // $48,500 LTV }, cart: { total_cents: 249900, // $2,499 order contains_annual_plan: true, // Recurring revenue at stake }, feature_flags: { new_payment_flow: true, // Was new code involved? }, error: { type: 'PaymentError', code: 'card_declined', }, }; // Now you KNOW this is critical: Enterprise customer, $48.5k LTV, // trying to make a $2.5k purchase, and new_payment_flow is enabled ``` -------------------------------- ### Implement Request Correlation IDs (JSON Example) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/pitfalls.md Ensure requests can be traced across services by propagating a unique request ID. Without correlation, it's impossible to connect related log events from different services. This example contrasts logs missing a request ID with logs that include a common `request_id` for easier debugging. ```json // Service A logs { message: 'Order created', order_id: 'ord_123' } // Service B logs { message: 'Inventory reserved', items: 3 } // No way to connect these two events! ``` ```json // Both services include the same request_id { request_id: 'req_abc', message: 'Order created', order_id: 'ord_123' } { request_id: 'req_abc', message: 'Inventory reserved', items: 3 } // Query: WHERE request_id = 'req_abc' shows the full flow ``` -------------------------------- ### Example of a Wide Log Event with Rich Context (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/context.md This TypeScript code snippet demonstrates a comprehensive log event structure. It includes timing, request details, infrastructure information, high-cardinality user context, business context like cart details and feature flags, and payment information. This structure allows for detailed analysis and debugging. ```typescript const wideEvent = { // Timing timestamp: '2024-09-08T06:14:05.680Z', duration_ms: 268, // Request context method: 'POST', path: '/checkout', requestId: 'req_abc123', // Infrastructure service: 'checkout-service', version: '2.4.1', region: 'us-east-1', commit_hash: '690de31f', // User context (HIGH CARDINALITY - millions of unique values) user: { id: 'user_456', subscription: 'premium', account_age_days: 847, lifetime_value_cents: 284700, }, // Business context cart: { id: 'cart_xyz', item_count: 3, total_cents: 15999, coupon_applied: 'SAVE20', }, // Payment details payment: { method: 'card', provider: 'stripe', latency_ms: 189, }, // Feature flags - crucial for debugging rollouts feature_flags: { new_checkout_flow: true, }, // Outcome status_code: 200, outcome: 'success', }; ``` -------------------------------- ### Consolidate Log Lines Per Request (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/pitfalls.md Avoid emitting multiple log lines per request, which creates noise and hinders efficient querying. Instead, consolidate relevant information into a single, comprehensive log event. This example demonstrates how to transform scattered console logs into a single structured object. ```typescript app.post('/checkout', async (c) => { console.log('Received checkout request'); // Line 1 console.log(`User ID: ${c.get('userId')}`); // Line 2 const user = await getUser(c.get('userId')); console.log(`User fetched: ${user.email}`); // Line 3 const cart = await getCart(user.id); console.log(`Cart fetched: ${cart.items.length} items`); // Line 4 const payment = await processPayment(cart); console.log(`Payment processed: ${payment.status}`); // Line 5 console.log('Checkout completed successfully'); // Line 6 return c.json({ orderId: payment.orderId }); }); // 6 log lines per request = noise ``` ```typescript // Single wide event with everything const wideEvent = { method: 'POST', path: '/checkout', user: { id: user.id, email: user.email }, cart: { item_count: cart.items.length, total: cart.total }, payment: { status: payment.status, order_id: payment.orderId }, status_code: 200, duration_ms: 1247, }; ``` -------------------------------- ### Design for Unknown Unknowns with Wide Events (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/pitfalls.md Traditional logging often misses 'unknown unknowns' – unexpected issues. Implement wide events that capture rich context, enabling investigation of unforeseen problems. This example shows how to enrich log events with user and article details to diagnose issues like access restrictions for trial users. ```typescript // Logging only for anticipated issues app.post('/articles', async (c) => { const article = await createArticle(c.req.body, user); if (!article.published) { console.log('Article created but not published'); // Anticipated issue } return c.json({ article }); }); // Bug: "Users on free trial can't see their articles" // Your logs say: "Article created successfully" ✓ // But you have NO visibility into: // - Which users are affected (free trial? all?) // - What subscription plans see this issue // - When it started ``` ```typescript // Wide event captures everything wideEvent.user = { id: user.id, subscription: user.subscription, trial: user.trial, trial_expiration: user.trialExpiration, }; wideEvent.article = { id: article.id, published: article.published, // Captured even though we didn't anticipate the bug }; // Now you can query: WHERE article.published = false GROUP BY user.trial // Result: 95% of unpublished articles are from trial users! ``` -------------------------------- ### Configure Single Logger Instance (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Configures a single Pino logger instance at application startup to ensure consistent formatting, log levels, and output destinations across all modules. It automatically includes environment context in all logs. This approach avoids the risk of misconfigured loggers in different files. ```typescript // lib/logger.ts - Single logger configuration import pino from 'pino'; // Configure once at startup export const logger = pino({ level: process.env.LOG_LEVEL || 'info', formatters: { level: (label) => ({ level: label }), }, base: { // Environment context added to ALL logs automatically service: process.env.SERVICE_NAME, version: process.env.SERVICE_VERSION, commit_hash: process.env.COMMIT_SHA, region: process.env.AWS_REGION, environment: process.env.NODE_ENV, }, }); // Usage everywhere else - just import // services/checkout.ts import { logger } from '../lib/logger'; logger.info({ event: 'checkout_completed', orderId }); ``` -------------------------------- ### Including Environment Characteristics in Log Events (TypeScript) Source: https://context7.com/boristane/agent-skills/llms.txt This snippet shows how to add environment and deployment information to log events, including commit hash, version, deployment ID, service name, region, and runtime details. This aids in correlating issues with specific deployments or infrastructure. ```typescript const wideEvent = { // ... request and business context // Environment characteristics env: { // Deployment info commit_hash: process.env.COMMIT_SHA || process.env.GIT_COMMIT, version: process.env.SERVICE_VERSION || process.env.npm_package_version, deployment_id: process.env.DEPLOYMENT_ID, deploy_time: process.env.DEPLOY_TIMESTAMP, // Infrastructure service: process.env.SERVICE_NAME, region: process.env.AWS_REGION || process.env.REGION, availability_zone: process.env.AWS_AVAILABILITY_ZONE, instance_id: process.env.INSTANCE_ID || process.env.HOSTNAME, container_id: process.env.CONTAINER_ID, // Runtime node_version: process.version, runtime: process.env.AWS_EXECUTION_ENV || 'node', memory_limit_mb: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE, // Environment type environment: process.env.NODE_ENV || process.env.ENVIRONMENT, stage: process.env.STAGE, }, }; ``` -------------------------------- ### Implement Wide Event Middleware (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Implements middleware to capture wide event data for all requests, including timing, status, and environment context. It initializes the event, makes it accessible for enrichment by handlers, and ensures emission in a finally block. This standardizes request logging across the application. ```typescript // middleware/wideEvent.ts import { logger } from '../lib/logger'; // Capture environment once at startup const envContext = { service: process.env.SERVICE_NAME, version: process.env.SERVICE_VERSION, commit_hash: process.env.COMMIT_SHA, region: process.env.AWS_REGION, environment: process.env.NODE_ENV, instance_id: process.env.HOSTNAME, }; export function wideEventMiddleware() { return async (c: Context, next: Next) => { const startTime = Date.now(); // Initialize event with standard fields + environment const wideEvent: Record = { request_id: c.get('requestId') || crypto.randomUUID(), timestamp: new Date().toISOString(), method: c.req.method, path: c.req.path, user_agent: c.req.header('user-agent'), ...envContext, // Environment automatically included }; // Make event accessible to handlers for enrichment c.set('wideEvent', wideEvent); try { await next(); wideEvent.status_code = c.res.status; wideEvent.outcome = c.res.status < 400 ? 'success' : 'error'; } catch (error) { wideEvent.status_code = 500; wideEvent.outcome = 'error'; wideEvent.error = { type: error.name, message: error.message, }; throw error; } finally { wideEvent.duration_ms = Date.now() - startTime; logger.info(wideEvent); // Uses the single logger } }; } // Apply middleware globally app.use('*', wideEventMiddleware()); ``` -------------------------------- ### Adding Business Context to Log Events (TypeScript) Source: https://context7.com/boristane/agent-skills/llms.txt This snippet demonstrates how to enrich log events with detailed business context, such as user subscription level, account age, lifetime value, cart details, and feature flag status. This helps in understanding the business impact of issues. ```typescript const wideEvent = { requestId: 'req_123', method: 'POST', path: '/checkout', status_code: 500, // Business context that changes response priority user: { id: 'user_456', subscription: 'enterprise', // High-value customer account_age_days: 1247, // Long-term customer lifetime_value_cents: 4850000, // $48,500 LTV }, cart: { total_cents: 249900, // $2,499 order contains_annual_plan: true, // Recurring revenue at stake }, feature_flags: { new_payment_flow: true, // Was new code involved? }, error: { type: 'PaymentError', code: 'card_declined', }, }; // Now you KNOW this is critical: Enterprise customer, $48.5k LTV, // trying to make a $2.5k purchase, and new_payment_flow is enabled ``` -------------------------------- ### Implement Wide Event Middleware in TypeScript Source: https://context7.com/boristane/agent-skills/llms.txt This middleware captures request timing, status, environment context, and emits a structured wide event. It initializes the event with standard fields and environment context, makes it accessible to handlers for enrichment, and logs the event with timing and outcome details. Handlers then focus on adding business context. ```typescript // middleware/wideEvent.ts import { logger } from '../lib/logger'; // Capture environment once at startup const envContext = { service: process.env.SERVICE_NAME, version: process.env.SERVICE_VERSION, commit_hash: process.env.COMMIT_SHA, region: process.env.AWS_REGION, environment: process.env.NODE_ENV, instance_id: process.env.HOSTNAME, }; export function wideEventMiddleware() { return async (c: Context, next: Next) => { const startTime = Date.now(); // Initialize event with standard fields + environment const wideEvent: Record = { request_id: c.get('requestId') || crypto.randomUUID(), timestamp: new Date().toISOString(), method: c.req.method, path: c.req.path, user_agent: c.req.header('user-agent'), ...envContext, // Environment automatically included }; // Make event accessible to handlers for enrichment c.set('wideEvent', wideEvent); try { await next(); wideEvent.status_code = c.res.status; wideEvent.outcome = c.res.status < 400 ? 'success' : 'error'; } catch (error) { wideEvent.status_code = 500; wideEvent.outcome = 'error'; wideEvent.error = { type: error.name, message: error.message, }; throw error; } finally { wideEvent.duration_ms = Date.now() - startTime; logger.info(wideEvent); // Uses the single logger } }; } // Apply middleware globally app.use('*', wideEventMiddleware()); // Handlers just enrich with business context app.post('/checkout', async (c) => { const wideEvent = c.get('wideEvent'); const user = c.get('user'); // Add business context - environment already included by middleware wideEvent.user = { id: user.id, subscription: user.subscription }; const cart = await getCart(user.id); wideEvent.cart = { id: cart.id, total: cart.total }; const order = await createOrder(cart); wideEvent.order = { id: order.id }; return c.json(order, 201); }); // Middleware handles: timing, status, environment, emission // Handler handles: business context only ``` -------------------------------- ### Including Environment Characteristics in Log Events (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/context.md This TypeScript code snippet shows how to incorporate environment and deployment details into log events. It includes fields like commit hash, service version, region, instance ID, and Node.js version, which are crucial for correlating issues with deployments and identifying environment-specific problems. ```typescript const wideEvent = { // ... request and business context // Environment characteristics env: { // Deployment info commit_hash: process.env.COMMIT_SHA || process.env.GIT_COMMIT, version: process.env.SERVICE_VERSION || process.env.npm_package_version, deployment_id: process.env.DEPLOYMENT_ID, deploy_time: process.env.DEPLOY_TIMESTAMP, // Infrastructure service: process.env.SERVICE_NAME, region: process.env.AWS_REGION || process.env.REGION, availability_zone: process.env.AWS_AVAILABILITY_ZONE, instance_id: process.env.INSTANCE_ID || process.env.HOSTNAME, container_id: process.env.CONTAINER_ID, // Runtime node_version: process.version, runtime: process.env.AWS_EXECUTION_ENV || 'node', memory_limit_mb: process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE, // Environment type environment: process.env.NODE_ENV || process.env.ENVIRONMENT, stage: process.env.STAGE, }, }; ``` -------------------------------- ### Emit Wide Event per Request in TypeScript Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/SKILL.md Demonstrates emitting a single, context-rich 'wide event' at the completion of a request. This pattern consolidates all relevant information into one structured log entry, improving debugging and analytics. It includes error handling and timing information. ```typescript const wideEvent: Record = { method: 'POST', path: '/checkout', requestId: c.get('requestId'), timestamp: new Date().toISOString(), }; try { const user = await getUser(c.get('userId')); wideEvent.user = { id: user.id, subscription: user.subscription }; const cart = await getCart(user.id); wideEvent.cart = { total_cents: cart.total, item_count: cart.items.length }; wideEvent.status_code = 200; wideEvent.outcome = 'success'; return c.json({ success: true }); } catch (error) { wideEvent.status_code = 500; wideEvent.outcome = 'error'; wideEvent.error = { message: error.message, type: error.name }; throw error; } finally { wideEvent.duration_ms = Date.now() - startTime; logger.info(wideEvent); } ``` -------------------------------- ### Correct Logging Pattern with Wide Events (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/wide-events.md Illustrates the correct implementation of wide events by building a single, comprehensive event object throughout the request lifecycle and emitting it once at completion. This pattern ensures all relevant context is captured, even in case of errors, and facilitates powerful querying. ```typescript app.post('/articles', async (c) => { const startTime = Date.now(); const wideEvent: Record = { method: 'POST', path: '/articles', service: 'articles', requestId: c.get('requestId'), }; try { const body = await c.req.json(); const user = await getUser(c.get('userId')); wideEvent.user = { id: user.id, subscription: user.subscription, trial: user.trial, }; const article = await database.saveArticle({ ...body, ownerId: user.id }); wideEvent.article = { id: article.id, title: article.title, published: article.published, }; await cache.set(article.id, article); wideEvent.cache = { operation: 'write', key: article.id }; wideEvent.status_code = 201; wideEvent.outcome = 'success'; return c.json({ article }, 201); } catch (error) { wideEvent.status_code = 500; wideEvent.outcome = 'error'; wideEvent.error = { message: error.message, type: error.name }; throw error; } finally { wideEvent.duration_ms = Date.now() - startTime; wideEvent.timestamp = new Date().toISOString(); logger.info(JSON.stringify(wideEvent)); } }); // Single event with all context - queryable by any field ``` -------------------------------- ### Enrich Wide Event with Business Context (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/structure.md Demonstrates how request handlers can enrich the `wideEvent` object, which is made available by the middleware. Handlers add business-specific context, such as user details and order information, to the existing event structure. The middleware handles the common logging aspects like timing and status. ```typescript app.post('/checkout', async (c) => { const wideEvent = c.get('wideEvent'); const user = c.get('user'); // Add business context - environment already included by middleware wideEvent.user = { id: user.id, subscription: user.subscription }; const cart = await getCart(user.id); wideEvent.cart = { id: cart.id, total: cart.total }; const order = await createOrder(cart); wideEvent.order = { id: order.id }; return c.json(order, 201); }); // Middleware handles: timing, status, environment, emission // Handler handles: business context only ``` -------------------------------- ### Propagating and Extracting Request IDs (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/wide-events.md Demonstrates how to generate a unique request ID in a downstream service and propagate it to subsequent services via headers. It also shows how to extract this request ID in the receiving service to maintain event correlation across distributed systems. ```typescript // Service A - generate and propagate const requestId = c.get('requestId') || crypto.randomUUID(); wideEvent.requestId = requestId; await fetch('http://downstream-service/endpoint', { headers: { 'x-request-id': requestId }, body: JSON.stringify(data), }); // Service B - extract and use const requestId = c.req.header('x-request-id'); wideEvent.requestId = requestId; // Same ID links events together ``` -------------------------------- ### Propagate Request ID for Correlation in TypeScript Source: https://context7.com/boristane/agent-skills/llms.txt Illustrates how to propagate a unique request ID across service calls in TypeScript for request tracing. It shows generating the ID in one service and extracting it in a downstream service to link related events. ```typescript // Service A - generate and propagate const requestId = c.get('requestId') || crypto.randomUUID(); wideEvent.requestId = requestId; await fetch('http://downstream-service/endpoint', { headers: { 'x-request-id': requestId }, body: JSON.stringify(data), }); // Service B - extract and use const requestId = c.req.header('x-request-id'); wideEvent.requestId = requestId; // Same ID links events together // Query: WHERE request_id = 'req_abc' shows the full flow across services ``` -------------------------------- ### Incorrect Logging Pattern (TypeScript) Source: https://github.com/boristane/agent-skills/blob/main/skills/logging-best-practices/rules/wide-events.md Demonstrates an incorrect approach to logging where multiple, disconnected log lines are scattered throughout a request handler. This makes it difficult to query and analyze request data effectively. ```typescript app.post('/articles', async (c) => { console.log('Received POST /articles request'); const body = await c.req.json(); console.log('Request body parsed', { title: body.title }); const user = await getUser(c.get('userId')); console.log('User fetched', { userId: user.id }); const article = await database.saveArticle({ ...body, ownerId: user.id }); console.log('Article saved', { articleId: article.id }); await cache.set(article.id, article); console.log('Cache updated'); console.log('Request completed successfully'); return c.json({ article }, 201); }); // 6 disconnected log lines with scattered context // Cannot query: "show me all article creates by free trial users" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.