diff --git a/core/src/main/java/com/volcengine/veadk/trace/OpenTelemetry.java b/core/src/main/java/com/volcengine/veadk/trace/OpenTelemetry.java index 7fe5bba..6d35e1a 100644 --- a/core/src/main/java/com/volcengine/veadk/trace/OpenTelemetry.java +++ b/core/src/main/java/com/volcengine/veadk/trace/OpenTelemetry.java @@ -19,16 +19,20 @@ import com.volcengine.veadk.Version; import com.volcengine.veadk.trace.exporter.AttributeRewritingSpanExporter; import com.volcengine.veadk.trace.exporter.ExporterFactory; +import com.volcengine.veadk.utils.EnvUtil; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.List; +import java.util.Locale; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; public class OpenTelemetry { @@ -48,24 +52,26 @@ public static void initOpenTelemetry(List exporterFactories) { BatchSpanProcessor.builder(rewritingExporter) // 重写一次 .setMaxQueueSize(2048) .setMaxExportBatchSize(512) - .setScheduleDelay(100, TimeUnit.MILLISECONDS) + // Keep the HTTP root and its Agent/LLM/tool children in one export batch. + // A very short delay lets the platform trace merger finalize a partial + // trace before the long-running HTTP root span has ended. + .setScheduleDelay(30, TimeUnit.SECONDS) .setExporterTimeout(30, TimeUnit.SECONDS) .build(); + AttributesBuilder resourceAttributes = + Attributes.builder() + .put("service.name", EnvUtil.getOpenTelemetryServiceName()) + .put("service.version", Version.JAVA_VEADK_VERSION); + addEnvironmentResourceAttributes( + resourceAttributes, EnvUtil.getOpenTelemetryResourceAttributes()); + SdkTracerProvider tracerProvider = SdkTracerProvider.builder() .addSpanProcessor(batchProcessor) .setResource( Resource.getDefault() - .merge( - Resource.create( - Attributes.of( - AttributeKey.stringKey( - "service.name"), - "veadk_tracing", - AttributeKey.stringKey( - "service.version"), - Version.JAVA_VEADK_VERSION)))) + .merge(Resource.create(resourceAttributes.build()))) .build(); OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); @@ -74,4 +80,22 @@ public static void initOpenTelemetry(List exporterFactories) { Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close)); } + + private static void addEnvironmentResourceAttributes( + AttributesBuilder builder, String configuredAttributes) { + if (StringUtils.isBlank(configuredAttributes)) { + return; + } + for (String entry : configuredAttributes.split(",")) { + int separator = entry.indexOf('='); + if (separator <= 0 || separator == entry.length() - 1) { + continue; + } + String key = entry.substring(0, separator).trim(); + String value = entry.substring(separator + 1).trim(); + if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) { + builder.put(AttributeKey.stringKey(key.toLowerCase(Locale.ROOT)), value); + } + } + } } diff --git a/core/src/main/java/com/volcengine/veadk/trace/exporter/APMPlusExporter.java b/core/src/main/java/com/volcengine/veadk/trace/exporter/APMPlusExporter.java new file mode 100644 index 0000000..c4d66ab --- /dev/null +++ b/core/src/main/java/com/volcengine/veadk/trace/exporter/APMPlusExporter.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.volcengine.veadk.trace.exporter; + +import com.volcengine.veadk.utils.EnvUtil; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.apache.commons.lang3.StringUtils; + +/** Exports Agent traces to the APMPlus OTLP endpoint injected by AgentKit Runtime. */ +public class APMPlusExporter implements ExporterFactory { + + @Override + public SpanExporter create() { + String standardEndpoint = EnvUtil.getOpenTelemetryTracesEndpoint(); + if (StringUtils.isNotBlank(standardEndpoint)) { + String protocol = EnvUtil.getOpenTelemetryTracesProtocol(); + if (StringUtils.isBlank(protocol) || "http/protobuf".equalsIgnoreCase(protocol)) { + return OtlpHttpSpanExporter.builder().setEndpoint(standardEndpoint).build(); + } + if ("grpc".equalsIgnoreCase(protocol)) { + return OtlpGrpcSpanExporter.builder().setEndpoint(standardEndpoint).build(); + } + throw new IllegalStateException( + "Unsupported OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: " + protocol); + } + return OtlpGrpcSpanExporter.builder() + .setEndpoint(EnvUtil.getAPMPlusEndpoint()) + .addHeader("x-byteapm-appkey", EnvUtil.getAPMPlusApiKey()) + .build(); + } +} diff --git a/core/src/main/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporter.java b/core/src/main/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporter.java index 2611c2b..ca90059 100644 --- a/core/src/main/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporter.java +++ b/core/src/main/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporter.java @@ -71,10 +71,6 @@ private static class RewrittenSpanData implements SpanData { } private Attributes rewriteAttributes(Attributes attributes) { - if (attributes.isEmpty()) { - return attributes; - } - AttributesBuilder builder = Attributes.builder(); attributes.forEach( (key, value) -> { @@ -123,9 +119,64 @@ private Attributes rewriteAttributes(Attributes attributes) { break; } }); + addPlatformAttributes(builder, delegate.getName(), attributes); return builder.build(); } + private void addPlatformAttributes( + AttributesBuilder builder, String spanName, Attributes originalAttributes) { + if (spanName == null) { + return; + } + if (spanName.startsWith("invocation")) { + builder.put("gen_ai.operation.name", "chain"); + builder.put("gen_ai.span.kind", "workflow"); + } else if (spanName.startsWith("agent_run") || spanName.startsWith("invoke_agent")) { + builder.put("gen_ai.operation.name", "agent"); + builder.put("gen_ai.span.kind", "agent"); + } else if (spanName.startsWith("call_llm")) { + builder.put("gen_ai.operation.name", "chat"); + builder.put("gen_ai.span.kind", "llm"); + copyStringAttribute( + builder, + originalAttributes, + "gcp.vertex.agent.llm_request", + "gen_ai.input"); + copyStringAttribute( + builder, + originalAttributes, + "gcp.vertex.agent.llm_response", + "gen_ai.output"); + } else if (spanName.startsWith("tool_call")) { + builder.put("gen_ai.operation.name", "execute_tool"); + builder.put("gen_ai.span.kind", "tool"); + copyStringAttribute( + builder, + originalAttributes, + "gcp.vertex.agent.tool_call_args", + "gen_ai.input"); + } else if (spanName.startsWith("tool_response")) { + builder.put("gen_ai.operation.name", "execute_tool"); + builder.put("gen_ai.span.kind", "tool"); + copyStringAttribute( + builder, + originalAttributes, + "gcp.vertex.agent.tool_response", + "gen_ai.output"); + } + } + + private void copyStringAttribute( + AttributesBuilder builder, + Attributes originalAttributes, + String sourceKey, + String targetKey) { + String value = originalAttributes.get(AttributeKey.stringKey(sourceKey)); + if (value != null) { + builder.put(targetKey, value); + } + } + @Override public String getName() { return delegate.getName(); diff --git a/core/src/main/java/com/volcengine/veadk/utils/EnvUtil.java b/core/src/main/java/com/volcengine/veadk/utils/EnvUtil.java index 9b08309..b04f718 100644 --- a/core/src/main/java/com/volcengine/veadk/utils/EnvUtil.java +++ b/core/src/main/java/com/volcengine/veadk/utils/EnvUtil.java @@ -25,6 +25,16 @@ public class EnvUtil { private static final String TLS_ENDPOINT = "OBSERVABILITY_OPENTELEMETRY_TLS_ENDPOINT"; private static final String TLS_SERVICE_NAME = "OBSERVABILITY_OPENTELEMETRY_TLS_SERVICE_NAME"; private static final String TLS_REGION = "OBSERVABILITY_OPENTELEMETRY_TLS_REGION"; + private static final String APMPLUS_ENDPOINT = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_ENDPOINT"; + private static final String APMPLUS_API_KEY = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_API_KEY"; + private static final String APMPLUS_SERVICE_NAME = + "OBSERVABILITY_OPENTELEMETRY_APMPLUS_SERVICE_NAME"; + private static final String OTEL_SERVICE_NAME = "OTEL_SERVICE_NAME"; + private static final String OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES"; + private static final String OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = + "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"; + private static final String OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = + "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"; private static final String VIKINGMEM_MEMORY_TYPE = "DATABASE_VIKINGMEM_MEMORY_TYPE"; private static final String MODEL_AGENT_API_KEY = "MODEL_AGENT_API_KEY"; private static final String TOOL_CODE_SANDBOX_URL = "TOOL_CODE_SANDBOX_URL"; @@ -39,6 +49,7 @@ public class EnvUtil { private static final String DEFAULT_VIKING_MEMORY_TYPE = "sys_event_v1"; private static final String DEFAULT_AGENTKIT_SERVICE = "agentkit"; private static final String DEFAULT_AGENTKIT_REGION = "cn-beijing"; + private static final String DEFAULT_AGENTKIT_SCHEME = "https"; private EnvUtil() {} @@ -116,6 +127,48 @@ public static String getTLSRegion() { return tlsRegion; } + public static boolean isAPMPlusConfigured() { + return StringUtils.isNotBlank(getOpenTelemetryTracesEndpoint()) + || (StringUtils.isNotBlank(System.getenv(APMPLUS_ENDPOINT)) + && StringUtils.isNotBlank(System.getenv(APMPLUS_API_KEY))); + } + + public static String getOpenTelemetryTracesEndpoint() { + return System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT); + } + + public static String getOpenTelemetryTracesProtocol() { + return System.getenv(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL); + } + + public static String getAPMPlusEndpoint() { + String endpoint = System.getenv(APMPLUS_ENDPOINT); + if (StringUtils.isBlank(endpoint)) { + throw getIllegalStateException(APMPLUS_ENDPOINT); + } + return endpoint; + } + + public static String getAPMPlusApiKey() { + String apiKey = System.getenv(APMPLUS_API_KEY); + if (StringUtils.isBlank(apiKey)) { + throw getIllegalStateException(APMPLUS_API_KEY); + } + return apiKey; + } + + public static String getOpenTelemetryServiceName() { + String serviceName = System.getenv(APMPLUS_SERVICE_NAME); + if (StringUtils.isBlank(serviceName)) { + serviceName = System.getenv(OTEL_SERVICE_NAME); + } + return StringUtils.isBlank(serviceName) ? "veadk_tracing" : serviceName; + } + + public static String getOpenTelemetryResourceAttributes() { + return System.getenv(OTEL_RESOURCE_ATTRIBUTES); + } + public static String getVikingMmemoryType() { String memoryType = System.getenv(VIKINGMEM_MEMORY_TYPE); if (StringUtils.isBlank(memoryType)) { diff --git a/core/src/test/java/com/volcengine/veadk/trace/exporter/APMPlusExporterTest.java b/core/src/test/java/com/volcengine/veadk/trace/exporter/APMPlusExporterTest.java new file mode 100644 index 0000000..88289eb --- /dev/null +++ b/core/src/test/java/com/volcengine/veadk/trace/exporter/APMPlusExporterTest.java @@ -0,0 +1,28 @@ +package com.volcengine.veadk.trace.exporter; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearEnvironmentVariable; +import org.junitpioneer.jupiter.SetEnvironmentVariable; + +class APMPlusExporterTest { + + @Test + @SetEnvironmentVariable( + key = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", + value = "http://collector/path/v1/traces") + @SetEnvironmentVariable(key = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", value = "http/protobuf") + @ClearEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_ENDPOINT") + @ClearEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_API_KEY") + void create_shouldPreferRuntimeStandardHttpExporter() { + SpanExporter exporter = new APMPlusExporter().create(); + try { + assertThat(exporter).isInstanceOf(OtlpHttpSpanExporter.class); + } finally { + exporter.close(); + } + } +} diff --git a/core/src/test/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporterTest.java b/core/src/test/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporterTest.java index 5c230e6..2fdafd3 100644 --- a/core/src/test/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporterTest.java +++ b/core/src/test/java/com/volcengine/veadk/trace/exporter/AttributeRewritingSpanExporterTest.java @@ -36,6 +36,7 @@ void export_rewritesAttributes_correctly() { .build(); SpanData inputSpan = Mockito.mock(SpanData.class); + when(inputSpan.getName()).thenReturn("call_llm"); when(inputSpan.getAttributes()).thenReturn(input); SpanExporter delegate = Mockito.mock(SpanExporter.class); @@ -70,11 +71,41 @@ void export_rewritesAttributes_correctly() { assertEquals(List.of(true, false), out.get(AttributeKey.booleanArrayKey("normal.barr"))); assertEquals(List.of(1L, 2L), out.get(AttributeKey.longArrayKey("normal.larr"))); assertEquals(List.of(1.1, 2.2), out.get(AttributeKey.doubleArrayKey("normal.darr"))); + assertEquals("chat", out.get(AttributeKey.stringKey("gen_ai.operation.name"))); + assertEquals("llm", out.get(AttributeKey.stringKey("gen_ai.span.kind"))); // Attribute count reflects rewritten set assertEquals(out.size(), rewritten.getTotalAttributeCount()); } + @Test + void export_addsAgentKitPlatformAttributes() { + Attributes input = + Attributes.builder() + .put("gcp.vertex.agent.tool_call_args", "{\"code\":\"print(1)\"}") + .build(); + SpanData inputSpan = Mockito.mock(SpanData.class); + when(inputSpan.getName()).thenReturn("tool_call [run_code]"); + when(inputSpan.getAttributes()).thenReturn(input); + + SpanExporter delegate = Mockito.mock(SpanExporter.class); + when(delegate.export(anyList())).thenReturn(CompletableResultCode.ofSuccess()); + + new AttributeRewritingSpanExporter(delegate).export(List.of(inputSpan)); + + ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); + verify(delegate).export(captor.capture()); + SpanData rewritten = (SpanData) captor.getValue().get(0); + assertEquals( + "execute_tool", + rewritten.getAttributes().get(AttributeKey.stringKey("gen_ai.operation.name"))); + assertEquals( + "tool", rewritten.getAttributes().get(AttributeKey.stringKey("gen_ai.span.kind"))); + assertEquals( + "{\"code\":\"print(1)\"}", + rewritten.getAttributes().get(AttributeKey.stringKey("gen_ai.input"))); + } + @Test void flush_and_shutdown_delegate() { SpanExporter delegate = Mockito.mock(SpanExporter.class); diff --git a/core/src/test/java/com/volcengine/veadk/utils/EnvUtilTest.java b/core/src/test/java/com/volcengine/veadk/utils/EnvUtilTest.java index 60abced..b34e492 100644 --- a/core/src/test/java/com/volcengine/veadk/utils/EnvUtilTest.java +++ b/core/src/test/java/com/volcengine/veadk/utils/EnvUtilTest.java @@ -9,6 +9,38 @@ class EnvUtilTest { + @Test + @SetEnvironmentVariable( + key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_ENDPOINT", + value = "http://apmplus:4317") + @SetEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_API_KEY", value = "test-key") + void apmPlusConfiguration_shouldReadRuntimeEnvironment() { + assertThat(EnvUtil.isAPMPlusConfigured()).isTrue(); + assertThat(EnvUtil.getAPMPlusEndpoint()).isEqualTo("http://apmplus:4317"); + assertThat(EnvUtil.getAPMPlusApiKey()).isEqualTo("test-key"); + } + + @Test + @SetEnvironmentVariable( + key = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT", + value = "http://collector/path/v1/traces") + @SetEnvironmentVariable(key = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", value = "http/protobuf") + @ClearEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_ENDPOINT") + @ClearEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_API_KEY") + void apmPlusConfiguration_shouldPreferStandardOtlpEnvironment() { + assertThat(EnvUtil.isAPMPlusConfigured()).isTrue(); + assertThat(EnvUtil.getOpenTelemetryTracesEndpoint()) + .isEqualTo("http://collector/path/v1/traces"); + assertThat(EnvUtil.getOpenTelemetryTracesProtocol()).isEqualTo("http/protobuf"); + } + + @Test + @ClearEnvironmentVariable(key = "OBSERVABILITY_OPENTELEMETRY_APMPLUS_SERVICE_NAME") + @SetEnvironmentVariable(key = "OTEL_SERVICE_NAME", value = "runtime.agent") + void getOpenTelemetryServiceName_shouldUseRuntimeServiceName() { + assertThat(EnvUtil.getOpenTelemetryServiceName()).isEqualTo("runtime.agent"); + } + @Test @SetEnvironmentVariable(key = "MODEL_AGENT_API_KEY", value = "test_api_key") void getAgentApiKey() { diff --git a/example/src/main/java/com/volcengine/veadk/example/AgentKitTraceConfiguration.java b/example/src/main/java/com/volcengine/veadk/example/AgentKitTraceConfiguration.java new file mode 100644 index 0000000..e59715f --- /dev/null +++ b/example/src/main/java/com/volcengine/veadk/example/AgentKitTraceConfiguration.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.volcengine.veadk.example; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Scope; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.web.filter.OncePerRequestFilter; + +/** Adds the HTTP server parent span required by the AgentKit APMPlus trace merger. */ +@Configuration +public class AgentKitTraceConfiguration { + + @Bean + FilterRegistrationBean agentKitHttpServerTraceFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter( + new OncePerRequestFilter() { + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + String path = request.getRequestURI(); + return !("/run".equals(path) || "/run_sse".equals(path)); + } + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) + throws ServletException, IOException { + String route = request.getRequestURI(); + Span span = + GlobalOpenTelemetry.getTracer("veadk-http") + .spanBuilder(request.getMethod() + " " + route) + .setSpanKind(SpanKind.SERVER) + .setAttribute("http.method", request.getMethod()) + .setAttribute("http.route", route) + .startSpan(); + try (Scope ignored = span.makeCurrent()) { + filterChain.doFilter(request, response); + span.setAttribute("http.status_code", (long) response.getStatus()); + if (response.getStatus() >= 500) { + span.setStatus(StatusCode.ERROR); + } + } catch (RuntimeException | ServletException | IOException exception) { + span.recordException(exception); + span.setStatus(StatusCode.ERROR); + throw exception; + } finally { + span.end(); + } + } + }); + registration.setOrder(Ordered.HIGHEST_PRECEDENCE); + return registration; + } +} diff --git a/example/src/main/java/com/volcengine/veadk/example/AgentKitWeb.java b/example/src/main/java/com/volcengine/veadk/example/AgentKitWeb.java new file mode 100644 index 0000000..1117536 --- /dev/null +++ b/example/src/main/java/com/volcengine/veadk/example/AgentKitWeb.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.volcengine.veadk.example; + +import com.google.adk.web.AdkWebServer; +import com.volcengine.veadk.trace.OpenTelemetry; +import com.volcengine.veadk.trace.exporter.APMPlusExporter; +import com.volcengine.veadk.utils.EnvUtil; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; + +/** AgentKit launcher that enables the platform-provided APMPlus OTLP exporter. */ +public final class AgentKitWeb { + + private static final Logger log = LoggerFactory.getLogger(AgentKitWeb.class); + + private AgentKitWeb() {} + + public static void main(String[] args) { + if (EnvUtil.isAPMPlusConfigured()) { + OpenTelemetry.initOpenTelemetry(List.of(new APMPlusExporter())); + log.info( + "APMPlus OpenTelemetry exporter enabled for service: {}", + EnvUtil.getOpenTelemetryServiceName()); + } else { + log.info("APMPlus OpenTelemetry exporter is not configured; tracing remains local."); + } + System.setProperty("org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE", "10485760"); + SpringApplication application = + new SpringApplication(AdkWebServer.class, AgentKitTraceConfiguration.class); + application.run(args); + log.info("AgentKit ADK Web application started successfully."); + } +}