# Effective Logging Strategies for Java Microservices

<div><strong>Source</strong>: <a href='https://www.tuanh.net/blog/java/effective-logging-strategies-for-java-microservices'>Effective Logging Strategies for Java Microservices</a></div><div class="line-post"> 
 <h2 class="title-post">1. Structured Logging for Enhanced Analysis</h2> 
</div>
<div class="line-post">
  Structured logging is a key principle for Java microservices as it enables logs to be machine-readable and queryable. Unlike unstructured logs that consist of raw text, structured logs format data in a standardized structure (e.g., JSON) which allows for better analysis and querying. 
</div>
<div class="images-post"> 
 <img width="80%" class="element_778652-image" src="https://resource.tuanh.net/article/image/ef8fbd69-6c82-4c14-83c6-e7c4708aa117.png" alt="Image"> 
</div>
<div class="line-post"> 
 <h3 class="sub1">1.1 Implementing Structured Logging in Java</h3> 
</div>
<div class="line-post">
  Java logging frameworks such as Logback and SLF4J support structured logging by allowing custom formats. Using JSON format is particularly effective, as JSON logs can be easily parsed and analyzed by logging tools. 
</div>
<pre class="code">&lt;configuration&gt;<br>    &lt;appender name="JSON_FILE" <span class="keyword-css">class</span>="ch.qos.logback.core.FileAppender"&gt;<br>        &lt;file&gt;logs/microservice-log.json&lt;/file&gt;<br>        &lt;encoder <span class="keyword-css">class</span>="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"&gt;<br>            &lt;providers&gt;<br>                &lt;timestamp&gt;<br>                    &lt;fieldName&gt;timestamp&lt;/fieldName&gt;<br>                    &lt;pattern&gt;yyyy-MM-dd HH:mm:ss.SSS&lt;/pattern&gt;<br>                &lt;/timestamp&gt;<br>                &lt;pattern&gt;<br>                    &lt;pattern&gt;%msg&lt;/pattern&gt;<br>                &lt;/pattern&gt;<br>                &lt;stackTrace /&gt;<br>            &lt;/providers&gt;<br>        &lt;/encoder&gt;<br>    &lt;/appender&gt;<br><br>    &lt;root level="INFO"&gt;<br>        &lt;appender-ref ref="JSON_FILE" /&gt;<br>    &lt;/root&gt;<br>&lt;/configuration&gt;</pre>
<div class="line-post">
  In this configuration, logs are saved in JSON format, capturing the timestamp, message, and stack trace if an error occurs. This structured format simplifies searching and filtering within a logging or monitoring system, such as Elasticsearch or Kibana. 
</div>
<div class="line-post"> 
 <h3 class="sub1">1.2 Adding Contextual Data to Logs</h3> 
</div>
<div class="line-post">
  Adding contextual data, like userId, orderId, or serviceName, to each log entry enables precise filtering and provides insights into user-specific or service-specific events. In SLF4J, contextual data can be set using Mapped Diagnostic Context (MDC). 
</div>
<pre class="code"><span class="keyword-css">import</span> org.slf4j.MDC;<br><br><span class="keyword-css">public</span> <span class="keyword-css">void</span> processOrder(String orderId, String userId) {<br>    MDC.put("userId", userId);<br>    MDC.put("orderId", orderId);<br><br>    logger.info("Processing order");<br><br>    MDC.clear();<br>}</pre>
<div class="line-post">
  By including this data, logs contain additional identifiers, making it easier to locate specific events in a distributed environment. 
</div>
<div class="line-post"> 
 <h2 class="title-post">2. Log Correlation Across Services</h2> 
</div>
<div class="line-post">
  In microservices, a single user request can pass through multiple services, making end-to-end traceability essential. Log correlation involves tracking a request as it flows across services, typically by using a unique identifier called a correlationId. 
</div>
<div class="line-post"> 
 <h3 class="sub1">2.1 Generating and Passing Correlation IDs</h3> 
</div>
<div class="line-post">
  A correlationId is a unique identifier generated at the beginning of a request and passed to all services involved. Using this ID, logs from multiple services can be correlated to reconstruct the entire request path. 
</div>
<div class="line-post">
  The following example demonstrates how to generate and pass a correlation ID across services in Java: 
</div>
<pre class="code"><span class="keyword-css">import</span> org.slf4j.MDC;<br><span class="keyword-css">import</span> java.util.UUID;<br><br><span class="keyword-css">public</span> <span class="keyword-css">void</span> handleRequest() {<br>    String correlationId = UUID.randomUUID().toString();<br>    MDC.put("correlationId", correlationId);<br><br>    logger.info("Starting process <span class="keyword-css">for</span> correlation ID {}", correlationId);<br><br>    // Make a call to another service, passing the correlation ID in headers<br>    // RestTemplate or HttpClient can be used <span class="keyword-css">for</span> <span class="keyword-css">this</span> purpose<br>    MDC.clear();<br>}</pre>
<div class="line-post">
  By attaching correlationId to each log, you create a traceable link across services, which is invaluable when diagnosing issues in complex workflows. 
</div>
<div class="line-post"> 
 <h3 class="sub1">2.2 Handling Correlation in REST Calls</h3> 
</div>
<div class="line-post">
  When making REST calls, ensure that the correlationId is passed along in the headers. This allows each microservice to log the same correlation ID, keeping logs synchronized across services. 
</div>
<pre class="code"><span class="keyword-css">public</span> ResponseEntity&lt;String&gt; callAnotherService(String correlationId) {<br>    HttpHeaders headers = <span class="keyword-css">new</span> HttpHeaders();<br>    headers.set("X-Correlation-ID", correlationId);<br><br>    HttpEntity&lt;String&gt; request = <span class="keyword-css">new</span> HttpEntity&lt;&gt;(headers);<br>    <span class="keyword-css">return</span> restTemplate.exchange("http://another-service/api", HttpMethod.GET, request, String.<span class="keyword-css">class</span>);<br>}</pre>
<div class="line-post">
  Here, the correlationId is included in the request headers, ensuring that all subsequent services can continue logging with the same ID. 
</div>
<div class="line-post"> 
 <h2 class="title-post">3. Centralized Log Aggregation and Analysis</h2> 
</div>
<div class="line-post">
  Collecting logs in a single, centralized location enables efficient analysis and monitoring. Log aggregation is a must for microservices, where logs from each service need to be accessible in a single interface for real-time analysis and troubleshooting. 
</div>
<div class="line-post"> 
 <h3 class="sub1">3.1 Setting Up ELK Stack for Centralized Logging</h3> 
</div>
<div class="line-post">
  The ELK Stack (Elasticsearch, Logstash, and Kibana) is a popular choice for aggregating and analyzing logs from Java microservices. With ELK, logs are collected and indexed in Elasticsearch, processed with Logstash, and visualized with Kibana. 
</div>
<div class="line-post">
  To aggregate logs in ELK, Logstash should be configured to collect logs from each microservice and forward them to Elasticsearch. This configuration file for Logstash shows how to receive logs from multiple sources: 
</div>
<pre class="code">input {<br>  file {<br>    path =&gt; "/path/to/microservice-logs/*.json"<br>    start_position =&gt; "beginning"<br>  }<br>}<br><br>output {<br>  elasticsearch {<br>    hosts =&gt; ["http://localhost:9200"]<br>    index =&gt; "microservices-logs-%{+YYYY.MM.dd}"<br>  }<br>}</pre>
<div class="line-post">
  This Logstash setup reads JSON-formatted logs, indexes them in Elasticsearch, and organizes them by date. Using Kibana, developers can visualize log data, search specific entries, and create dashboards for monitoring. 
</div>
<div class="line-post"> 
 <h3 class="sub1">3.2 Creating Alerts for Critical Log Events</h3> 
</div>
<div class="line-post">
  By setting up alerts, you can proactively monitor the health of your microservices. Many logging platforms, including Kibana and Datadog, offer alerting features that notify developers of potential issues, such as high error rates or unusual spikes in response times. 
</div>
<div class="line-post">
  Example: Setting up Alerts in Kibana 
</div>
<div class="line-post"> 
 <ul> 
  <li>In Kibana, navigate to the “Alerts and Actions” section.</li> 
  <li>Create a new alert with conditions, such as an increase in error logs (severity level ERROR).</li> 
  <li>Specify the threshold, such as a count of ERROR logs exceeding 10 in 5 minutes.</li> 
  <li>Define actions for the alert, like sending notifications via email or Slack.</li> 
 </ul> 
</div>
<div class="line-post">
  This setup ensures that critical issues in microservices don’t go unnoticed, enabling rapid response to maintain service availability. 
</div>
<div class="line-post"> 
 <h2 class="title-post">4. Conclusion</h2> 
</div>
<div class="line-post">
  Establishing a robust logging strategy for Java microservices requires thoughtful design and attention to details. Structured logging, correlation IDs, and centralized aggregation form the backbone of an effective approach, allowing developers to trace requests, debug issues, and maintain observability across distributed services. Implementing these practices ensures that logs provide actionable insights without impacting application performance. 
</div>
<div class="line-post">
  If you have questions on implementing logging strategies or have insights from your experience, feel free to comment below. Logging can be complex in distributed environments, and sharing approaches helps everyone build more resilient systems. 
</div><p><strong>Read more at </strong>: <a href='https://www.tuanh.net/blog/java/effective-logging-strategies-for-java-microservices'>Effective Logging Strategies for Java Microservices</a></p>
