diff --git a/modules/logging/pom.xml b/modules/logging/pom.xml
index df0861a6..0f0484c6 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
+
\ 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..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,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..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,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..51add307
--- /dev/null
+++ b/modules/logging/src/main/java/com/devonfw/module/logging/common/impl/TraceContextFilter.java
@@ -0,0 +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() {
+//
+// }
+//
+// }
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..7efc59c6
--- /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);
+//
+// }
+//
+// }
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..0dde3e3e
--- /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);
+// }
+//
+// }
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
new file mode 100644
index 00000000..8d38554b
--- /dev/null
+++ b/modules/service/src/main/java/com/devonfw/module/service/common/impl/header/ServiceHeaderCustomizerTraceSpanId.java
@@ -0,0 +1,107 @@
+package com.devonfw.module.service.common.impl.header;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.devonfw.module.logging.common.api.LoggingConstants;
+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 static final Logger LOG = LoggerFactory.getLogger(ServiceHeaderCustomizerTraceSpanId.class);
+
+ /**
+ * The constructor.
+ */
+ public ServiceHeaderCustomizerTraceSpanId() {
+
+ super();
+ }
+
+ /**
+ * This method is used to create tracer with jaeger tracing.
+ *
+ * @return {@link Tracer}
+ */
+ public Tracer initTracer() {
+
+ 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);
+ //
+ // if (!StringUtils.isEmpty(traceId)) {
+ // context.setHeader(this.traceIdHeaderName, traceId);
+ // }
+ //
+ // if (!StringUtils.isEmpty(spanId)) {
+ // context.setHeader(this.spanIdHeaderName, spanId);
+ // }
+
+ 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());
+
+ } 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();
+ }
+
+ }
+
+}