Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
* propagation for all
* Reactor pipelines.
*
* <p><b>Migration:</b> New applications should configure an OpenTelemetry SDK through
* {@code OpenTelemetrySdk.builder().setTracerProvider(...).buildAndRegisterGlobal()}, then attach
* {@link OtelTracingMiddleware} to each agent. The middleware reads the globally registered
* OpenTelemetry instance directly, so new code should not call {@link #register(Tracer)}.
*
* @deprecated since 2.0.0. Use {@link OtelTracingMiddleware} instead.
*/
@Deprecated(forRemoval = true, since = "2.0.0")
Expand Down Expand Up @@ -142,6 +147,12 @@ public static synchronized void disableTracingHook() {

private static volatile Tracer tracer = new NoopTracer();

/**
* Registers a tracer for the legacy global tracing path.
*
* <p>New code should register an OpenTelemetry SDK globally and attach {@link
* OtelTracingMiddleware} to the agent instead.
*/
public static void register(Tracer tracer) {
TracerRegistry.tracer = tracer;
if (tracer instanceof NoopTracer) {
Expand Down
63 changes: 60 additions & 3 deletions docs/v2/en/docs/building-blocks/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,80 @@ ReActAgent agent =

When no OpenTelemetry SDK is configured (only the default no-op provider), every hook short-circuits to `next.apply(input)` — near-zero overhead.

Initialise the OpenTelemetry SDK in your process (OTLP exporter, `SdkTracerProvider`, `OpenTelemetrySdk.builder().setTracerProvider(...).buildAndRegisterGlobal()`) and then equip the middleware:
`OtelTracingMiddleware` reads the process-wide `GlobalOpenTelemetry` instance. Applications that export spans themselves need the OpenTelemetry SDK and OTLP exporter in addition to AgentScope. Keep their versions aligned through the OpenTelemetry BOM (the version below matches the one currently used by AgentScope):

```xml
<properties>
<opentelemetry.version>1.61.0</opentelemetry.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>
```

Build and register the SDK once per process before constructing the agent. The optional environment variable in this example can contain a value such as `Basic <base64-credentials>` for a backend that requires an `Authorization` header, including Langfuse:

```java
import io.agentscope.core.ReActAgent;
import io.agentscope.core.tracing.OtelTracingMiddleware;
import java.util.List;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;

String endpoint =
System.getenv().getOrDefault(
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318/v1/traces");
String authorization = System.getenv("OTEL_EXPORTER_OTLP_AUTHORIZATION");

var exporterBuilder = OtlpHttpSpanExporter.builder().setEndpoint(endpoint);
if (authorization != null && !authorization.isBlank()) {
exporterBuilder.addHeader("Authorization", authorization);
}

SdkTracerProvider tracerProvider =
SdkTracerProvider.builder()
.addSpanProcessor(
BatchSpanProcessor.builder(exporterBuilder.build()).build())
.build();

OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();
Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close));

ReActAgent agent =
ReActAgent.builder()
.name("assistant")
.sysPrompt("You are a helpful assistant.")
.model(model)
.toolkit(toolkit)
.middlewares(List.of(new OtelTracingMiddleware()))
.middleware(new OtelTracingMiddleware())
.build();
```

The SDK must be registered before the middleware is used. If your runtime (for example, Spring Boot OpenTelemetry auto-configuration) already registers `GlobalOpenTelemetry`, reuse it and only add the middleware. Do not call the deprecated `TracerRegistry.register(...)` in the new setup. Close the `SdkTracerProvider` during application shutdown so its batch processor can flush pending spans.

Each reply produces a nested span tree with attributes such as agent name, session ID, model name, token counts, tool name, and inputs.

### TaskReminderMiddleware
Expand Down
22 changes: 22 additions & 0 deletions docs/v2/en/docs/change-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,28 @@ Combinations that v1 tolerated (for example, a `USER` message carrying a `ToolUs

`isCheckRunning()` is still callable (returns `false`) and `Builder.checkRunning(boolean)` is still callable (ignored) — both are `@Deprecated`.

#### A.8 `TracerRegistry` + `TelemetryTracer` → `OtelTracingMiddleware`

The old tracing setup registered a framework-level `Tracer` globally:

```java
TracerRegistry.register(TelemetryTracer.builder().tracer(tracer).build());
```

In the current 2.0 source tree, `TelemetryTracer` lives in the `agentscope-extensions-studio` module rather than `agentscope-core`. It remains available for the Studio integration, but adding the Studio extension solely to restore application-wide tracing is not the recommended migration. The `Tracer` interface and `TracerRegistry` are deprecated for removal.

Configure tracing through standard OpenTelemetry components instead:

| Old setup | 2.0 replacement |
|---|---|
| `TelemetryTracer.builder().endpoint(...)` | Build an `OtlpHttpSpanExporter` and attach it to an `SdkTracerProvider` |
| `TelemetryTracer.builder().addHeader(...)` | Call `OtlpHttpSpanExporter.builder().addHeader(...)` |
| `TracerRegistry.register(...)` | Register the SDK with `OpenTelemetrySdk.buildAndRegisterGlobal()` |
| Framework-global tracer | Add `new OtelTracingMiddleware()` to each agent that should emit spans |
| `TracerRegistry.resetToNoop()` / tracer shutdown | Close the application-owned `SdkTracerProvider` during shutdown |

The middleware reads `GlobalOpenTelemetry`, so the SDK must be registered before the agent uses the middleware. See [Middleware — OtelTracingMiddleware](building-blocks/middleware.md#oteltracingmiddleware) for the required dependencies and a complete OTLP example with custom authentication headers.

---

### Part B — Recommended (`@Deprecated(forRemoval = true)`, still callable today)
Expand Down
63 changes: 60 additions & 3 deletions docs/v2/zh/docs/building-blocks/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,23 +71,80 @@ ReActAgent agent =

未配置 OpenTelemetry SDK(只剩默认的 no-op provider)时,所有 hook 会直接短路到 `next.apply(input)`,几乎零开销。

使用前先在进程中初始化 OpenTelemetry SDK(OTLP exporter、`SdkTracerProvider`、`OpenTelemetrySdk.builder().setTracerProvider(...).buildAndRegisterGlobal()`),随后把 `OtelTracingMiddleware` 装到 agent 上即可:
`OtelTracingMiddleware` 从进程级 `GlobalOpenTelemetry` 实例读取配置。应用如果自行导出 span,除了 AgentScope 之外还需要引入 OpenTelemetry SDK 和 OTLP exporter。使用 OpenTelemetry BOM 保持二者版本一致(下列版本与 AgentScope 当前使用的版本一致):

```xml
<properties>
<opentelemetry.version>1.61.0</opentelemetry.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>
```

构建 agent 之前,在每个进程中只构建并注册一次 SDK。下例中的可选环境变量可保存 `Basic <base64-credentials>` 形式的值,供 Langfuse 等要求 `Authorization` header 的后端使用:

```java
import io.agentscope.core.ReActAgent;
import io.agentscope.core.tracing.OtelTracingMiddleware;
import java.util.List;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;

String endpoint =
System.getenv().getOrDefault(
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318/v1/traces");
String authorization = System.getenv("OTEL_EXPORTER_OTLP_AUTHORIZATION");

var exporterBuilder = OtlpHttpSpanExporter.builder().setEndpoint(endpoint);
if (authorization != null && !authorization.isBlank()) {
exporterBuilder.addHeader("Authorization", authorization);
}

SdkTracerProvider tracerProvider =
SdkTracerProvider.builder()
.addSpanProcessor(
BatchSpanProcessor.builder(exporterBuilder.build()).build())
.build();

OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal();
Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close));

ReActAgent agent =
ReActAgent.builder()
.name("assistant")
.sysPrompt("You are a helpful assistant.")
.model(model)
.toolkit(toolkit)
.middlewares(List.of(new OtelTracingMiddleware()))
.middleware(new OtelTracingMiddleware())
.build();
```

必须在 middleware 开始工作前注册 SDK。如果运行环境(例如 Spring Boot 的 OpenTelemetry 自动配置)已经注册了 `GlobalOpenTelemetry`,直接复用并只添加 middleware 即可。新配置不再调用已弃用的 `TracerRegistry.register(...)`。应用关闭时应关闭 `SdkTracerProvider`,让 batch processor 刷新尚未导出的 span。

每次 reply 会产出一棵嵌套 span 树,关键属性包括 agent 名称、session ID、模型名、token 数、工具名与入参等。

### TaskReminderMiddleware
Expand Down
22 changes: 22 additions & 0 deletions docs/v2/zh/docs/change-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,28 @@ v1 中容忍的非法组合(例如 `USER` 携带 `ToolUseBlock`)现在会在

`isCheckRunning()` 仍可调用(返回 `false`),`Builder.checkRunning(boolean)` 仍可调用(被忽略),均已标 `@Deprecated`。

#### A.8 `TracerRegistry` + `TelemetryTracer` → `OtelTracingMiddleware`

旧的 tracing 配置会在框架中全局注册一个 `Tracer`:

```java
TracerRegistry.register(TelemetryTracer.builder().tracer(tracer).build());
```

在当前 2.0 源码中,`TelemetryTracer` 位于 `agentscope-extensions-studio` 模块,而不是 `agentscope-core`。Studio 集成仍会使用它,但仅仅为了恢复应用级 tracing 而引入 Studio 扩展并不是推荐迁移方式。`Tracer` 接口与 `TracerRegistry` 都已标记为待删除。

应用 tracing 应改用标准 OpenTelemetry 组件:

| 旧配置 | 2.0 替代方案 |
|---|---|
| `TelemetryTracer.builder().endpoint(...)` | 构建 `OtlpHttpSpanExporter` 并添加到 `SdkTracerProvider` |
| `TelemetryTracer.builder().addHeader(...)` | 调用 `OtlpHttpSpanExporter.builder().addHeader(...)` |
| `TracerRegistry.register(...)` | 通过 `OpenTelemetrySdk.buildAndRegisterGlobal()` 注册 SDK |
| 框架级全局 tracer | 为每个需要输出 span 的 agent 添加 `new OtelTracingMiddleware()` |
| `TracerRegistry.resetToNoop()` / tracer shutdown | 应用关闭时关闭由应用持有的 `SdkTracerProvider` |

Middleware 从 `GlobalOpenTelemetry` 读取 SDK,因此必须先注册 SDK,再让 agent 使用 middleware。所需依赖、完整 OTLP 配置以及自定义认证 header 示例见 [Middleware — OtelTracingMiddleware](building-blocks/middleware.md#oteltracingmiddleware)。

---

### Part B —— 推荐迁移(`@Deprecated(forRemoval = true)`,仍可调用)
Expand Down
Loading