Was ist MDC?
MDC ist ein Protokollierungstool in Java. Die zugrunde liegende Implementierung ist die Kapselung von ThreadLocal, um die Verfolgung und Speicherung von Aufruflinks auf Thread-Ebene in Form von kv zu implementieren
TraceId generieren
Generierungsregeln: Server-IP + ID-Generierungszeit + automatische Inkrementierungssequenz + aktuelle Prozessnummer
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.StringUtils;
public class TraceIdGenerator {
private static String IP_16 = "ffffffff";
private static AtomicInteger count = new AtomicInteger(1000);
public static String P_ID_CACHE = null;
static {
try {
String ipAddress = getInetAddress();
if (ipAddress != null) {
IP_16 = getIP_16(ipAddress);
}
} catch (Throwable e) {
// ignore
}
}
private static String getTraceId(String ip, long timestamp, int nextId) {
StringBuilder appender = new StringBuilder(30);
appender.append(ip).append(timestamp).append(nextId).append(getPID());
return appender.toString();
}
public static String generate() {
return getTraceId(IP_16, System.currentTimeMillis(), getNextId());
}
private static String getIP_16(String ip) {
String[] ips = ip.split("\\.");
StringBuilder sb = new StringBuilder();
for (String column : ips) {
String hex = Integer.toHexString(Integer.parseInt(column));
if (hex.length() == 1) {
sb.append('0').append(hex);
} else {
sb.append(hex);
}
}
return sb.toString();
}
private static int getNextId() {
for (; ; ) {
int current = count.get();
int next = (current > 9000) ? 1000 : current + 1;
if (count.compareAndSet(current, next)) {
return next;
}
}
}
public static String getInetAddress() {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
InetAddress address = null;
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
Enumeration<InetAddress> addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
address = addresses.nextElement();
if (!address.isLoopbackAddress() && address.getHostAddress().indexOf(":") == -1) {
return address.getHostAddress();
}
}
}
return null;
} catch (Throwable t) {
return null;
}
}
@SuppressWarnings("AbbreviationAsWordInName")
public static String getPID() {
// Check pid is cached.
if (P_ID_CACHE != null) {
return P_ID_CACHE;
}
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isBlank(processName)) {
return StringUtils.EMPTY;
}
String[] processSplitName = processName.split("@");
if (processSplitName.length == 0) {
return StringUtils.EMPTY;
}
String pid = processSplitName[0];
if (StringUtils.isBlank(pid)) {
return StringUtils.EMPTY;
}
P_ID_CACHE = pid;
return pid;
}
}
MDC-Paket
import com.google.common.collect.Sets;
import java.util.Optional;
import java.util.Set;
import org.slf4j.MDC;
@SuppressWarnings("AbbreviationAsWordInName")
public class MDCUtil {
String TRACE_ID = "TRACE_ID";
private static final Set<String> MDC_KEYs = Sets.newHashSet(TRACE_ID);
private MDCUtil() {}
public static void putTraceId() {
putTraceId(TraceIdGenerator.generate());
}
public static void putTraceId(String traceId) {
if (MDC.get(TRACE_ID) == null) {
MDC.put(TRACE_ID, traceId);
}
}
public static Optional<String> getTraceId() {
String traceId = MDC.get(TRACE_ID);
return traceId == null ? Optional.empty() : Optional.of(traceId);
}
public static void clear() {
MDC_KEYs.forEach(key -> MDC.remove(TRACE_ID));
}
}
globaler TraceId-Interceptor
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerInterceptor;
@RequiredArgsConstructor
@Service
@Slf4j
public class TraceIdInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
MDCUtil.putTraceId();
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
MDCUtil.clear();
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
Interceptor-Konfiguration
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class TraceIdConfig implements WebMvcConfigurer {
private final TraceIdInterceptor traceIdInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(traceIdInterceptor).addPathPatterns("/**");
}
}