At the end of November, we’ll be migrating the Sematext Logs backend from Elasticsearch to OpenSearch

Log Formatting: 8 Best Practices for Better Readability

May 28, 2024

Table of contents

Logs act as silent sentinels, recording every whisper of your application’s activity. They are invaluable chronicles illuminating system behavior, diagnosing issues, and providing crucial insights into your application’s health. 

However, the true power of logs lies not just in their existence, but in how they are formatted.

Log formatting is pivotal in transforming these raw data streams into actionable intelligence. It dictates how information is structured, categorized, and presented, ultimately determining the effectiveness of your logging efforts.

This blog post delves into the essential best practices for log formatting, guiding you toward maximizing the value extracted from your logs. 

What is a Log Format?

Log formatting refers to how information within log files is structured and organized. It dictates how each log entry is presented, including the data it contains, the order of that data, and the delimiters used to separate individual elements.

Imagine a log file as a news report. 

Unstructured logs resemble a jumbled collection of headlines and snippets, making it difficult to decipher the full story. 

Structured logs, on the other hand, are like well-organized articles with clear sections, titles, and timestamps, providing a much more comprehensible and actionable record of events.

Why should you care?

Prioritizing good log formatting allows you to unlock the true potential of your logs, transforming them from a collection of cryptic messages into a powerful tool for monitoring, troubleshooting, and optimizing your application performance.

While the benefits of good log formatting are undeniable, neglecting proper practices can incur significant costs for your development and operations teams. 

Here’s a glimpse into the potential consequences of bad logging:

Wasted Time in Troubleshooting

Unstructured or poorly formatted logs make it incredibly difficult to pinpoint the root cause of issues. Engineers spend countless hours sifting through irrelevant information, delaying resolution times and impacting productivity.

Delayed Problem Identification

Critical issues can remain undetected for extended periods due to the lack of clear and concise information within logs. This can lead to cascading failures, impacting the user experience and potentially causing financial losses.

Difficulty in Scaling

As your application grows, managing massive volumes of unstructured logs becomes a significant challenge. This can lead to storage bottlenecks, performance degradation, and increased infrastructure costs.

Compliance Challenges

Industries with strict data regulations often require specific log formats for audit purposes. Failing to comply with these regulations can result in hefty fines and reputational damage.

Limited Visibility into Application Health

Without proper log formatting, it becomes difficult to understand your application’s overall health and performance. This hinders proactive monitoring and optimization efforts.

By implementing effective log formatting practices, you can mitigate these costs and unlock the true potential of your logs. They become a valuable asset for proactive problem identification, efficient troubleshooting, and informed decision-making, ultimately leading to a smoother development and operational experience.

Types of log formats

The world of log formats can be categorized into three main types of log, each offering varying levels of structure and benefits:

Unstructured Logs

These are the most basic and least informative log formats. 

They typically consist of plain text messages, often with no specific order or delimiters separating individual elements.

2023-10-26 15:34:12 - Request received for /products/123

While simple to implement, unstructured logs are difficult to analyze and search. They offer limited insights and require significant manual effort to extract any meaningful information.

Semi-structured Logs

These logs represent a step towards better organization. 

They often utilize key-value pairs to associate specific data points with labels, providing some level of structure. Common formats include:

  • JSON (JavaScript Object Notation): A popular human-readable format that uses key-value pairs nested within objects and array
JSON
{
  "timestamp": "2023-10-26T15:34:12Z",
  "level": "INFO",
  "message": "Request received for product with ID 123",
  "user_id": "12345"
}
  • XML (Extensible Markup Language): A structured format using tags and attributes to define data elements.

While semi-structured logs offer better readability and searchability compared to unstructured logs, they still require parsing and interpretation to extract the full value of the data.

Structured Logs

Structured logs are the gold standard in log formatting. 

They follow a predefined schema, with each log entry containing specific fields in a consistent order. This enables efficient parsing and analysis by both humans and machines. Common structured formats include:

Syslog: A widely used standard format with defined message headers and data fields.

CEF (Common Event Format): A standardized format designed for security and event management systems. Using Common Event Format (CEF) with logging lets you standardize field names across different log messages, significantly enhancing the correlation between security logs

Here are two examples that show how CEF standardization enhances the correlation between security logs from different sources, both generating logs related to network traffic:

Firewall Log:

CEF:0|FirewallVendor|FirewallProduct|1.0|100|FirewallTraffic|3|src=192.168.1.100 dst=10.0.0.1 spt=443 dpt=80

IDS Log:

CEF:0|IDSVendor|IDSProduct|2.0|200|IDSAlert|5|src=192.168.1.100 dst=10.0.0.1 proto=TCP

Standardization:

  • src (source IP): Both logs use the src field to represent the source IP address.
  • dst (destination IP): Both logs use the dst field for the destination IP address.
  • spt (source port) and dpt (destination port): While the IDS log doesn’t include ports if it did, it would use these fields.

Correlation:

Because the source and destination IP addresses are consistently labeled in both logs, an SIEM system can easily correlate these events, identifying that traffic from 192.168.1.100 to 10.0.0.1 passed through the firewall and triggered an alert on the IDS. This correlation might indicate a suspicious pattern or a security incident.

12 best practices for log formatting 

1. Structure JSON logs

Structured JSON logging is widely considered the gold standard in log formatting due to its numerous advantages.

It allows efficient parsing and analysis by logging tools, making it easier to identify trends and troubleshoot issues. This structure also scales well with large datasets and accommodates various data types, providing flexibility for capturing diverse information. 

Furthermore, JSON logs streamline the creation of charts, dashboards, and alerts based on specific data points, enabling real-time application monitoring and faster incident response.

Tips for implementing structured JSON as a log format: 

  • Define a Consistent Schema – When creating a log, be sure to define a consistent schema and include all relevant metadata fields. This ensures all logs follow the same format, facilitating easier parsing and analysis.
  • Utilize Meaningful Keys – Choose descriptive and informative keys for your JSON data points. This makes understanding the content of your logs much more intuitive.
  • Include Relevant Metadata – Enrich your logs with valuable metadata like timestamps, log levels, source information, and contextual fields relevant to your application.
  • Standardize Log Levels – Adhere to a standardized set of log levels (e.g., DEBUG, INFO, WARN, ERROR) to categorize the severity of events within your logs.
  • Leverage Logging Libraries – Many languages provide logging libraries with built-in support for structured JSON, ISO 8601 timestamps, contextual metadata, and more to simplify the implementation of the proper log.format. Utilize a log formatter library to simplify the process of generating JSON log entries.
JSON
{
  "timestamp": "2023-10-26T15:34:12Z",
  "level": "INFO",
  "message": "Request received for product with ID 123",
  "user_id": "12345",
  "source": "web_server",
  "http_method": "GET",
  "response_time": 250
}

2. Use Log Levels

Log levels play a crucial role in categorizing the severity of events within your logs. While logging frameworks often represent these levels internally with integers, for clarity and consistency, it’s highly recommended to always emit log levels as strings.

Log levels improve log management in two key ways:

  1. Clarity: They use terms like “DEBUG” and “ERROR” which are clear to humans and computers alike, making logs easier to read and understand.
  2. Analysis Efficiency: Log analysis tools leverage these levels to filter, group, and identify anomalies within the data, streamlining the troubleshooting process by recognizing log patterns.
{"level": "INFO", "time": "2023-10-26T15:34:12Z", "message": "Request received for product with ID 123"}

3. Record timestamps with ISO 8601

Ensuring consistent and accurate timestamps within your logs is crucial for effective log analysis and troubleshooting. The ISO 8601 format is the gold standard for timestamp representation, offering numerous benefits:

  • Universality: ISO 8601 is recognized internationally, eliminating confusion and ensuring clear interpretation of timestamps across different systems and time zones.
  • Machine-Readability: The structured format makes timestamps readily parsable by log analysis tools, facilitating efficient data sorting, filtering, and aggregation.
  • Unambiguity: ISO 8601 removes ambiguity by specifying separators for date and time components, avoiding potential misinterpretations.

The basic format of an ISO 8601 timestamp follows this structure:

YYYY-MM-DDTHH:mm:ssZ

Here’s a breakdown of the components:

  • YYYY: Year with four digits (e.g., 2024)
  • MM: Month with two digits, zero-padded (e.g., 05 for May)
  • DD: Day of the month with two digits, zero-padded (e.g., 07)
  • T: Separator between date and time (optional)
  • HH: Hour in 24-hour format with two digits, zero-padded (e.g., 13)
  • mm: Minutes with two digits, zero-padded (e.g., 37)
  • ss: Seconds with two digits, zero-padded (e.g., 42)
  • Z: Designates Coordinated Universal Time (UTC)

Optional Components:

  • Timezone Offset: You can include the timezone offset after the “Z” character using the following format:
    • Positive offset for time zones east of UTC: +HH:mm (e.g., +02:00 for Central European Time)
    • Negative offset for time zones west of UTC: -HH:mm (e.g., -07:00 for Pacific Standard Time)
  • Milliseconds: Milliseconds can be added after the seconds, separated by a decimal point (e.g., 2023-10-26T13:37:42.123Z).

Examples of ISO 8601 Timestamps

  • 2023-10-26T13:37:42Z (Current time in UTC)
  • 2023-05-07T09:15:00-07:00 (May 7th, 2023 at 9:15 AM Pacific Standard Time)
  • 2024-12-31T23:59:59.999Z (Last millisecond of December 31st, 2024, in UTC)

4. Include the Build Version or Commit Hash in Your Logs

Including the Build Version or Commit Hash in logs significantly aids troubleshooting. 

It allows you to trace log entries back to specific code versions, pinpointing potential problem areas. This information also improves issue reproducibility during debugging and simplifies rollback processes by providing clear version control awareness.

Implementation Strategies

There are several ways to incorporate build version or commit hash information into your logs:

  • Environment Variables: You can set environment variables during the build process to store the build version or commit hash. Your logging framework can then access these variables and include them within log messages.
  • Command-Line Arguments: Pass the build version or commit hash as a command-line argument to your application. This information can then be retrieved and included in the logs.
  • Custom Logging Library Functionality: Many logging libraries offer built-in functions for automatically capturing version information or integrating with version control systems. Refer to your specific logging library’s documentation for available features.

Here’s an example of how you might include the commit hash in a JSON log message:

JSON
{
  "level": "INFO",
  "time": "2023-10-26T15:34:12Z",
  "message": "Request received for product with ID 123",
  "commit_hash": "1a2b3c4d5e6f7890"
}

5. Include detailed log source information

Including detailed log source information pinpoints the exact component generating the message, saving time during issue identification.  Furthermore, source data provides context for complex systems and allows for focused analysis through filtering and aggregation based on the origin of the logs.

There are several ways to capture detailed log source information:

  • Hostname and Application Name: Include the hostname of the machine where the log message originated and the name of the application generating the logs.
  • Class and Method Names: For logs within your application code, capture the class name and method name where the log message is generated. This provides a precise location within your codebase.
  • Thread ID: In multithreaded environments, including the thread ID can help identify which thread generated the log message, aiding in debugging concurrency issues.
  • Custom Context Information: Include additional context-specific data relevant to your application or system. This could be user IDs, session IDs, or other relevant identifiers that further pinpoint the source of the log message.

Here’s an example of a JSON log message with detailed source information:

JSON
{
  "level": "WARN",
  "time": "2023-10-26T15:34:12Z",
  "message": "Failed to connect to database",
  "source": {
    "host": "server1.example.com",
    "application": "inventory_service",
    "class": "DatabaseManager",
    "method": "connect"
  }
}

6. Ensure Stack Traces are Included in Error Logs

Stack traces are crucial for error diagnosis as they identify the exact location of the error in the code, allowing developers to fix the root cause quickly. 

Additionally, stack traces offer valuable context for debugging by showing the sequence of events leading up to the error, and can even aid in reproducing the issue for further analysis.

How Stack Traces Help

Imagine an error message stating Failed to process a request. While informative, it doesn’t reveal the specific line of code causing the failure. However, by including the stack trace:

java.lang.NullPointerException: Attempt to invoke a virtual method on a null object reference
  at com.example.app.OrderService.processOrder(OrderService.java:42)
  at com.example.app.OrderController.handleOrderRequest(OrderController.java:23)
  at ... (other method calls in the call stack)

The stack trace exposes the issue as a NullPointerException occurring on line 42 of the OrderService.java file. This detailed information empowers developers to pinpoint the exact cause and location of the error.

Remember: While including stack traces is crucial for error logs, it’s generally recommended to avoid excessive logging of stack traces for informational or debug messages. This can clutter your logs and impact performance and logging costs.

7. Use Standardized Field Names 

Logs may be flowing into your application from different sources, causing similar information to be sent under different field names. 

Standardizing these similar values under the same field names improves searchability and provides correlation capabilities. By using standards for field names, everyone can understand the meaning of each field within the logs.

Defining Your Contextual Fields

  • Identify Common Fields: Identify the common values included in your logs from different sources. This might include user IDs, session IDs, request URLs, timestamps, and response codes.
  • Establish Naming Conventions: Define clear and consistent naming conventions for your fields. Use descriptive names that accurately reflect the data being captured. Avoid abbreviations or acronyms that might be unclear to others.
  • Document Your Standards: Maintain a centralized document outlining your logging standards, including the defined contextual fields and their meanings. This ensures everyone is on the same page when interpreting and analyzing logs.

8. Consider Log Sampling for High-Volume Environments

In large-scale, high-volume environments, processing and storing all log data can become a significant burden on your infrastructure and resources and increase costs. Log sampling offers a practical approach to managing log volume while still retaining valuable insights.

What is Log Sampling?

Log sampling involves capturing and storing only a subset of your log data, based on predetermined criteria. It’s a trade-off between capturing every single event and maintaining manageable log sizes.

Log Sampling benefits

Log sampling offers significant advantages for managing large datasets. It reduces storage costs by keeping only a representative subset of logs. Moreover, processing efficiency improves as smaller datasets require fewer resources for analysis. Strategic sampling allows you to focus on critical events like errors, minimizing the storage of less important informational messages.

Implementation Strategies:

There are several ways to implement log sampling:

  1. Random Sampling: Capture a random percentage of all log messages. This provides a general overview of system activity but might miss some specific events.
  2. Rate-Based Sampling: Capture a specific number of log messages per unit of time (e.g., per second). This ensures a steady stream of logs for analysis.
  3. Reservoir Sampling: This technique guarantees capturing at least a minimum number of important events, even with low sampling rates.

Is Log Sampling Right for You?

Consider these factors before implementing log sampling:

  • Log Volume: If your log volume is overwhelming, sampling can offer significant benefits.
  • Tolerance for Missed Events: Can you tolerate potentially missing some log data in exchange for improved efficiency?
  • Monitoring and Alerting: Ensure your monitoring and alerting systems are robust enough to identify critical events even with sampling in place.

Remember: Log sampling can be a valuable tool in high-volume environments, but it’s crucial to weigh the trade-offs carefully and implement it strategically to maintain adequate visibility into your system’s health.

Final thoughts 

Well-formatted logs are the cornerstone of effective application monitoring and troubleshooting. 

After ensuring your logs are well-structured and formatted, the natural progression is to consolidate them using a log management platform. Sematext Logs offers a centralized solution where you can seamlessly filter and visualize your log data, while also configuring alert rules to stay informed about critical events or anomalies that require immediate attention.

For further reading on log management, read our latest article.

Sounds interesting? Try Sematext Logs for free to see how easy log analytics can be.

Java Logging Basics: Concepts, Tools, and Best Practices

Imagine you're a detective trying to solve a crime, but...

Best Web Transaction Monitoring Tools in 2024

Websites are no longer static pages.  They’re dynamic, transaction-heavy ecosystems...

17 Linux Log Files You Must Be Monitoring

Imagine waking up to a critical system failure that has...