{"id":18176,"date":"2023-02-23T13:56:52","date_gmt":"2023-02-23T19:56:52","guid":{"rendered":"https:\/\/threecloud.wpengine.com\/?p=18176"},"modified":"2023-02-23T13:56:52","modified_gmt":"2023-02-23T19:56:52","slug":"distributed-spring-boot-logger-using-azure-application-insights","status":"publish","type":"post","link":"https:\/\/3cloudsolutions.com\/resources\/distributed-spring-boot-logger-using-azure-application-insights\/","title":{"rendered":"Distributed Spring Boot Logger using Azure Application Insights"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>In a distributed system, logging is critical for tracking the flow of requests and responses between microservices. In this article, we will describe a distributed logger built using Spring Boot and Microsoft Application Insights. This logger provides extensible logging, correlation IDs, and flexible logging formats.<\/p>\n<h2>Library Setup<\/h2>\n<p>In this article, we&#8217;ll be setting up a logger that streamlines the logging process, making it easy to track the flow of requests and responses between micro-services. Our logger uses a correlation ID to keep track of transactions and ensure that logs are properly formatted and organized. The logger is composed of three key components: the <em>logUtils<\/em> class, which creates a new log appender; the <em>HeaderRequestMapper<\/em> class, which provides utility methods for working with HTTP requests; and the <em>CorrelationIdFilterBase<\/em> class, which can be extended in your application to add correlation IDs to incoming requests.<\/p>\n<h2>Azure Dependencies<\/h2>\n<p>Maven:<\/p>\n<p><code>&lt;dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;groupId&gt;com.azure.spring&lt;\/groupId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;artifactId&gt;spring-cloud-azure-starter&lt;\/artifactId&gt;<\/code><\/p>\n<p><code>&lt;\/dependency&gt;<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>&lt;properties&gt;<\/code><\/p>\n<p><code>\u00a0 &lt;version.spring.cloud&gt;2021.0.3&lt;\/version.spring.cloud&gt;<\/code><\/p>\n<p><code>\u00a0 &lt;version.spring.cloud.azure&gt;4.3.0&lt;\/version.spring.cloud.azure&gt;<\/code><\/p>\n<p><code>&lt;\/properties&gt;<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>&lt;dependencyManagement&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;dependencies&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;artifactId&gt;spring-cloud-dependencies&lt;\/artifactId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;version&gt;${version.spring.cloud}&lt;\/version&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;type&gt;pom&lt;\/type&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;scope&gt;import&lt;\/scope&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;groupId&gt;com.azure.spring&lt;\/groupId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;artifactId&gt;spring-cloud-azure-dependencies&lt;\/artifactId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;version&gt;${version.spring.cloud.azure}&lt;\/version&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;type&gt;pom&lt;\/type&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;scope&gt;import&lt;\/scope&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;\/dependencies&gt;<\/code><\/p>\n<p><code>&lt;\/dependencyManagement&gt;<\/code><\/p>\n<p>&nbsp;<\/p>\n<p>Gradle:<\/p>\n<p><code>ext {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 set('springBootCloudVersion', \"2021.0.4\")<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 set('springBootStarterVersion', \"2.7.2\")<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>dependencies {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 implementation \"org.springframework.cloud:spring-cloud-starter:${springBootCloudVersion}\"<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 implementation \"org.springframework.boot:spring-boot-starter-web:${springBootStarterVersion}\"<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>CorrelationId Filter<\/h2>\n<p class=\"FirstParagraph\">The <b><i>CorrelationIdFilterBase.java<\/i><\/b> class is a custom request filter that can be extended in your application to add Correlation IDs to requests.<\/p>\n<p><code>public class CorrelationIdFilterBase extends OncePerRequestFilter {<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>\u00a0\u00a0\u00a0 public static final String CORRELATION_ID_HEADER_NAME = \"x-correlation-id\";<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 public static final String CORRELATION_ID_MDC_KEY = \"CorrelationId\";<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>\u00a0\u00a0\u00a0 @Override<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 throws ServletException, IOException {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 List&lt;String&gt; headers = Collections.list(request.getHeaderNames());<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (headers.contains(CORRELATION_ID_HEADER_NAME)) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MDC.put(CORRELATION_ID_MDC_KEY, request.getHeader(CORRELATION_ID_HEADER_NAME));\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 filterChain.doFilter(request, response);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } else {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String id = UUID.randomUUID().toString();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MDC.put(CORRELATION_ID_MDC_KEY, id);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HeaderRequestMapper headerRequestMapper = new HeaderRequestMapper(request);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 headerRequestMapper.addHeader(CORRELATION_ID_HEADER_NAME, id);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.addHeader(CORRELATION_ID_HEADER_NAME, id);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 filterChain.doFilter(headerRequestMapper, response);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Request Header Wrapper<\/h2>\n<p class=\"FirstParagraph\">The <b><i>HeaderRequestMapper.java<\/i><\/b> class provides convenient methods for fetching and setting Http Requests.<\/p>\n<p><code>public class HeaderRequestMapper extends HttpServletRequestWrapper {<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public HeaderRequestMapper(HttpServletRequest request) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 super(request);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 private Map&lt;String, String&gt; headerMap = new HashMap&lt;String, String&gt;();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public void addHeader(String name, String value) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 headerMap.put(name, value);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Override<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public String getHeader(String name) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 String headerValue = super.getHeader(name);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (headerMap.containsKey(name)) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 headerValue = headerMap.get(name);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return headerValue;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Override<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public Enumeration&lt;String&gt; getHeaderNames() {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 List&lt;String&gt; names = Collections.list(super.getHeaderNames());<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 for (String name : headerMap.keySet()) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 names.add(name);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return Collections.enumeration(names);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 @Override<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public Enumeration&lt;String&gt; getHeaders(String name) {\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 List&lt;String&gt; values = Collections.list(super.getHeaders(name));<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (headerMap.containsKey(name)) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 values.add(headerMap.get(name));<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return Collections.enumeration(values);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Logging Utility<\/h2>\n<p class=\"FirstParagraph\">The <b><i>LogUtils.java<\/i><\/b> class is a utility class that will create a new Log Appender.<\/p>\n<p><code>public class LogUtils {<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public static Logger getConsoleLogger(String loggerName, Level level) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ add the pid (process id) to the MDC context<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MDC.put(\"pid\", bean.getName().split(\"@\")[0]);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 PatternLayoutEncoder ple = configurePatterLayout(context);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ConsoleAppender&lt;ILoggingEvent&gt; consoleAppender = configureConsoleAppender(context, ple);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Logger logger = configureLogger(consoleAppender, level, loggerName);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return logger;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 private static Logger configureLogger(ConsoleAppender&lt;ILoggingEvent&gt; consoleAppender, Level level, String loggerName) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Logger logger = (Logger) LoggerFactory.getLogger(loggerName);\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 logger.addAppender(consoleAppender);\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 logger.setLevel(level);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 logger.setAdditive(false);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return logger;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 private static ConsoleAppender&lt;ILoggingEvent&gt; configureConsoleAppender(LoggerContext context, PatternLayoutEncoder ple) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ConsoleAppender&lt;ILoggingEvent&gt; consoleAppender = new ConsoleAppender&lt;&gt;();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 consoleAppender.setEncoder(ple);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 consoleAppender.setWithJansi(true);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 consoleAppender.setContext(context);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 consoleAppender.start();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return consoleAppender;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 private static PatternLayoutEncoder configurePatterLayout(LoggerContext context) {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 PatternLayoutEncoder ple = new PatternLayoutEncoder();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ple.setPattern(\"%-3d{dd-MM-yyyy HH:mm:ss.SSS} %highlight(%level) %magenta(%mdc{pid}) --- [%mdc{CorrelationId}] %cyan(%C{40}).%M : %msg%n\");<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ple.setContext(context);<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ple.start();<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return ple;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Library Usage<\/h2>\n<p class=\"FirstParagraph\">To use the Console Appender logger library we just created in your Spring Boot project, you first need to add it as a dependency. This can be done with Maven or Gradle.<\/p>\n<p>Maven:<\/p>\n<p><code>&lt;dependency&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;groupId&gt;com.examplecompany.azure&lt;\/groupId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;artifactId&gt;logback-console-appender&lt;\/artifactId&gt;<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 &lt;version&gt;current version&lt;\/version&gt;<\/code><\/p>\n<p><code>&lt;\/dependency&gt;<\/code><\/p>\n<p>&nbsp;<\/p>\n<p>Gradle:<\/p>\n<p><code>implementation 'com.examplecompany.azure:logback-console-appender:current version';<\/code><\/p>\n<p>&nbsp;<\/p>\n<p class=\"FirstParagraph\">Next, create a new logger in the class where you want to use the Console Appender logger:<\/p>\n<p><code>private static final Logger logger = LogUtils.getConsoleLogger(MyAppName.class.getName(), Level.ALL);<\/code><\/p>\n<p>&nbsp;<\/p>\n<p class=\"FirstParagraph\">To log messages, use the following code:<\/p>\n<p><code>logger.info(\"My log message\");<\/code><\/p>\n<p>&nbsp;<\/p>\n<p>To use the correlation ID filter, extend the <em>CorrelationIdFilterBase<\/em> class and add it to the filter chain.<\/p>\n<p><code>@Component<\/code><\/p>\n<p><code>@Order(1)<\/code><\/p>\n<p><code>public class CorrelationIdFilter extends CorrelationIdFilterBase {<\/code><\/p>\n<p><code>\u00a0 @Override\u00a0\u00a0 public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 super.doFilterInternal(request, response, filterChain);<\/code><\/p>\n<p><code>\u00a0 }<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<p class=\"FirstParagraph\">If your service makes calls to other APIs, you can maintain the correlation ID header by adding the following code:<\/p>\n<p><code>WebClient webClient = new WebClient();<\/code><\/p>\n<p><code>return webClient<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .put()<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .uri(uriPath)<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .attributes(oauth2AuthorizedClient(client))<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .header(CorrelationIdFilterBase.CORRELATION_ID_HEADER_NAME, MDC.get(CorrelationIdFilterBase.CORRELATION_ID_MDC_KEY))<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .header(HttpHeaders.CONTENT_TYPE, \"application\/json\")<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .bodyValue(resourceDTO.getJson())<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .retrieve()<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .bodyToMono(String.class);<\/code><\/p>\n<p>&nbsp;<\/p>\n<h2>Integration with Microsoft Application Insights<\/h2>\n<p>&nbsp;<\/p>\n<p>The logging library described in the article can be integrated with Application Insights, allowing you to use the tool to monitor the logs produced by the library. This can help you identify issues and trends in the logs and use that information to improve the performance and reliability of your applications.<\/p>\n<p>&nbsp;<\/p>\n<p>Additionally, Application Insights supports a variety of ways to visualize and analyze the data, including built-in dashboards, custom charts and graphs, and integration with other tools such as Power BI. By leveraging the capabilities of Application Insights, you can gain deeper visibility into your applications and services, allowing you to make informed decisions about how to optimize their performance.<\/p>\n<h2>Application Insights Integration<\/h2>\n<p>&nbsp;<\/p>\n<p>In your projects Application class add the following line to your main() method:<\/p>\n<p><code>ApplicationInsights.attach();<\/code><\/p>\n<p>&nbsp;<\/p>\n<p>Create a configuration json file in your \/resources folder named <strong><em>applicationinsights.json<\/em><\/strong><\/p>\n<p>Add the following to the <strong><em>applicationinsights.json<\/em><\/strong> file adding the <strong>InstrumentationKey<\/strong> value of your Application Insights instance:<\/p>\n<p><code>{<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 \"connectionString\": \"InstrumentationKey=[InstrumentationKey value]\"<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<p class=\"FirstParagraph\">You can change defaults of what level to log by adding it to the json file, the default level is &#8220;INFO&#8221;. For example, to log all debug messages to Application Insights, change the json to be:<\/p>\n<p><code>{<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 \"connectionString\": \"InstrumentationKey=[InstrumentationKey value]\",<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 \"instrumentation\": {<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"logging\": {<\/code><\/p>\n<p><code>\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"level\": \"DEBUG\"<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>\u00a0\u00a0\u00a0 }<\/code><\/p>\n<p><code>}<\/code><\/p>\n<p>&nbsp;<\/p>\n<p>Additional configuration options using the json file can be found <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/azure-monitor\/app\/java-in-process-agent#configuration-options\">here<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>In conclusion, the distributed logger using Spring Boot and Microsoft&#8217;s Application Insights is a flexible and extensible logging library. With the ability to log messages to the console, maintain correlation IDs, and log to Application Insights, it provides a comprehensive solution for logging in a distributed environment. Additionally, by extending the <em>CorrelationIdFilterBase<\/em> class, you can easily customize the logging format to meet your specific needs.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In a distributed system, logging is critical for tracking the flow of requests and&mldr;<\/p>\n","protected":false},"author":68,"featured_media":18194,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[290,278],"tags":[284,362],"class_list":["post-18176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud-platform","category-managed-services","tag-azure","tag-spring-boot-logger","topics-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/18176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/users\/68"}],"replies":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/comments?post=18176"}],"version-history":[{"count":0,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/18176\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media\/18194"}],"wp:attachment":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media?parent=18176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/categories?post=18176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/tags?post=18176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}