Adds tracing documentation (#1039)

<!-- 🚀 Thank you for contributing! -->

<!-- Describe your changes clearly and use examples if possible. -->

Adds new Tracing chapter to document API introduced in
https://github.com/vapor/vapor/pull/3253

<!-- When this PR is merged, the title and body will be -->
<!-- used to generate a release automatically. -->
This commit is contained in:
Jay Herron 2024-12-30 10:29:10 -07:00 committed by GitHub
parent 399b55f27f
commit a0d7615b8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 84 additions and 0 deletions

83
docs/advanced/tracing.md Normal file
View File

@ -0,0 +1,83 @@
# Tracing
Tracing is a powerful tool for monitoring and debugging distributed systems. Vapor's tracing API allows developers to easily track request lifecycles, propagate metadata, and integrate with popular backends like OpenTelemetry.
Vapor's tracing API is built on top of [swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing), which means it is compatible with all of swift-distributed-tracing's [backend implementations](https://github.com/apple/swift-distributed-tracing/blob/main/README.md#tracing-backends).
If you are unfamiliar with tracing and spans in Swift, review the [OpenTelemetry Trace documentation](https://opentelemetry.io/docs/concepts/signals/traces/) and [swift-distributed-tracing documentation](https://swiftpackageindex.com/apple/swift-distributed-tracing/main/documentation/tracing).
## TracingMiddleware
To automatically create a fully annotated span for each request, add the `TracingMiddleware` to your application.
```swift
app.middleware.use(TracingMiddleware())
```
To get accurate span measurements and ensure that tracing identifiers are passed along correctly to other services, add this middleware before other middlewares.
## Adding Spans
When adding spans to route handlers, it's ideal for them to be associated with the top-level request span. This is referred to as "span propagation" and can be handled in two different ways: automatic or manual.
### Automatic Propagation
Vapor has support to automatically propagate spans between middleware and route callbacks. To do so, set the `Application.traceAutoPropagation` property to true during configuration.
```swift
app.traceAutoPropagation = true
```
!!! note
Enabling auto-propagation may degrade performance on high-throughput APIs with minimal tracing needs, since request span metadata must be restored for every route handler regardless of whether spans are created.
Then spans may be created in the route closure using the ordinary distributed tracing syntax.
```swift
app.get("fetchAndProcess") { req in
let result = try await fetch()
return try await withSpan("getNameParameter") { _ in
try await process(result)
}
}
```
### Manual Propagation
To avoid the performance implications of automatic propagation, you may manually restore span metadata where necessary. `TracingMiddleware` automatically sets a `Request.serviceContext` property which may be used directly in `withSpan`'s `context` parameter.
```swift
app.get("fetchAndProcess") { req in
let result = try await fetch()
return try await withSpan("getNameParameter", context: req.serviceContext) { _ in
try await process(result)
}
}
```
To restore the span metadata without creating a span, use `ServiceContext.withValue`. This is valuable if you know that downstream async libraries emit their own tracing spans, and those should be nested underneath the parent request span.
```swift
app.get("fetchAndProcess") { req in
try await ServiceContext.withValue(req.serviceContext) {
try await fetch()
return try await process(result)
}
}
```
## NIO Considerations
Because `swift-distributed-tracing` uses [`TaskLocal properties`](https://developer.apple.com/documentation/swift/tasklocal) to propagate, you must manually re-restore the context whenever you cross `NIO EventLoopFuture` boundaries to ensure spans are linked correctly. **This is necessary regardless of whether automatic propagation is enabled**.
```swift
app.get("fetchAndProcessNIO") { req in
withSpan("fetch", context: req.serviceContext) { span in
fetchSomething().map { result in
withSpan("process", context: span.context) { _ in
process(result)
}
}
}
}
```

View File

@ -578,6 +578,7 @@ nav:
- Services: "advanced/services.md"
- Request: "advanced/request.md"
- APNS: "advanced/apns.md"
- Tracing: "advanced/tracing.md"
- Security:
- Authentication: "security/authentication.md"
- Crypto: "security/crypto.md"