From 2aeda44a6ef0e1e053f8b8149d798e680cf9328a Mon Sep 17 00:00:00 2001 From: Ravichandran M Date: Thu, 23 Jul 2020 23:13:51 +0530 Subject: [PATCH 1/5] initial commit --- modules/logging/pom.xml | 6 +- .../common/api/DiagnosticContextFacade.java | 32 +++ .../logging/common/api/LoggingConstants.java | 20 ++ .../impl/DiagnosticContextFacadeImpl.java | 39 +++ .../common/impl/TraceContextFilter.java | 223 ++++++++++++++++++ .../common/impl/TraceHeadersInjector.java | 23 ++ 6 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java create mode 100644 modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java diff --git a/modules/logging/pom.xml b/modules/logging/pom.xml index df0861a6..11757ebb 100644 --- a/modules/logging/pom.xml +++ b/modules/logging/pom.xml @@ -22,7 +22,7 @@ net.logstash.logback logstash-logback-encoder - + org.slf4j jcl-over-slf4j @@ -59,6 +59,10 @@ org.springframework.boot spring-boot-starter + + org.springframework.cloud + spring-cloud-starter-sleuth + \ No newline at end of file diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java index c3aa316f..cc52e53a 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java @@ -30,4 +30,36 @@ public interface DiagnosticContextFacade { */ void removeCorrelationId(); + /** + * + */ + void removeTraceId(); + + /** + * + */ + void removeSpanId(); + + /** + * + * @return + */ + String getTraceId(); + + /** + * + * @return + */ + String getSpanId(); + + /** + * @param spanId + */ + void setSpanId(String spanId); + + /** + * @param traceId + */ + void setTraceId(String traceId); + } diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/LoggingConstants.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/LoggingConstants.java index 660e1b8e..88aede23 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/LoggingConstants.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/LoggingConstants.java @@ -15,6 +15,26 @@ public final class LoggingConstants { */ public static final String CORRELATION_ID = "correlationId"; + /** + * SPAN ID + */ + public static final String SPAN_ID = "spanId"; + + /** + * TRACEID + */ + public static final String TRACE_ID = "traceId"; + + /** + * SPANNAME + */ + public static final String SPAN_NAME = "spanName"; + + /** + * PARENT_ID + */ + public static final String PARENT_ID = "parentSpanId"; + /** * Construction prohibited. */ diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java index 88f407de..420f3a00 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java @@ -37,4 +37,43 @@ public void removeCorrelationId() { MDC.remove(LoggingConstants.CORRELATION_ID); } + @Override + public void setTraceId(String traceId) { + + MDC.put(LoggingConstants.TRACE_ID, traceId); + + } + + @Override + public void setSpanId(String spanId) { + + MDC.put(LoggingConstants.SPAN_ID, spanId); + } + + @Override + public void removeTraceId() { + + MDC.remove(LoggingConstants.TRACE_ID); + + } + + @Override + public void removeSpanId() { + + MDC.remove(LoggingConstants.SPAN_ID); + + } + + @Override + public String getTraceId() { + + return MDC.get(LoggingConstants.TRACE_ID); + } + + @Override + public String getSpanId() { + + return MDC.get(LoggingConstants.SPAN_ID); + } + } diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java new file mode 100644 index 00000000..3ad61aaf --- /dev/null +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java @@ -0,0 +1,223 @@ +package com.devonfw.module.logging.common.impl; + +import java.io.IOException; + +import javax.inject.Inject; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.module.logging.common.api.DiagnosticContextFacade; +import com.devonfw.module.logging.common.api.LoggingConstants; + +import brave.Tracer; +import brave.propagation.TraceContext; + +/** + * + */ +public class TraceContextFilter implements Filter { + + private static final Logger LOG = LoggerFactory.getLogger(TraceContextFilter.class); + + /** + * + */ + public static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHeaderName"; + + /** + * + */ + public static final String TRACE_ID_HEADER_NAME_DEFAULT = "X-Trace-Id"; + + /** + * + */ + public static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHeaderName"; + + /** + * + */ + public static final String SPAN_ID_HEADER_NAME_DEFAULT = "X-Span-Id"; + + /** @see #setTraceIdHttpHeaderName(String) */ + private String traceIdHttpHeaderName; + + private String spanIdHeaderName; + + private DiagnosticContextFacade diagnosticContextFacade; + + private TraceHeadersInjector traceHeadersInjector; + + @Inject + private Tracer tracer; + + /** + * The constructor. + */ + public TraceContextFilter() { + + super(); + this.traceIdHttpHeaderName = TRACE_ID_HEADER_NAME_DEFAULT; + } + + /** + * @param traceIdHttpHeaderName + */ + public void setTraceIdHttpHeaderName(String traceIdHttpHeaderName) { + + this.traceIdHttpHeaderName = traceIdHttpHeaderName; + } + + /** + * @param spanIdHeaderName + */ + public void setSpanIdHeaderName(String spanIdHeaderName) { + + this.spanIdHeaderName = spanIdHeaderName; + } + + private static String normalizeValue(String value) { + + if (value != null) { + String result = value.trim(); + if (!result.isEmpty()) { + return result; + } + } + return null; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + String traceHeaderName = filterConfig.getInitParameter(TRACE_ID_HEADER_NAME_PARAM); + + if (traceHeaderName == null) { + LOG.debug("Parameter {} not configured via filter config.", TRACE_ID_HEADER_NAME_PARAM); + } else { + this.traceIdHttpHeaderName = traceHeaderName; + } + + LOG.info("trace ID header initialized to: {}", this.traceIdHttpHeaderName); + + if (this.diagnosticContextFacade == null) { + try { + // ATTENTION: We do not import these classes as we keep spring as an optional dependency. + // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a + // ClassNotFoundException and use the fallback in the catch statement. + ServletContext servletContext = filterConfig.getServletContext(); + org.springframework.web.context.WebApplicationContext springContext; + springContext = org.springframework.web.context.support.WebApplicationContextUtils + .getWebApplicationContext(servletContext); + this.diagnosticContextFacade = springContext.getBean(DiagnosticContextFacade.class); + } catch (Throwable e) { + LOG.warn("DiagnosticContextFacade not defined in spring. Falling back to default", e); + this.diagnosticContextFacade = new DiagnosticContextFacadeImpl(); + } + + } + + if (this.traceHeadersInjector == null) { + try { + // ATTENTION: We do not import these classes as we keep spring as an optional dependency. + // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a + // ClassNotFoundException and use the fallback in the catch statement. + ServletContext servletContext = filterConfig.getServletContext(); + org.springframework.web.context.WebApplicationContext springContext; + springContext = org.springframework.web.context.support.WebApplicationContextUtils + .getWebApplicationContext(servletContext); + this.traceHeadersInjector = springContext.getBean(TraceHeadersInjector.class); + } catch (Throwable e) { + LOG.warn("TraceHeadersInjector not defined in spring. Falling back to default", e); + this.traceHeadersInjector = new TraceHeadersInjector(); + } + + } + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + setTraceId(request); + try { + chain.doFilter(request, response); + } finally { + this.diagnosticContextFacade.removeTraceId(); + this.diagnosticContextFacade.removeSpanId(); + } + + } + + private void setTraceId(ServletRequest request) { + + String traceId = null; + String spanId = null; + + if (request instanceof HttpServletRequest && this.traceIdHttpHeaderName != null && this.spanIdHeaderName != null) { + + traceId = normalizeValue(((HttpServletRequest) request).getHeader(this.traceIdHttpHeaderName)); + + if (traceId == null) { + LOG.debug("No trace ID found for HTTP header {}.", this.traceIdHttpHeaderName); + } else { + this.diagnosticContextFacade.setTraceId(traceId); + LOG.debug("Using traceId ID {} from HTTP header {}.", traceId, this.traceIdHttpHeaderName); + return; + } + + spanId = normalizeValue(((HttpServletRequest) request).getHeader(this.spanIdHeaderName)); + + if (spanId == null) { + LOG.debug("No spanId ID found for HTTP header {}.", this.spanIdHeaderName); + } else { + this.diagnosticContextFacade.setSpanId(spanId); + LOG.debug("Using spanId ID {} from HTTP header {}.", spanId, this.spanIdHeaderName); + return; + } + + } + + if (traceId == null) { + // potential fallback if initialized before this filter... + traceId = normalizeValue(this.diagnosticContextFacade.getTraceId()); + if (traceId != null) { + LOG.debug("TraceId ID was already set to {} before TraceContextFilter has been invoked.", traceId); + } else { + // no traceId ID present, inject from trace context + // traceId = UUID.randomUUID().toString(); + // this.diagnosticContextFacade.setTraceId(traceId); + TraceContext context = getActiveTraceContext(); + this.traceHeadersInjector.inject(context, this.diagnosticContextFacade); + LOG.debug("Injected trace ID {} and span ID {} .", context.traceIdString(), context.spanIdString()); + } + } + + } + + private TraceContext getActiveTraceContext() { + + if (this.tracer.currentSpan() == null) { + this.tracer.nextSpan().name(LoggingConstants.SPAN_NAME).start(); + return this.tracer.nextSpan().context(); + } + + return this.tracer.currentSpan().context(); + } + + @Override + public void destroy() { + + } + +} diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java new file mode 100644 index 00000000..24f24159 --- /dev/null +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java @@ -0,0 +1,23 @@ +package com.devonfw.module.logging.common.impl; + +import com.devonfw.module.logging.common.api.DiagnosticContextFacade; + +import brave.propagation.TraceContext; + +/** + * + */ +public class TraceHeadersInjector implements TraceContext.Injector { + + @Override + public void inject(TraceContext traceContext, DiagnosticContextFacade contextFacade) { + + String traceId = traceContext.traceIdString(); + contextFacade.setTraceId(traceId); + + String spanId = traceContext.spanIdString(); + contextFacade.setSpanId(spanId); + + } + +} From aca520bbdd8fd1ba63fd64b551eaf52bd182e571 Mon Sep 17 00:00:00 2001 From: Ravichandran M Date: Fri, 24 Jul 2020 22:06:44 +0530 Subject: [PATCH 2/5] full impl --- .../common/impl/TraceContextFilter.java | 2 - .../ServiceHeaderCustomizerTraceSpanId.java | 57 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java index 3ad61aaf..eecfee4d 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java @@ -195,8 +195,6 @@ private void setTraceId(ServletRequest request) { LOG.debug("TraceId ID was already set to {} before TraceContextFilter has been invoked.", traceId); } else { // no traceId ID present, inject from trace context - // traceId = UUID.randomUUID().toString(); - // this.diagnosticContextFacade.setTraceId(traceId); TraceContext context = getActiveTraceContext(); this.traceHeadersInjector.inject(context, this.diagnosticContextFacade); LOG.debug("Injected trace ID {} and span ID {} .", context.traceIdString(), context.spanIdString()); diff --git a/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java b/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java new file mode 100644 index 00000000..aa6fc656 --- /dev/null +++ b/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java @@ -0,0 +1,57 @@ +package com.devonfw.module.service.common.impl.header; + +import org.slf4j.MDC; +import org.springframework.util.StringUtils; + +import com.devonfw.module.logging.common.api.LoggingConstants; +import com.devonfw.module.logging.common.impl.TraceContextFilter; +import com.devonfw.module.service.common.api.header.ServiceHeaderContext; +import com.devonfw.module.service.common.api.header.ServiceHeaderCustomizer; + +/** + * + */ +public class ServiceHeaderCustomizerTraceSpanId implements ServiceHeaderCustomizer { + + private final String traceIdHeaderName; + + private final String spanIdHeaderName; + + /** + * The constructor. + */ + public ServiceHeaderCustomizerTraceSpanId() { + + this(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT, TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); + } + + /** + * The constructor. + * + * @param traceIdHeaderName + * @param spanIdHeaderName + */ + public ServiceHeaderCustomizerTraceSpanId(String traceIdHeaderName, String spanIdHeaderName) { + + super(); + this.traceIdHeaderName = traceIdHeaderName; + this.spanIdHeaderName = spanIdHeaderName; + } + + @Override + public void addHeaders(ServiceHeaderContext context) { + + String traceId = MDC.get(LoggingConstants.TRACE_ID); + String spanId = MDC.get(LoggingConstants.SPAN_ID); + + if (!StringUtils.isEmpty(traceId)) { + context.setHeader(this.traceIdHeaderName, traceId); + } + + if (!StringUtils.isEmpty(spanId)) { + context.setHeader(this.spanIdHeaderName, spanId); + } + + } + +} From 3fc1814a72d5a18bb93cc22bf32a1e773f627553 Mon Sep 17 00:00:00 2001 From: Ravichandran M Date: Sun, 26 Jul 2020 18:33:57 +0530 Subject: [PATCH 3/5] junits --- .../common/impl/TraceContextFilter.java | 38 ++++-- .../common/impl/TraceContextFilterTest.java | 112 ++++++++++++++++++ 2 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java index eecfee4d..26b2190f 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java @@ -51,7 +51,8 @@ public class TraceContextFilter implements Filter { /** @see #setTraceIdHttpHeaderName(String) */ private String traceIdHttpHeaderName; - private String spanIdHeaderName; + /** @see #setSpanIdHttpHeaderName(String) */ + private String spanIdHttpHeaderName; private DiagnosticContextFacade diagnosticContextFacade; @@ -67,6 +68,7 @@ public TraceContextFilter() { super(); this.traceIdHttpHeaderName = TRACE_ID_HEADER_NAME_DEFAULT; + this.spanIdHttpHeaderName = SPAN_ID_HEADER_NAME_DEFAULT; } /** @@ -82,7 +84,7 @@ public void setTraceIdHttpHeaderName(String traceIdHttpHeaderName) { */ public void setSpanIdHeaderName(String spanIdHeaderName) { - this.spanIdHeaderName = spanIdHeaderName; + this.spanIdHttpHeaderName = spanIdHeaderName; } private static String normalizeValue(String value) { @@ -100,6 +102,7 @@ private static String normalizeValue(String value) { public void init(FilterConfig filterConfig) throws ServletException { String traceHeaderName = filterConfig.getInitParameter(TRACE_ID_HEADER_NAME_PARAM); + String spanHeaderName = filterConfig.getInitParameter(SPAN_ID_HEADER_NAME_PARAM); if (traceHeaderName == null) { LOG.debug("Parameter {} not configured via filter config.", TRACE_ID_HEADER_NAME_PARAM); @@ -107,7 +110,14 @@ public void init(FilterConfig filterConfig) throws ServletException { this.traceIdHttpHeaderName = traceHeaderName; } + if (spanHeaderName == null) { + LOG.debug("Parameter {} not configured via filter config.", SPAN_ID_HEADER_NAME_PARAM); + } else { + this.spanIdHttpHeaderName = spanHeaderName; + } + LOG.info("trace ID header initialized to: {}", this.traceIdHttpHeaderName); + LOG.info("span ID header initialized to: {}", this.spanIdHttpHeaderName); if (this.diagnosticContextFacade == null) { try { @@ -149,22 +159,23 @@ public void init(FilterConfig filterConfig) throws ServletException { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - setTraceId(request); + setTraceAndSpanId(request); try { chain.doFilter(request, response); } finally { - this.diagnosticContextFacade.removeTraceId(); this.diagnosticContextFacade.removeSpanId(); + this.diagnosticContextFacade.removeTraceId(); } } - private void setTraceId(ServletRequest request) { + private void setTraceAndSpanId(ServletRequest request) { String traceId = null; String spanId = null; - if (request instanceof HttpServletRequest && this.traceIdHttpHeaderName != null && this.spanIdHeaderName != null) { + if (request instanceof HttpServletRequest && this.traceIdHttpHeaderName != null + && this.spanIdHttpHeaderName != null) { traceId = normalizeValue(((HttpServletRequest) request).getHeader(this.traceIdHttpHeaderName)); @@ -176,13 +187,13 @@ private void setTraceId(ServletRequest request) { return; } - spanId = normalizeValue(((HttpServletRequest) request).getHeader(this.spanIdHeaderName)); + spanId = normalizeValue(((HttpServletRequest) request).getHeader(this.spanIdHttpHeaderName)); if (spanId == null) { - LOG.debug("No spanId ID found for HTTP header {}.", this.spanIdHeaderName); + LOG.debug("No spanId ID found for HTTP header {}.", this.spanIdHttpHeaderName); } else { this.diagnosticContextFacade.setSpanId(spanId); - LOG.debug("Using spanId ID {} from HTTP header {}.", spanId, this.spanIdHeaderName); + LOG.debug("Using spanId ID {} from HTTP header {}.", spanId, this.spanIdHttpHeaderName); return; } @@ -191,10 +202,13 @@ private void setTraceId(ServletRequest request) { if (traceId == null) { // potential fallback if initialized before this filter... traceId = normalizeValue(this.diagnosticContextFacade.getTraceId()); - if (traceId != null) { - LOG.debug("TraceId ID was already set to {} before TraceContextFilter has been invoked.", traceId); + spanId = normalizeValue(this.diagnosticContextFacade.getSpanId()); + + if (traceId != null && spanId != null) { + LOG.debug("Trace ID and Span ID was already set to {} and {} before TraceContextFilter has been invoked.", + traceId, spanId); } else { - // no traceId ID present, inject from trace context + // no traceId ID and span ID present, inject from trace context TraceContext context = getActiveTraceContext(); this.traceHeadersInjector.inject(context, this.diagnosticContextFacade); LOG.debug("Injected trace ID {} and span ID {} .", context.traceIdString(), context.spanIdString()); diff --git a/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java b/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java new file mode 100644 index 00000000..a05ac8e8 --- /dev/null +++ b/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java @@ -0,0 +1,112 @@ +package com.devonfw.module.logging.common.impl; + +import static org.mockito.Mockito.when; + +import javax.servlet.FilterConfig; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import com.devonfw.module.test.common.base.ModuleTest; + +/** + * + */ +@ExtendWith(MockitoExtension.class) +public class TraceContextFilterTest extends ModuleTest { + + private static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHttpHeaderName"; + + private static final String TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME = "TRACE_ID_HEADER_NAME_PARAM"; + + private static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHttpHeaderName"; + + private static final String SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME = "SPAN_ID_HEADER_NAME_PARAM"; + + @Mock + private FilterConfig config; + + /** + * + */ + @Test + public void testTraceAndSpanIdHttpHeaderNameAfterConstructor() { + + // setup + TraceContextFilter filter = new TraceContextFilter(); + + // exercise + String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); + String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); + + // verify + assertThat(traceIdHttpHeaderName).isNotNull(); + assertThat(spanIdHttpHeaderName).isNotNull(); + } + + /** + * @throws Exception + */ + @Test + public void testInitWithNullInitParameter() throws Exception { + + // setup + TraceContextFilter filter = new TraceContextFilter(); + String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, + TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); + String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, + SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); + + assertThat(traceIdField).isNotNull(); + assertThat(spanIdField).isNotNull(); + + when(this.config.getInitParameter(traceIdField)).thenReturn(null); + when(this.config.getInitParameter(spanIdField)).thenReturn(null); + + // exercise + filter.init(this.config); + + // verify + String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); + assertThat(traceIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT); + + String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); + assertThat(spanIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); + } + + /** + * @throws Exception + */ + @Test + public void testInitWithNonDefaultParameter() throws Exception { + + // setup + TraceContextFilter filter = new TraceContextFilter(); + String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, + TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); + String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, + SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); + + assertThat(traceIdField).isNotNull(); + assertThat(spanIdField).isNotNull(); + + String nonDefaultParameter = "test"; + + when(this.config.getInitParameter(traceIdField)).thenReturn(nonDefaultParameter); + when(this.config.getInitParameter(spanIdField)).thenReturn(nonDefaultParameter); + + // exercise + filter.init(this.config); + + // verify + String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); + assertThat(traceIdHttpHeaderName).isEqualTo(nonDefaultParameter); + + String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); + assertThat(spanIdHttpHeaderName).isEqualTo(nonDefaultParameter); + } + +} From df5718ee386eacff4488c524a20c7b007345cf71 Mon Sep 17 00:00:00 2001 From: Ravichandran M Date: Tue, 28 Jul 2020 17:50:42 +0530 Subject: [PATCH 4/5] added missed condition for spanId --- .../devonfw/module/logging/common/impl/TraceContextFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java index 26b2190f..d30f2345 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java @@ -199,7 +199,7 @@ private void setTraceAndSpanId(ServletRequest request) { } - if (traceId == null) { + if (traceId == null && spanId == null) { // potential fallback if initialized before this filter... traceId = normalizeValue(this.diagnosticContextFacade.getTraceId()); spanId = normalizeValue(this.diagnosticContextFacade.getSpanId()); From eff64b056755adab096f8bfb0c906abf7eb31b15 Mon Sep 17 00:00:00 2001 From: Ravichandran M Date: Tue, 11 Aug 2020 21:53:46 +0530 Subject: [PATCH 5/5] introduced open tracing anf jaeger --- modules/logging/pom.xml | 4 +- .../common/api/DiagnosticContextFacade.java | 62 +-- .../impl/DiagnosticContextFacadeImpl.java | 76 +-- .../common/impl/TraceContextFilter.java | 470 +++++++++--------- .../common/impl/TraceHeadersInjector.java | 46 +- .../common/impl/TraceContextFilterTest.java | 224 ++++----- modules/service/pom.xml | 13 +- .../ServiceHeaderCustomizerTraceSpanId.java | 92 +++- 8 files changed, 524 insertions(+), 463 deletions(-) diff --git a/modules/logging/pom.xml b/modules/logging/pom.xml index 11757ebb..0f0484c6 100644 --- a/modules/logging/pom.xml +++ b/modules/logging/pom.xml @@ -59,10 +59,10 @@ org.springframework.boot spring-boot-starter - + \ No newline at end of file diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java index cc52e53a..5fcb0010 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/api/DiagnosticContextFacade.java @@ -30,36 +30,36 @@ public interface DiagnosticContextFacade { */ void removeCorrelationId(); - /** - * - */ - void removeTraceId(); - - /** - * - */ - void removeSpanId(); - - /** - * - * @return - */ - String getTraceId(); - - /** - * - * @return - */ - String getSpanId(); - - /** - * @param spanId - */ - void setSpanId(String spanId); - - /** - * @param traceId - */ - void setTraceId(String traceId); + // /** + // * + // */ + // void removeTraceId(); + // + // /** + // * + // */ + // void removeSpanId(); + // + // /** + // * + // * @return + // */ + // String getTraceId(); + // + // /** + // * + // * @return + // */ + // String getSpanId(); + // + // /** + // * @param spanId + // */ + // void setSpanId(String spanId); + // + // /** + // * @param traceId + // */ + // void setTraceId(String traceId); } diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java index 420f3a00..60db77b6 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/DiagnosticContextFacadeImpl.java @@ -37,43 +37,43 @@ public void removeCorrelationId() { MDC.remove(LoggingConstants.CORRELATION_ID); } - @Override - public void setTraceId(String traceId) { - - MDC.put(LoggingConstants.TRACE_ID, traceId); - - } - - @Override - public void setSpanId(String spanId) { - - MDC.put(LoggingConstants.SPAN_ID, spanId); - } - - @Override - public void removeTraceId() { - - MDC.remove(LoggingConstants.TRACE_ID); - - } - - @Override - public void removeSpanId() { - - MDC.remove(LoggingConstants.SPAN_ID); - - } - - @Override - public String getTraceId() { - - return MDC.get(LoggingConstants.TRACE_ID); - } - - @Override - public String getSpanId() { - - return MDC.get(LoggingConstants.SPAN_ID); - } + // @Override + // public void setTraceId(String traceId) { + // + // MDC.put(LoggingConstants.TRACE_ID, traceId); + // + // } + // + // @Override + // public void setSpanId(String spanId) { + // + // MDC.put(LoggingConstants.SPAN_ID, spanId); + // } + // + // @Override + // public void removeTraceId() { + // + // MDC.remove(LoggingConstants.TRACE_ID); + // + // } + // + // @Override + // public void removeSpanId() { + // + // MDC.remove(LoggingConstants.SPAN_ID); + // + // } + // + // @Override + // public String getTraceId() { + // + // return MDC.get(LoggingConstants.TRACE_ID); + // } + // + // @Override + // public String getSpanId() { + // + // return MDC.get(LoggingConstants.SPAN_ID); + // } } diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java index d30f2345..51add307 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java @@ -1,235 +1,235 @@ -package com.devonfw.module.logging.common.impl; - -import java.io.IOException; - -import javax.inject.Inject; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.devonfw.module.logging.common.api.DiagnosticContextFacade; -import com.devonfw.module.logging.common.api.LoggingConstants; - -import brave.Tracer; -import brave.propagation.TraceContext; - -/** - * - */ -public class TraceContextFilter implements Filter { - - private static final Logger LOG = LoggerFactory.getLogger(TraceContextFilter.class); - - /** - * - */ - public static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHeaderName"; - - /** - * - */ - public static final String TRACE_ID_HEADER_NAME_DEFAULT = "X-Trace-Id"; - - /** - * - */ - public static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHeaderName"; - - /** - * - */ - public static final String SPAN_ID_HEADER_NAME_DEFAULT = "X-Span-Id"; - - /** @see #setTraceIdHttpHeaderName(String) */ - private String traceIdHttpHeaderName; - - /** @see #setSpanIdHttpHeaderName(String) */ - private String spanIdHttpHeaderName; - - private DiagnosticContextFacade diagnosticContextFacade; - - private TraceHeadersInjector traceHeadersInjector; - - @Inject - private Tracer tracer; - - /** - * The constructor. - */ - public TraceContextFilter() { - - super(); - this.traceIdHttpHeaderName = TRACE_ID_HEADER_NAME_DEFAULT; - this.spanIdHttpHeaderName = SPAN_ID_HEADER_NAME_DEFAULT; - } - - /** - * @param traceIdHttpHeaderName - */ - public void setTraceIdHttpHeaderName(String traceIdHttpHeaderName) { - - this.traceIdHttpHeaderName = traceIdHttpHeaderName; - } - - /** - * @param spanIdHeaderName - */ - public void setSpanIdHeaderName(String spanIdHeaderName) { - - this.spanIdHttpHeaderName = spanIdHeaderName; - } - - private static String normalizeValue(String value) { - - if (value != null) { - String result = value.trim(); - if (!result.isEmpty()) { - return result; - } - } - return null; - } - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - - String traceHeaderName = filterConfig.getInitParameter(TRACE_ID_HEADER_NAME_PARAM); - String spanHeaderName = filterConfig.getInitParameter(SPAN_ID_HEADER_NAME_PARAM); - - if (traceHeaderName == null) { - LOG.debug("Parameter {} not configured via filter config.", TRACE_ID_HEADER_NAME_PARAM); - } else { - this.traceIdHttpHeaderName = traceHeaderName; - } - - if (spanHeaderName == null) { - LOG.debug("Parameter {} not configured via filter config.", SPAN_ID_HEADER_NAME_PARAM); - } else { - this.spanIdHttpHeaderName = spanHeaderName; - } - - LOG.info("trace ID header initialized to: {}", this.traceIdHttpHeaderName); - LOG.info("span ID header initialized to: {}", this.spanIdHttpHeaderName); - - if (this.diagnosticContextFacade == null) { - try { - // ATTENTION: We do not import these classes as we keep spring as an optional dependency. - // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a - // ClassNotFoundException and use the fallback in the catch statement. - ServletContext servletContext = filterConfig.getServletContext(); - org.springframework.web.context.WebApplicationContext springContext; - springContext = org.springframework.web.context.support.WebApplicationContextUtils - .getWebApplicationContext(servletContext); - this.diagnosticContextFacade = springContext.getBean(DiagnosticContextFacade.class); - } catch (Throwable e) { - LOG.warn("DiagnosticContextFacade not defined in spring. Falling back to default", e); - this.diagnosticContextFacade = new DiagnosticContextFacadeImpl(); - } - - } - - if (this.traceHeadersInjector == null) { - try { - // ATTENTION: We do not import these classes as we keep spring as an optional dependency. - // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a - // ClassNotFoundException and use the fallback in the catch statement. - ServletContext servletContext = filterConfig.getServletContext(); - org.springframework.web.context.WebApplicationContext springContext; - springContext = org.springframework.web.context.support.WebApplicationContextUtils - .getWebApplicationContext(servletContext); - this.traceHeadersInjector = springContext.getBean(TraceHeadersInjector.class); - } catch (Throwable e) { - LOG.warn("TraceHeadersInjector not defined in spring. Falling back to default", e); - this.traceHeadersInjector = new TraceHeadersInjector(); - } - - } - - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - - setTraceAndSpanId(request); - try { - chain.doFilter(request, response); - } finally { - this.diagnosticContextFacade.removeSpanId(); - this.diagnosticContextFacade.removeTraceId(); - } - - } - - private void setTraceAndSpanId(ServletRequest request) { - - String traceId = null; - String spanId = null; - - if (request instanceof HttpServletRequest && this.traceIdHttpHeaderName != null - && this.spanIdHttpHeaderName != null) { - - traceId = normalizeValue(((HttpServletRequest) request).getHeader(this.traceIdHttpHeaderName)); - - if (traceId == null) { - LOG.debug("No trace ID found for HTTP header {}.", this.traceIdHttpHeaderName); - } else { - this.diagnosticContextFacade.setTraceId(traceId); - LOG.debug("Using traceId ID {} from HTTP header {}.", traceId, this.traceIdHttpHeaderName); - return; - } - - spanId = normalizeValue(((HttpServletRequest) request).getHeader(this.spanIdHttpHeaderName)); - - if (spanId == null) { - LOG.debug("No spanId ID found for HTTP header {}.", this.spanIdHttpHeaderName); - } else { - this.diagnosticContextFacade.setSpanId(spanId); - LOG.debug("Using spanId ID {} from HTTP header {}.", spanId, this.spanIdHttpHeaderName); - return; - } - - } - - if (traceId == null && spanId == null) { - // potential fallback if initialized before this filter... - traceId = normalizeValue(this.diagnosticContextFacade.getTraceId()); - spanId = normalizeValue(this.diagnosticContextFacade.getSpanId()); - - if (traceId != null && spanId != null) { - LOG.debug("Trace ID and Span ID was already set to {} and {} before TraceContextFilter has been invoked.", - traceId, spanId); - } else { - // no traceId ID and span ID present, inject from trace context - TraceContext context = getActiveTraceContext(); - this.traceHeadersInjector.inject(context, this.diagnosticContextFacade); - LOG.debug("Injected trace ID {} and span ID {} .", context.traceIdString(), context.spanIdString()); - } - } - - } - - private TraceContext getActiveTraceContext() { - - if (this.tracer.currentSpan() == null) { - this.tracer.nextSpan().name(LoggingConstants.SPAN_NAME).start(); - return this.tracer.nextSpan().context(); - } - - return this.tracer.currentSpan().context(); - } - - @Override - public void destroy() { - - } - -} +// package com.devonfw.module.logging.common.impl; +// +// import java.io.IOException; +// +// import javax.inject.Inject; +// import javax.servlet.Filter; +// import javax.servlet.FilterChain; +// import javax.servlet.FilterConfig; +// import javax.servlet.ServletContext; +// import javax.servlet.ServletException; +// import javax.servlet.ServletRequest; +// import javax.servlet.ServletResponse; +// import javax.servlet.http.HttpServletRequest; +// +// import org.slf4j.Logger; +// import org.slf4j.LoggerFactory; +// +// import com.devonfw.module.logging.common.api.DiagnosticContextFacade; +// import com.devonfw.module.logging.common.api.LoggingConstants; +// +// import brave.Tracer; +// import brave.propagation.TraceContext; +// +/// ** +// * +// */ +// public class TraceContextFilter implements Filter { +// +// private static final Logger LOG = LoggerFactory.getLogger(TraceContextFilter.class); +// +// /** +// * +// */ +// public static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHeaderName"; +// +// /** +// * +// */ +// public static final String TRACE_ID_HEADER_NAME_DEFAULT = "X-Trace-Id"; +// +// /** +// * +// */ +// public static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHeaderName"; +// +// /** +// * +// */ +// public static final String SPAN_ID_HEADER_NAME_DEFAULT = "X-Span-Id"; +// +// /** @see #setTraceIdHttpHeaderName(String) */ +// private String traceIdHttpHeaderName; +// +// /** @see #setSpanIdHttpHeaderName(String) */ +// private String spanIdHttpHeaderName; +// +// private DiagnosticContextFacade diagnosticContextFacade; +// +// private TraceHeadersInjector traceHeadersInjector; +// +// @Inject +// private Tracer tracer; +// +// /** +// * The constructor. +// */ +// public TraceContextFilter() { +// +// super(); +// this.traceIdHttpHeaderName = TRACE_ID_HEADER_NAME_DEFAULT; +// this.spanIdHttpHeaderName = SPAN_ID_HEADER_NAME_DEFAULT; +// } +// +// /** +// * @param traceIdHttpHeaderName +// */ +// public void setTraceIdHttpHeaderName(String traceIdHttpHeaderName) { +// +// this.traceIdHttpHeaderName = traceIdHttpHeaderName; +// } +// +// /** +// * @param spanIdHeaderName +// */ +// public void setSpanIdHeaderName(String spanIdHeaderName) { +// +// this.spanIdHttpHeaderName = spanIdHeaderName; +// } +// +// private static String normalizeValue(String value) { +// +// if (value != null) { +// String result = value.trim(); +// if (!result.isEmpty()) { +// return result; +// } +// } +// return null; +// } +// +// @Override +// public void init(FilterConfig filterConfig) throws ServletException { +// +// String traceHeaderName = filterConfig.getInitParameter(TRACE_ID_HEADER_NAME_PARAM); +// String spanHeaderName = filterConfig.getInitParameter(SPAN_ID_HEADER_NAME_PARAM); +// +// if (traceHeaderName == null) { +// LOG.debug("Parameter {} not configured via filter config.", TRACE_ID_HEADER_NAME_PARAM); +// } else { +// this.traceIdHttpHeaderName = traceHeaderName; +// } +// +// if (spanHeaderName == null) { +// LOG.debug("Parameter {} not configured via filter config.", SPAN_ID_HEADER_NAME_PARAM); +// } else { +// this.spanIdHttpHeaderName = spanHeaderName; +// } +// +// LOG.info("trace ID header initialized to: {}", this.traceIdHttpHeaderName); +// LOG.info("span ID header initialized to: {}", this.spanIdHttpHeaderName); +// +// if (this.diagnosticContextFacade == null) { +// try { +// // ATTENTION: We do not import these classes as we keep spring as an optional dependency. +// // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a +// // ClassNotFoundException and use the fallback in the catch statement. +// ServletContext servletContext = filterConfig.getServletContext(); +// org.springframework.web.context.WebApplicationContext springContext; +// springContext = org.springframework.web.context.support.WebApplicationContextUtils +// .getWebApplicationContext(servletContext); +// this.diagnosticContextFacade = springContext.getBean(DiagnosticContextFacade.class); +// } catch (Throwable e) { +// LOG.warn("DiagnosticContextFacade not defined in spring. Falling back to default", e); +// this.diagnosticContextFacade = new DiagnosticContextFacadeImpl(); +// } +// +// } +// +// if (this.traceHeadersInjector == null) { +// try { +// // ATTENTION: We do not import these classes as we keep spring as an optional dependency. +// // If spring is not available in your classpath (e.g. some real JEE context) then this will produce a +// // ClassNotFoundException and use the fallback in the catch statement. +// ServletContext servletContext = filterConfig.getServletContext(); +// org.springframework.web.context.WebApplicationContext springContext; +// springContext = org.springframework.web.context.support.WebApplicationContextUtils +// .getWebApplicationContext(servletContext); +// this.traceHeadersInjector = springContext.getBean(TraceHeadersInjector.class); +// } catch (Throwable e) { +// LOG.warn("TraceHeadersInjector not defined in spring. Falling back to default", e); +// this.traceHeadersInjector = new TraceHeadersInjector(); +// } +// +// } +// +// } +// +// @Override +// public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) +// throws IOException, ServletException { +// +// setTraceAndSpanId(request); +// try { +// chain.doFilter(request, response); +// } finally { +// this.diagnosticContextFacade.removeSpanId(); +// this.diagnosticContextFacade.removeTraceId(); +// } +// +// } +// +// private void setTraceAndSpanId(ServletRequest request) { +// +// String traceId = null; +// String spanId = null; +// +// if (request instanceof HttpServletRequest && this.traceIdHttpHeaderName != null +// && this.spanIdHttpHeaderName != null) { +// +// traceId = normalizeValue(((HttpServletRequest) request).getHeader(this.traceIdHttpHeaderName)); +// +// if (traceId == null) { +// LOG.debug("No trace ID found for HTTP header {}.", this.traceIdHttpHeaderName); +// } else { +// this.diagnosticContextFacade.setTraceId(traceId); +// LOG.debug("Using traceId ID {} from HTTP header {}.", traceId, this.traceIdHttpHeaderName); +// return; +// } +// +// spanId = normalizeValue(((HttpServletRequest) request).getHeader(this.spanIdHttpHeaderName)); +// +// if (spanId == null) { +// LOG.debug("No spanId ID found for HTTP header {}.", this.spanIdHttpHeaderName); +// } else { +// this.diagnosticContextFacade.setSpanId(spanId); +// LOG.debug("Using spanId ID {} from HTTP header {}.", spanId, this.spanIdHttpHeaderName); +// return; +// } +// +// } +// +// if (traceId == null && spanId == null) { +// // potential fallback if initialized before this filter... +// traceId = normalizeValue(this.diagnosticContextFacade.getTraceId()); +// spanId = normalizeValue(this.diagnosticContextFacade.getSpanId()); +// +// if (traceId != null && spanId != null) { +// LOG.debug("Trace ID and Span ID was already set to {} and {} before TraceContextFilter has been invoked.", +// traceId, spanId); +// } else { +// // no traceId ID and span ID present, inject from trace context +// TraceContext context = getActiveTraceContext(); +// this.traceHeadersInjector.inject(context, this.diagnosticContextFacade); +// LOG.debug("Injected trace ID {} and span ID {} .", context.traceIdString(), context.spanIdString()); +// } +// } +// +// } +// +// private TraceContext getActiveTraceContext() { +// +// if (this.tracer.currentSpan() == null) { +// this.tracer.nextSpan().name(LoggingConstants.SPAN_NAME).start(); +// return this.tracer.nextSpan().context(); +// } +// +// return this.tracer.currentSpan().context(); +// } +// +// @Override +// public void destroy() { +// +// } +// +// } diff --git a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java index 24f24159..7efc59c6 100644 --- a/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java +++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceHeadersInjector.java @@ -1,23 +1,23 @@ -package com.devonfw.module.logging.common.impl; - -import com.devonfw.module.logging.common.api.DiagnosticContextFacade; - -import brave.propagation.TraceContext; - -/** - * - */ -public class TraceHeadersInjector implements TraceContext.Injector { - - @Override - public void inject(TraceContext traceContext, DiagnosticContextFacade contextFacade) { - - String traceId = traceContext.traceIdString(); - contextFacade.setTraceId(traceId); - - String spanId = traceContext.spanIdString(); - contextFacade.setSpanId(spanId); - - } - -} +// package com.devonfw.module.logging.common.impl; +// +// import com.devonfw.module.logging.common.api.DiagnosticContextFacade; +// +// import brave.propagation.TraceContext; +// +/// ** +// * +// */ +// public class TraceHeadersInjector implements TraceContext.Injector { +// +// @Override +// public void inject(TraceContext traceContext, DiagnosticContextFacade contextFacade) { +// +// String traceId = traceContext.traceIdString(); +// contextFacade.setTraceId(traceId); +// +// String spanId = traceContext.spanIdString(); +// contextFacade.setSpanId(spanId); +// +// } +// +// } diff --git a/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java b/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java index a05ac8e8..0dde3e3e 100644 --- a/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java +++ b/modules/logging/src/test/java/com/devonfw/module/logging/common/impl/TraceContextFilterTest.java @@ -1,112 +1,112 @@ -package com.devonfw.module.logging.common.impl; - -import static org.mockito.Mockito.when; - -import javax.servlet.FilterConfig; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.test.util.ReflectionTestUtils; - -import com.devonfw.module.test.common.base.ModuleTest; - -/** - * - */ -@ExtendWith(MockitoExtension.class) -public class TraceContextFilterTest extends ModuleTest { - - private static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHttpHeaderName"; - - private static final String TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME = "TRACE_ID_HEADER_NAME_PARAM"; - - private static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHttpHeaderName"; - - private static final String SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME = "SPAN_ID_HEADER_NAME_PARAM"; - - @Mock - private FilterConfig config; - - /** - * - */ - @Test - public void testTraceAndSpanIdHttpHeaderNameAfterConstructor() { - - // setup - TraceContextFilter filter = new TraceContextFilter(); - - // exercise - String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); - String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); - - // verify - assertThat(traceIdHttpHeaderName).isNotNull(); - assertThat(spanIdHttpHeaderName).isNotNull(); - } - - /** - * @throws Exception - */ - @Test - public void testInitWithNullInitParameter() throws Exception { - - // setup - TraceContextFilter filter = new TraceContextFilter(); - String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, - TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); - String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, - SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); - - assertThat(traceIdField).isNotNull(); - assertThat(spanIdField).isNotNull(); - - when(this.config.getInitParameter(traceIdField)).thenReturn(null); - when(this.config.getInitParameter(spanIdField)).thenReturn(null); - - // exercise - filter.init(this.config); - - // verify - String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); - assertThat(traceIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT); - - String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); - assertThat(spanIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); - } - - /** - * @throws Exception - */ - @Test - public void testInitWithNonDefaultParameter() throws Exception { - - // setup - TraceContextFilter filter = new TraceContextFilter(); - String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, - TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); - String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, - SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); - - assertThat(traceIdField).isNotNull(); - assertThat(spanIdField).isNotNull(); - - String nonDefaultParameter = "test"; - - when(this.config.getInitParameter(traceIdField)).thenReturn(nonDefaultParameter); - when(this.config.getInitParameter(spanIdField)).thenReturn(nonDefaultParameter); - - // exercise - filter.init(this.config); - - // verify - String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); - assertThat(traceIdHttpHeaderName).isEqualTo(nonDefaultParameter); - - String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); - assertThat(spanIdHttpHeaderName).isEqualTo(nonDefaultParameter); - } - -} +// package com.devonfw.module.logging.common.impl; +// +// import static org.mockito.Mockito.when; +// +// import javax.servlet.FilterConfig; +// +// import org.junit.jupiter.api.Test; +// import org.junit.jupiter.api.extension.ExtendWith; +// import org.mockito.Mock; +// import org.mockito.junit.jupiter.MockitoExtension; +// import org.springframework.test.util.ReflectionTestUtils; +// +// import com.devonfw.module.test.common.base.ModuleTest; +// +/// ** +// * +// */ +// @ExtendWith(MockitoExtension.class) +// public class TraceContextFilterTest extends ModuleTest { +// +// private static final String TRACE_ID_HEADER_NAME_PARAM = "traceIdHttpHeaderName"; +// +// private static final String TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME = "TRACE_ID_HEADER_NAME_PARAM"; +// +// private static final String SPAN_ID_HEADER_NAME_PARAM = "spanIdHttpHeaderName"; +// +// private static final String SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME = "SPAN_ID_HEADER_NAME_PARAM"; +// +// @Mock +// private FilterConfig config; +// +// /** +// * +// */ +// @Test +// public void testTraceAndSpanIdHttpHeaderNameAfterConstructor() { +// +// // setup +// TraceContextFilter filter = new TraceContextFilter(); +// +// // exercise +// String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); +// String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); +// +// // verify +// assertThat(traceIdHttpHeaderName).isNotNull(); +// assertThat(spanIdHttpHeaderName).isNotNull(); +// } +// +// /** +// * @throws Exception +// */ +// @Test +// public void testInitWithNullInitParameter() throws Exception { +// +// // setup +// TraceContextFilter filter = new TraceContextFilter(); +// String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, +// TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); +// String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, +// SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); +// +// assertThat(traceIdField).isNotNull(); +// assertThat(spanIdField).isNotNull(); +// +// when(this.config.getInitParameter(traceIdField)).thenReturn(null); +// when(this.config.getInitParameter(spanIdField)).thenReturn(null); +// +// // exercise +// filter.init(this.config); +// +// // verify +// String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); +// assertThat(traceIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT); +// +// String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); +// assertThat(spanIdHttpHeaderName).isNotNull().isEqualTo(TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); +// } +// +// /** +// * @throws Exception +// */ +// @Test +// public void testInitWithNonDefaultParameter() throws Exception { +// +// // setup +// TraceContextFilter filter = new TraceContextFilter(); +// String traceIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, +// TRACE_ID_HEADER_NAME_PARAM_FIELD_NAME); +// String spanIdField = (String) ReflectionTestUtils.getField(TraceContextFilter.class, +// SPAN_ID_HEADER_NAME_PARAM_FIELD_NAME); +// +// assertThat(traceIdField).isNotNull(); +// assertThat(spanIdField).isNotNull(); +// +// String nonDefaultParameter = "test"; +// +// when(this.config.getInitParameter(traceIdField)).thenReturn(nonDefaultParameter); +// when(this.config.getInitParameter(spanIdField)).thenReturn(nonDefaultParameter); +// +// // exercise +// filter.init(this.config); +// +// // verify +// String traceIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, TRACE_ID_HEADER_NAME_PARAM); +// assertThat(traceIdHttpHeaderName).isEqualTo(nonDefaultParameter); +// +// String spanIdHttpHeaderName = (String) ReflectionTestUtils.getField(filter, SPAN_ID_HEADER_NAME_PARAM); +// assertThat(spanIdHttpHeaderName).isEqualTo(nonDefaultParameter); +// } +// +// } diff --git a/modules/service/pom.xml b/modules/service/pom.xml index bba31b46..683b4b73 100644 --- a/modules/service/pom.xml +++ b/modules/service/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 @@ -47,6 +48,16 @@ javax.annotation-api test + + io.opentracing + opentracing-api + 0.33.0 + + + io.jaegertracing + jaeger-client + 0.32.0 + diff --git a/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java b/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java index aa6fc656..8d38554b 100644 --- a/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java +++ b/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java @@ -1,55 +1,105 @@ package com.devonfw.module.service.common.impl.header; -import org.slf4j.MDC; -import org.springframework.util.StringUtils; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.devonfw.module.logging.common.api.LoggingConstants; -import com.devonfw.module.logging.common.impl.TraceContextFilter; import com.devonfw.module.service.common.api.header.ServiceHeaderContext; import com.devonfw.module.service.common.api.header.ServiceHeaderCustomizer; +import io.jaegertracing.Configuration; +import io.jaegertracing.Configuration.ReporterConfiguration; +import io.jaegertracing.Configuration.SamplerConfiguration; +import io.opentracing.Scope; +import io.opentracing.Span; +import io.opentracing.Tracer; +import io.opentracing.log.Fields; +import io.opentracing.tag.Tags; + /** * */ public class ServiceHeaderCustomizerTraceSpanId implements ServiceHeaderCustomizer { - private final String traceIdHeaderName; - - private final String spanIdHeaderName; + private static final Logger LOG = LoggerFactory.getLogger(ServiceHeaderCustomizerTraceSpanId.class); /** * The constructor. */ public ServiceHeaderCustomizerTraceSpanId() { - this(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT, TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); + super(); } /** - * The constructor. + * This method is used to create tracer with jaeger tracing. * - * @param traceIdHeaderName - * @param spanIdHeaderName + * @return {@link Tracer} */ - public ServiceHeaderCustomizerTraceSpanId(String traceIdHeaderName, String spanIdHeaderName) { + public Tracer initTracer() { - super(); - this.traceIdHeaderName = traceIdHeaderName; - this.spanIdHeaderName = spanIdHeaderName; + SamplerConfiguration samplerConfig = SamplerConfiguration.fromEnv().withType("const").withParam(1); + ReporterConfiguration reporterConfig = ReporterConfiguration.fromEnv().withLogSpans(true); + Configuration config = new Configuration("service").withSampler(samplerConfig).withReporter(reporterConfig); + return config.getTracer(); } + // private final String traceIdHeaderName; + // + // private final String spanIdHeaderName; + // + // /** + // * The constructor. + // */ + // public ServiceHeaderCustomizerTraceSpanId() { + // + // this(TraceContextFilter.TRACE_ID_HEADER_NAME_DEFAULT, TraceContextFilter.SPAN_ID_HEADER_NAME_DEFAULT); + // } + // + // /** + // * The constructor. + // * + // * @param traceIdHeaderName + // * @param spanIdHeaderName + // */ + // public ServiceHeaderCustomizerTraceSpanId(String traceIdHeaderName, String spanIdHeaderName) { + // + // super(); + // this.traceIdHeaderName = traceIdHeaderName; + // this.spanIdHeaderName = spanIdHeaderName; + // } + @Override public void addHeaders(ServiceHeaderContext context) { - String traceId = MDC.get(LoggingConstants.TRACE_ID); - String spanId = MDC.get(LoggingConstants.SPAN_ID); + // String traceId = MDC.get(LoggingConstants.TRACE_ID); + // String spanId = MDC.get(LoggingConstants.SPAN_ID); + // + // if (!StringUtils.isEmpty(traceId)) { + // context.setHeader(this.traceIdHeaderName, traceId); + // } + // + // if (!StringUtils.isEmpty(spanId)) { + // context.setHeader(this.spanIdHeaderName, spanId); + // } - if (!StringUtils.isEmpty(traceId)) { - context.setHeader(this.traceIdHeaderName, traceId); - } + Tracer tracer = initTracer(); + + Span span = tracer.buildSpan(LoggingConstants.SPAN_NAME).start(); + LOG.info("new span {} has been created for the http request {}.", context.getUrl(), span.context().toSpanId()); + + try (Scope scope = tracer.scopeManager().activate(span)) { + + context.setHeader(LoggingConstants.TRACE_ID, span.context().toTraceId()); + context.setHeader(LoggingConstants.SPAN_ID, span.context().toSpanId()); - if (!StringUtils.isEmpty(spanId)) { - context.setHeader(this.spanIdHeaderName, spanId); + } catch (Exception ex) { + Tags.ERROR.set(span, true); + span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, ex, Fields.MESSAGE, ex.getMessage())); + } finally { + span.finish(); } }