diff --git a/server/skillhub-app/pom.xml b/server/skillhub-app/pom.xml
index 224e42d11..428982a51 100644
--- a/server/skillhub-app/pom.xml
+++ b/server/skillhub-app/pom.xml
@@ -175,7 +175,22 @@
default-test
- process-global-diagnostics
+ process-global-diagnostics,process-global-otel-context
+
+
+
+
+ isolated-otel-context
+ test
+
+ process-global-otel-context
+
+ **/BusinessLogs*Test.java
+
+ false
+ 1
+ false
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsCollectorTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsCollectorTest.java
index dcf5f14e2..898e77f69 100644
--- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsCollectorTest.java
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsCollectorTest.java
@@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/** Actual production configuration sends protobuf over HTTP to a pinned real Collector/file sink. */
@Testcontainers
+@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsCollectorTest {
@Container
static final GenericContainer> COLLECTOR = new GenericContainer<>("otel/opentelemetry-collector-contrib:0.111.0")
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsHttpTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsHttpTest.java
index e7b31b3cc..ee1580d07 100644
--- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsHttpTest.java
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsHttpTest.java
@@ -21,6 +21,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
+@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsHttpTest {
@Test
void truncatedErrorBodyCannotPermanentlyExhaustAdmission() throws Exception {
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsPipelineTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsPipelineTest.java
index f0f94df33..cdba9688e 100644
--- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsPipelineTest.java
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsPipelineTest.java
@@ -20,6 +20,7 @@ import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
+@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsPipelineTest {
@ParameterizedTest
@ValueSource(booleans = {true, false})
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsProducerPostgresTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsProducerPostgresTest.java
index 22d182dc8..e4cdb2503 100644
--- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsProducerPostgresTest.java
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsProducerPostgresTest.java
@@ -64,6 +64,7 @@ import static org.mockito.Mockito.when;
SkillDownloadService.class, SkillSlugResolutionService.class, ReviewService.class, PromotionService.class,
ReviewPermissionChecker.class, BusinessLogsProducerPostgresTest.Configuration.class})
@Transactional(propagation = Propagation.NOT_SUPPORTED)
+@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsProducerPostgresTest {
@Container
static final PostgreSQLContainer> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine")
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTracingCoexistenceTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTracingCoexistenceTest.java
new file mode 100644
index 000000000..d786bbd01
--- /dev/null
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTracingCoexistenceTest.java
@@ -0,0 +1,47 @@
+package com.iflytek.skillhub.observability.business;
+
+import com.iflytek.skillhub.observability.tracing.SkillHubTracingConfiguration;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import io.micrometer.tracing.Tracer;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.slf4j.MDC;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Production configurations must coexist in the same startup, before any raw test context. */
+@Tag("process-global-otel-context")
+class BusinessLogsTracingCoexistenceTest {
+ @Configuration(proxyBeanMethods = false)
+ @EnableAutoConfiguration
+ @Import({SkillHubTracingConfiguration.class, BusinessLogsConfiguration.class})
+ static class Application {}
+
+ @Test
+ void enablingBusinessLogsPreservesTraceAndSpanCorrelation() {
+ new ApplicationContextRunner().withUserConfiguration(Application.class)
+ .withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)
+ .withPropertyValues("spring.flyway.enabled=false", "spring.jpa.hibernate.ddl-auto=none",
+ "skillhub.observability.tracing-mode=otel-sdk",
+ "management.tracing.sampling.probability=1",
+ "skillhub.observability.business-logs.enabled=true",
+ "skillhub.observability.business-logs.endpoint=http://127.0.0.1:4318/v1/logs")
+ .run(context -> {
+ assertThat(context).hasNotFailed();
+ assertThat(context).hasSingleBean(BusinessLogsPipeline.class);
+ Tracer tracer = context.getBean(Tracer.class);
+ var span = tracer.nextSpan().name("business-logs-coexistence").start();
+ try (var ignored = tracer.withSpan(span)) {
+ assertThat(MDC.get("traceId")).isEqualTo(span.context().traceId()).hasSize(32);
+ assertThat(MDC.get("spanId")).isEqualTo(span.context().spanId()).hasSize(16);
+ } finally {
+ span.end();
+ MDC.clear();
+ }
+ });
+ }
+}
diff --git a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTransactionTest.java b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTransactionTest.java
index c8f800de7..6e19a6744 100644
--- a/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTransactionTest.java
+++ b/server/skillhub-app/src/test/java/com/iflytek/skillhub/observability/business/BusinessLogsTransactionTest.java
@@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;
@Testcontainers
+@org.junit.jupiter.api.Tag("process-global-otel-context")
class BusinessLogsTransactionTest {
@Container
static final PostgreSQLContainer> POSTGRES = new PostgreSQLContainer<>("postgres:16-alpine")