wy471x opened a new pull request, #7655: URL: https://github.com/apache/shenyu/pull/7655
### Summary Records what the gateway knows about a traced request, so that a trace carries the routing decision and the failure of the request instead of a bare span. This is the second task of #7566. Make sure that: - [X] You have read the [contribution guidelines](https://shenyu.apache.org/community/contributor-guide). - [X] You submit test cases (unit or integration tests) that back your changes. - [X] Your local test passed `./mvnw clean install -Dmaven.javadoc.skip=true`. Run here for the touched modules and their dependencies: `mvn -pl shenyu-plugin/shenyu-plugin-tracing,shenyu-plugin/shenyu-plugin-api,shenyu-web -am install` with checkstyle, RAT and tests enabled (BUILD SUCCESS). The full repository build was not run locally, CI covers it. ### Changes: 1. `SpanAttributesBuilder` (new, `shenyu-plugin/shenyu-plugin-tracing/.../SpanAttributesBuilder.java:63,79,107`) — builds the span name and records the request and outcome attributes. Only bounded values are recorded: the route comes from the metadata of the matched api, the context path from the exchange once the chain has run, and the status code from the response or from the exception the gateway answered the request with. The request path and the query string are left out, and the status description of a failure is limited to its type; the exception event keeps the message and the stack trace, as the OpenTelemetry convention defines. 2. `TracingPlugin` (`.../TracingPlugin.java:78,103`) — keeps the span lifecycle: continues the inbound context or starts a new trace, starts the `SERVER` span per subscription, stores the context, exposes the trace id and ends the span once with the terminal signal. The recording logic moved to the builder, which leaves the plugin with a single responsibility. 3. `ShenyuWebHandler.handle` and `after` (`shenyu-web/.../ShenyuWebHandler.java:114,129,138`) — the chain timing now runs with the terminal signal of the request instead of while the chain is assembled. The reported cost is the duration of the request and the gateway span already exists, so its trace id can be read; previously the timing was logged before the subscription, which is early for both. `Constants.CHAIN_START_TIME` is only read and written by this handler. 4. `TraceIdUtils` (new, `shenyu-plugin/shenyu-plugin-api/.../utils/TraceIdUtils.java:41`) and `ShenyuPlugin.after` (`.../ShenyuPlugin.java:150,153`) — the plugin timing log prints the real span trace id instead of the WebFlux log prefix, and falls back to the log prefix while no span is active, for example when tracing is disabled. 5. `TracingConstants` (`.../TracingConstants.java:68,74`) — the attributes which have a semantic convention key are named after it (`http.request.method`, `http.route`, `http.response.status_code`), and the gateway specific ones use a `shenyu.` prefix. The upstream host is recorded as `shenyu.upstream.host`, because the server of a gateway span is the gateway itself, not the upstream. 6. Span naming — the name is `{method} {route}` as the http conventions ask for, where the route is the path the client registered, so the name does not grow with the request path. A request which did not match a registered api is named by its method only. 7. Outcome handling — a 5xx response is an error span while a 4xx response is not, as the http conventions ask for. A failure records the exception and reports the timeout outcome, which covers the `408` a retried request is answered with, the `504` which wraps a timeout of an upstream call, and a timeout which is only visible in the cause chain of a status exception. A failure whose status is a client error keeps the span status unset, like the same status answered by a response, while a timeout stays an error span whether it is reported by a status or by an exception, because the gateway or the upstream ran out of time. The error type is recorded exactly when the request is an error span, so that it can be used to count failures without counting client errors, and a timeout answered by a response is reported like one which surfaced as an exception. A request which the client cancelled is marked with an attribute. The outcome is written in one place and the span is ended exactl y once, even when recording the outcome fails. ### Test Cases: - `TracingSpanLifecycleTest` (14 tests) — success, client error, client error answered by an exception, client error only visible in the cause chain, server error, thrown exception, timeout, the timeout exception of a protocol plugin, the timeout wrapped into a `504`, the timeout only visible in the cause chain, the timeout answered by a `504` response, the timeout answered by a `408` response, the retried request answered with `408`, and cancellation. Each case asserts that the exporter sees exactly one span for the request, plus the status and the attributes of that path. - `TracingSpanAttributesTest` (8 tests) — the request attributes, the guard which keeps the request path out of the route method attribute of the http like protocols, the route and the span name taken from the registered api, the method only name without a registered api, the context path read once the chain has run with the ShenyuContext fallback, the upstream host and the selector id once the request is routed with a closed set assertion over every attribute the gateway records, and a closed set which may not contain the request path or the query string. - `TracingPluginTest` (18 tests, extended) and `TraceContextExtractorTest` (18 tests) — the inbound span behaviour and the W3C header handling of the first task, with the span name assertion updated to the route based name. - `TraceIdUtilsTest` (2 tests) — the trace id of a traced request and the log prefix fallback. - `ShenyuWebHandlerTest` (9 tests, 3 new) — the chain timing is read with the terminal signal rather than while the chain is assembled, a request which is subscribed again is not reported again, and a logback appender proves that both the chain timing log and the plugin timing log carry the span trace id which a plugin exposed while the request was subscribed. ### Verification - `mvn -pl shenyu-plugin/shenyu-plugin-tracing,shenyu-plugin/shenyu-plugin-api,shenyu-web -am install` → BUILD SUCCESS, module tests: tracing 58, plugin-api 3, shenyu-web 96, no failures. - checkstyle 0 violations and `apache-rat:check` Unapproved 0 for the three modules. - `mvn -pl shenyu-bootstrap -am install -DskipTests` → BUILD SUCCESS, which checks that the tracing plugin and the core handler still integrate with the gateway build. - Not covered by this change: outbound context injection (#7616), OTLP export, sampling and Java agent coexistence (#7612), the integration test and documentation (#7617). Fixes #7613 Part of #7566 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
