Logging Best Practices for Developers: Writing Better Logs
Key Takeaways
- Log intentionally, not excessively. Avoid logging routine successes, sensitive data, large user content, and anything inside loops. Use proper log levels (ERROR, WARN, INFO, DEBUG) and suppress repetitive exceptions to control volume and cost.
- Use structured logging with rich context. Always prefer JSON formats and a common schema like Elastic Common Schema (ECS). Every log line should include timestamp, service name, environment, request ID, and user ID for queryability.
- Optimize for performance and cost. Combine multiple logs into a single structured entry, discard DEBUG logs in production or move them to cold storage, and use modern logging libraries (Structlog, Winston, Serilog, Log4j2 with JSON) to implement these practices efficiently.
Effective log management starts with the application code itself. What you log and how you log it directly impacts the usability, performance, and cost of your log management system. These best practices help developers write logs that are both useful and efficient. For a complete overview of strategy, security, and scalability, read our Ultimate Guide to Log Management.
What to Log and What Not to Log
- Log Only on Error or Unexpected Behavior: Avoid logging routine successful operations at high levels. Log success in lower levels like DEBUG or FINE.
- Log at the Proper Level: Use standard levels appropriately: ERROR (critical failures), WARN (unexpected but recoverable), INFO (significant state changes), DEBUG (detailed diagnostic data).
- Do Not Log Sensitive Data: Never log passwords, API keys, Personally Identifiable Information (PII), or payment card data.
- Avoid Logging Large User Content: Uploaded files or huge JSON payloads can dramatically increase log size and storage costs.
Structuring Your Logs
- Use Structured Logging Formats: Always prefer JSON. It allows for automatic parsing and querying without writing complex regex.
- Include Contextual Metadata: Every log line should include a timestamp, service name, environment, request ID, and user ID (if applicable).
- Use a Common Schema: Adhering to standards like Elastic Common Schema (ECS) ensures consistency across applications.
Performance and Volume Control
- Avoid Logging Inside Loops: Logging inside a loop that runs thousands of times will generate a massive volume of prints and crash your logging system.
- Suppress Repetitive Exceptions: For known, expected exceptions, log only the exception name or use rate limiting to avoid log flooding.
- Combine Multiple Logs: Instead of logging the start, progress, and end of an operation separately, combine them into a single structured log at the end.
- Be Mindful of Log Retention Costs: Each terabyte of logs can cost significant money to store and make searchable. Consider discarding DEBUG logs in production or moving them to cheap cold storage.
Modern Logging Frameworks
Use logging libraries that support structured logging out of the box, such as:
- For Python: Structlog, Python JSON Logger
- For JavaScript: Winston, Pino
- For Java: Logback, Log4j2 with JSON layout
- For .NET: Serilog
Conclusion
Writing high quality logs is an investment that pays dividends during debugging and incident response. By following these developer focused best practices, you ensure your logs are consistent, performant, and secure, reducing noise and highlighting what truly matters. Well structured logs make analysis easier. Learn how in Log Analysis Turning Data into Insights.
