In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article is about how to use SpringBoot and LogBack to achieve a simple log call link tracking function, the editor feels very practical, so share with you to learn, I hope you can get something after reading this article, say no more, follow the editor to have a look.
Preface
In the traditional system, if the log output can be provided, it can basically meet the demand. However, once the system is divided into two or more systems, coupled with load balancing, the calling link becomes more complex.
Especially in the direction of further evolution to micro-services, if there is no reasonable log planning, link tracking, then troubleshooting logs will become extremely difficult.
For example, systems A, B, C, the call link is A-> B-> C, if each set of services is double active, then the call path has a cubic possibility of 2. If there are more systems and more services, the calling links will grow exponentially.
Therefore, whether it is a few simple internal service calls or complex micro-service systems, we need a mechanism to achieve log link tracking. Let the log output of your system have formal beauty and harmonious rhythm like poetry.
Log tracking actually has a lot of off-the-shelf frameworks, such as Sleuth, Zipkin and other components. But that's not what we're talking about.
Integration of Logback in Spring Boot
Spring Boot itself has built-in logging capabilities, and here the logback logging framework is used and the output is formatted. Let's take a look at SpringBoot's built-in integration with Logback. The dependencies are as follows. When the project introduces:
Org.springframework.boot spring-boot-starter-web
Spring-boot-starter-web indirectly introduces:
Org.springframework.boot spring-boot-starter
Spring-boot-starter also introduces logging's starter:
Org.springframework.boot spring-boot-starter-logging
You really introduced the required logback package in logging:
Ch.qos.logback logback-classic org.apache.logging.log4j log4j-to-slf4j org.slf4j jul-to-slf4j
Therefore, when we use it, we just need to put the logback-spring.xml configuration file in the resources directory. Theoretically, it is also supported to name the configuration file logback.xml, but the name recommended on the official website of Spring Boot is logback-spring.xml.
Then, configure the log output in logback-spring.xml. Instead of posting all the codes here, only the relevant log output format is posted. Take the console output as an example:
In the expression of the value attribute, we added a custom variable value requestId, which is shown in the form of "[% X {requestId}]".
This requestId is the only ID we use to track the log. If a request uses the same requestId from beginning to end, the entire request link can be concatenated. If the system also carries out unified collection based on log collection tools such as EKL, it will be more convenient to view the call link of the entire log.
So how did this requestId variable come from and where is it stored? To understand this, we first need to take a look at the MDC capabilities provided by the logging framework.
What is MDC?
MDC (Mapped Diagnostic Contexts) is a thread-safe container for storing diagnostic logs. MDC is a utility class provided by slf4j to adapt to other specific log implementation packages. Currently, only logback and log4j support this feature.
MDC is thread-independent and thread-safe, and usually both HTTP and RPC requests are completed in separate threads, which fits well with the mechanism of MDC.
When using the MDC function, we mainly use the put method, which indirectly calls the put method of the MDCAdapter interface.
Take a look at the code in BasicMDCAdapter, one of the implementation classes of interface MDCAdapter:
Public class BasicMDCAdapter implements MDCAdapter {private InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal () {@ Override protected Map childValue (Map parentValue) {if (parentValue = = null) {return null;} return new HashMap (parentValue);}} Public void put (String key, String val) {if (key = = null) {throw new IllegalArgumentException ("key cannot be null");} Map map = inheritableThreadLocal.get (); if (map = = null) {map = new HashMap (); inheritableThreadLocal.set (map);} map.put (key, val) } / /...}
You can see from the source code that an instance of InheritableThreadLocal is held internally, in which context data is saved through HashMap.
In addition, MDC provides several core interfaces, such as put/get/clear, for manipulating data stored in ThreadLocal. In logback.xml, you can get the data stored in MDC by declaring "% X {requestId}" in layout and print this information.
Based on these characteristics of MDC, it is often used for log link tracking, dynamic configuration of user-defined information (such as requestId, sessionId, etc.) and other scenarios.
Practical use
Having learned some basic principles above, let's take a look at how to achieve log tracking based on the MDC function of the logging framework.
Tool class preparation
First of all, define some tool classes, which is strongly recommended that you implement some operations in the form of tool classes, which is part of writing elegant code and avoiding the need to change every place when you make later changes.
The generation class of TraceID (we define the parameter as requestId) is generated by UUID here, of course, it can be generated in other ways according to your scene and needs.
Public class TraceIdUtils {/ * generate traceId * * @ return TraceId based on UUID * / public static String getTraceId () {return UUID.randomUUID () .toString () .replace ("-", ");}}
The tool class TraceIdContext for manipulating Context content:
Public class TraceIdContext {public static final String TRACE_ID_KEY = "requestId"; public static void setTraceId (String traceId) {if (StringLocalUtil.isNotEmpty (traceId)) {MDC.put (TRACE_ID_KEY, traceId);}} public static String getTraceId () {String traceId = MDC.get (TRACE_ID_KEY); return traceId = = null? ": traceId } public static void removeTraceId () {MDC.remove (TRACE_ID_KEY);} public static void clearTraceId () {MDC.clear ();}}
Through the tool class, it is convenient for all services to be used uniformly, such as requestId can be uniformly defined to avoid being different from place to place. Not only the set method is provided here, but also methods for removal and cleanup are provided.
Note the use of the MDC.clear () method. It doesn't matter if all threads are created through the new Thread method, and after the thread dies, so does the stored data. However, if the thread pool is used, the thread can be reused. If the MDC content of the previous thread is not cleared, and the thread is obtained from the thread pool again, the previous data (dirty data) will be taken out, resulting in some unexpected errors, so the current thread must be cleared after the end of the thread.
Filter intercept
Since we are going to trace the log link, the most intuitive idea is to generate a request ID at the source of the access and pass it on until the request is complete. Here, take Http as an example, intercept requests through Filter, and store and transfer data through Http's Header. When it comes to inter-system calls, the caller sets the requestId to Header, and the callee can take it from the Header.
Definition of Filter:
Public class TraceIdRequestLoggingFilter extends AbstractRequestLoggingFilter {@ Override protected void beforeRequest (HttpServletRequest request, String message) {String requestId = request.getHeader (TraceIdContext.TRACE_ID_KEY); if (StringLocalUtil.isNotEmpty (requestId)) {TraceIdContext.setTraceId (requestId);} else {TraceIdContext.setTraceId (TraceIdUtils.getTraceId ()) } @ Override protected void afterRequest (HttpServletRequest request, String message) {TraceIdContext.removeTraceId ();}}
In the beforeRequest method, get the requestId from the Header, if not, it is regarded as the "source", generate a requestId, set it to the MDC. When this request is completed, the set requestId is removed to prevent the thread pool problem mentioned above. Each service in the system can be implemented in the above way, and the whole request link is strung together.
Of course, the Filter defined above needs to be initialized, and the instantiation method in Spring Boot is as follows:
@ Configuration public class TraceIdConfig {@ Bean public TraceIdRequestLoggingFilter traceIdRequestLoggingFilter () {return new TraceIdRequestLoggingFilter ();}}
For ordinary system calls, the above methods can basically be satisfied, and can be extended on this basis according to their own needs in practice. Filter is used here, and it can also be implemented through interceptors, Spring's AOP, and so on.
Feign in Micro Services
If your system is based on the Feign component in Spring Cloud, you can add requestId by implementing the RequestInterceptor interceptor. The specific implementation is as follows:
@ Configuration public class FeignConfig implements RequestInterceptor {@ Override public void apply (RequestTemplate requestTemplate) {requestTemplate.header (TraceIdContext.TRACE_ID_KEY, TraceIdContext.getTraceId ();}}
Result verification
When the above operation is completed, a request is made to a Controller, and the following log is printed:
2021-04-13 10 INFO 580 cloud-sevice-consumer-demo [http-nio-7199-exec-1] INFO [ef76526ca96242bc8e646cdef3ab31e6] c.b.demo.controller.CityController-getCity 2021-04-13 10 14 14 14 13 10 14 13 14 14 14 15 31 185 cloud-sevice-consumer-demo [http-nio-7199-exec-1] WARN [ef76526ca96242bc8e646cdef3ab31e6] o.s.c.o.l.FeignBlockingLoadBalancerClient-
You can see that requestID has been successfully added. When we troubleshoot the log, we only need to find the requested key information, and then the entire log can be concatenated according to the requestId value in the critical information log.
Finally, let's review the whole process of log tracing: when the request arrives at the first server, the service checks whether the requestId exists, and if not, it creates one and puts it into the MDC; when the service invokes other services, it passes the requestId through Header; and the logback of each service configures the output of the requestId. In order to achieve the effect of concatenating the logs from beginning to end.
In this article, if you only learn about log tracking, it's a loss, because it also involves SpringBoot's integration of logback, the underlying implementation of MDC and pits, the use of filters, Feign's request interceptor, and so on. If you are interested, each can diverge and learn more knowledge points.
The above is how to use SpringBoot and LogBack to achieve a simple log call link tracking function, the editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.