Giao diện
Logging chuyên nghiệp 📝
console.log('here') là thừa nhận thất bại.
Tip 1: Structured Logging
Problem
Text logs vô dụng ở quy mô lớn. Không thể query "Hiển thị tất cả lỗi của User 123".
Solution
Structured logging: Log as JSON objects, not strings.
Example
javascript
// Bad: String concatenation
console.log("User login failed: " + user.id + " at " + new Date());
// Bad: Template literals (still string)
console.log(`User ${user.id} login failed at ${new Date()}`);
// Good: Structured logging
logger.info({
event: 'user_login_failed',
userId: user.id,
timestamp: new Date().toISOString(),
context: {
ip: req.ip,
userAgent: req.headers['user-agent'],
reason: 'invalid_password'
}
});Benefits:
- Query by field: "Show all
user_login_failedevents" - Filter by user: "Show all events for
userId: 123" - Aggregate: "Count login failures per hour"
- Index in ELK, Datadog, CloudWatch
Pro Tips
- Use logging library: Winston, Pino, Bunyan
- Consistent field names:
userIdnotuser_idoruid - Include correlation ID for request tracing
- Add metadata: Environment, service name, version
Tip 2: Log Levels
Problem
Mọi thứ đều log là INFO, không phân biệt được mức độ nghiêm trọng.
Solution
Use appropriate log levels: DEBUG, INFO, WARN, ERROR, FATAL.
Example
javascript
// DEBUG: Detailed info for development
logger.debug({
event: 'cache_lookup',
key: 'user:123',
hit: true,
ttl: 3600
});
// INFO: High-level events
logger.info({
event: 'server_started',
port: 3000,
environment: 'production'
});
// WARN: Something unusual, but not breaking
logger.warn({
event: 'api_retry',
attempt: 2,
maxAttempts: 3,
reason: 'timeout'
});
// ERROR: Operation failed
logger.error({
event: 'payment_failed',
userId: 123,
amount: 99.99,
error: error.message,
stack: error.stack
});
// FATAL: Application crash
logger.fatal({
event: 'database_connection_lost',
error: error.message
});When to Use:
- DEBUG: Development only, verbose details
- INFO: Normal operations, milestones
- WARN: Degraded state, retries, fallbacks
- ERROR: Failed operations, caught exceptions
- FATAL: Application crash, unrecoverable errors
Pro Tips
- Production: Set level to INFO or WARN
- Development: Set level to DEBUG
- Environment variable:
LOG_LEVEL=debug - Never log sensitive data at any level
Tip 3: Context is King
Problem
Log message không đủ thông tin để debug: "Payment failed" - Which user? Which payment?
Solution
Include context: User ID, request ID, transaction ID, etc.
Example
javascript
// Bad: No context
logger.error('Payment failed');
// Bad: Some context
logger.error('Payment failed for user 123');
// Good: Rich context
logger.error({
event: 'payment_failed',
userId: 123,
orderId: 'ORD-456',
amount: 99.99,
currency: 'USD',
paymentMethod: 'credit_card',
gateway: 'stripe',
gatewayTransactionId: 'ch_abc123',
error: {
code: 'card_declined',
message: 'Insufficient funds',
declineCode: 'insufficient_funds'
},
requestId: 'req-789',
timestamp: '2024-01-15T10:30:00Z',
userAgent: 'Mozilla/5.0...',
ip: '192.168.1.1'
});Essential Context:
- Who: User ID, session ID
- What: Event name, action
- When: Timestamp (ISO 8601)
- Where: Service name, server ID, environment
- Why: Error message, reason code
- How: Request ID for tracing
Pro Tips
- Correlation ID: Track request across services
- Include stack trace for errors
- Sanitize sensitive data: Credit cards, passwords
- Add business context: Order ID, product ID
Tip 4: Don't Log Sensitive Data
Problem
Logs chứa passwords, credit cards, API keys → Security breach.
Solution
Sanitize logs: Redact sensitive fields.
Example
javascript
// ⚠️ SECURITY WARNING: This example shows what NOT to do!
// NEVER log passwords, API keys, or credentials in production
// ❌ BAD: Logging sensitive data (DO NOT DO THIS!)
logger.info({
event: 'user_created',
user: {
email: 'user@example.com',
password: 'user-password-123', // ❌ NEVER log passwords!
creditCard: '4111111111111111' // ❌ NEVER log credit cards!
}
});
// ✅ GOOD: Sanitized logging
logger.info({
event: 'user_created',
user: {
email: 'user@example.com',
// Password should NEVER be logged, not even redacted
creditCard: '****1111' // Last 4 digits only
}
});
// Better: Sanitization function
function sanitize(obj) {
const sensitive = ['password', 'creditCard', 'ssn', 'apiKey'];
const sanitized = { ...obj };
sensitive.forEach(field => {
if (sanitized[field]) {
sanitized[field] = '[REDACTED]';
}
});
return sanitized;
}
logger.info({
event: 'user_created',
user: sanitize(userData)
});Never Log:
- Passwords, API keys, tokens
- Credit card numbers, CVV
- Social security numbers
- Personal health information
- Private keys, certificates
Pro Tips
- Automated sanitization: Middleware/interceptor
- Log last 4 digits of cards:
****1111 - Hash sensitive IDs if needed for correlation
- Audit logs regularly for leaks
Tip 5: Performance Considerations
Problem
Excessive logging làm chậm application, tốn disk space.
Solution
Log strategically: Không log mọi thứ, optimize hot paths.
Example
javascript
// Bad: Logging in tight loop
for (let i = 0; i < 1000000; i++) {
logger.debug(`Processing item ${i}`); // ❌ 1M log entries!
}
// Good: Log summary
logger.info(`Processing ${items.length} items`);
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
}
logger.info(`Processed ${items.length} items in ${duration}ms`);
// Bad: Expensive computation in log
logger.debug(`User data: ${JSON.stringify(hugeObject)}`); // ❌ Always computed
// Good: Lazy evaluation
logger.debug(() => `User data: ${JSON.stringify(hugeObject)}`); // ✅ Only if DEBUG enabledOptimization Strategies:
- Sample logs: Log 1% of requests in high-traffic endpoints
- Async logging: Don't block main thread
- Log rotation: Prevent disk full
- Conditional logging: Check level before expensive operations
Pro Tips
- Use fast logging library: Pino (fastest for Node.js)
- Avoid synchronous I/O in logs
- Buffer logs, flush periodically
- Monitor log volume, set alerts
Tip 6: Correlation IDs for Distributed Tracing
Problem
Request đi qua nhiều services, không trace được flow.
Solution
Correlation ID: Unique ID cho mỗi request, pass qua tất cả services.
Example
javascript
// API Gateway: Generate correlation ID
app.use((req, res, next) => {
req.correlationId = req.headers['x-correlation-id'] || uuidv4();
res.setHeader('x-correlation-id', req.correlationId);
next();
});
// Service A: Log with correlation ID
logger.info({
event: 'order_created',
correlationId: req.correlationId,
orderId: order.id
});
// Service A → Service B: Pass correlation ID
const response = await fetch('http://service-b/api/payment', {
headers: {
'x-correlation-id': req.correlationId
}
});
// Service B: Log with same correlation ID
logger.info({
event: 'payment_processed',
correlationId: req.headers['x-correlation-id'],
paymentId: payment.id
});
// Now query logs: "Show all events for correlationId: abc-123"
// → See entire request flow across servicesPro Tips
- Use UUID v4 for correlation IDs
- Include in all logs for that request
- Pass in HTTP headers:
x-correlation-id,x-request-id - Distributed tracing tools: Jaeger, Zipkin, OpenTelemetry
Tip 7: Error Logging Best Practices
Problem
Error logs thiếu thông tin để debug, hoặc quá nhiều noise.
Solution
Log errors properly: Stack trace, context, error code.
Example
javascript
// Bad: Swallow error
try {
await processPayment();
} catch (error) {
// ❌ Silent failure
}
// Bad: Log only message
try {
await processPayment();
} catch (error) {
logger.error(error.message); // ❌ No stack trace
}
// Good: Full error logging
try {
await processPayment();
} catch (error) {
logger.error({
event: 'payment_processing_failed',
error: {
name: error.name,
message: error.message,
stack: error.stack,
code: error.code
},
context: {
userId: user.id,
orderId: order.id,
amount: order.total
},
correlationId: req.correlationId
});
// Re-throw or handle
throw error;
}
// Better: Error serialization
function serializeError(error) {
return {
name: error.name,
message: error.message,
stack: error.stack,
code: error.code,
...error // Include custom properties
};
}
logger.error({
event: 'payment_processing_failed',
error: serializeError(error),
context: { userId, orderId }
});Pro Tips
- Always include stack trace
- Log at error boundary, not every catch
- Include error code for categorization
- Don't log same error multiple times (log once at boundary)
Tip 8: Log Aggregation and Monitoring
Problem
Logs scattered across nhiều servers, không thể search hoặc analyze.
Solution
Centralized logging: Ship logs to aggregation service.
Example
javascript
// Winston with Elasticsearch transport
const winston = require('winston');
const { ElasticsearchTransport } = require('winston-elasticsearch');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
// Console for development
new winston.transports.Console(),
// Elasticsearch for production
new ElasticsearchTransport({
level: 'info',
clientOpts: {
node: 'http://elasticsearch:9200'
},
index: 'logs'
})
]
});
// Now logs are searchable in Kibana
logger.info({
event: 'user_login',
userId: 123
});Popular Solutions:
- ELK Stack: Elasticsearch, Logstash, Kibana
- Datadog: Logs, metrics, traces in one platform
- CloudWatch: AWS native logging
- Splunk: Enterprise log management
- Grafana Loki: Lightweight, Prometheus-like
Pro Tips
- Set up alerts: Error rate > threshold
- Create dashboards: Visualize trends
- Retention policy: Keep logs 30-90 days
- Cost optimization: Sample high-volume logs
Tip 9: Development vs Production Logging
Problem
Development logs quá verbose cho production, production logs không đủ cho debugging.
Solution
Environment-specific configuration: Different log levels per environment.
Example
javascript
// config/logger.js
const winston = require('winston');
const level = process.env.LOG_LEVEL ||
(process.env.NODE_ENV === 'production' ? 'info' : 'debug');
const logger = winston.createLogger({
level,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
// Development: Pretty console output
...(process.env.NODE_ENV !== 'production' ? [
new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
})
] : []),
// Production: JSON to file/service
...(process.env.NODE_ENV === 'production' ? [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
] : [])
]
});
module.exports = logger;Environment Differences:
- Development: DEBUG level, colorized console, pretty format
- Staging: INFO level, JSON format, file + console
- Production: WARN level, JSON format, centralized logging only
Pro Tips
- Use environment variables:
LOG_LEVEL=debug - Never log DEBUG in production (performance + security)
- Enable DEBUG temporarily for troubleshooting
- Separate error logs:
error.logvscombined.log
Tip 10: Logging Metrics and Analytics
Problem
Logs chỉ dùng để debug, không dùng cho business insights.
Solution
Log business events: Track user behavior, feature usage, performance.
Example
javascript
// Technical logging
logger.info({
event: 'http_request',
method: 'POST',
path: '/api/orders',
statusCode: 201,
duration: 145
});
// Business logging
logger.info({
event: 'order_completed',
userId: 123,
orderId: 'ORD-456',
revenue: 99.99,
currency: 'USD',
items: 3,
paymentMethod: 'credit_card',
shippingMethod: 'express',
couponUsed: 'SAVE10',
isFirstOrder: false,
customerLifetimeValue: 450.00
});
// Feature usage logging
logger.info({
event: 'feature_used',
feature: 'dark_mode',
userId: 123,
enabled: true
});
// Performance logging
logger.info({
event: 'query_performance',
query: 'getUserOrders',
duration: 234,
rowsReturned: 50,
cacheHit: false
});Analytics Use Cases:
- Revenue tracking: Sum
order_completedevents - Feature adoption: Count
feature_usedevents - Performance monitoring: Average
query_performanceduration - User behavior: Funnel analysis from logs
Pro Tips
- Separate analytics logs from debug logs
- Use dedicated analytics tools: Mixpanel, Amplitude
- Real-time dashboards: Grafana, Kibana
- A/B testing: Log experiment variants
📋 Quick Reference
| Practice | Why | How |
|---|---|---|
| Structured Logging | Queryable, filterable | Log JSON objects |
| Log Levels | Prioritize issues | DEBUG, INFO, WARN, ERROR, FATAL |
| Context | Debug faster | Include user ID, request ID, etc. |
| Sanitize | Security | Redact passwords, cards |
| Performance | Don't slow app | Sample, async, lazy eval |
| Correlation IDs | Trace requests | Pass ID across services |
| Error Logging | Full debugging info | Stack trace + context |
| Aggregation | Centralized search | ELK, Datadog, CloudWatch |
| Environment Config | Right verbosity | DEBUG in dev, INFO in prod |
| Business Metrics | Analytics | Log user behavior, revenue |