-
Notifications
You must be signed in to change notification settings - Fork 0
Add Vapor tracing middleware (SignozVapor) #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4f749dd
be09ecb
6957f1e
2c6eefa
cc73520
a6e1c27
ca8cdfc
e940fbd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| @preconcurrency import OpenTelemetryApi | ||
|
|
||
| /// Shared W3C Trace Context parsing and serialization. | ||
| /// | ||
| /// Used by both `OTelTracingBridge` (for gRPC distributed tracing) and | ||
| /// `SignozTracingMiddleware` (for Vapor HTTP tracing). | ||
| public enum W3CTraceContext { | ||
|
|
||
| public static let traceparentKey = "traceparent" | ||
| public static let tracestateKey = "tracestate" | ||
|
|
||
| /// Parse W3C `traceparent` and optional `tracestate` header values into a `SpanContext`. | ||
| public static func parse(traceparent: String, tracestate: String? = nil) -> SpanContext? { | ||
| // W3C spec: reject only version "ff"; accept unknown future versions | ||
| // for forward compatibility (the first 55 chars are guaranteed stable). | ||
| // Future versions may append extra `-` delimited fields, so require >= 4 parts. | ||
| let parts = traceparent.split(separator: "-") | ||
| guard parts.count >= 4, parts[0] != "ff" else { | ||
| return nil | ||
| } | ||
|
Comment on lines
+17
to
+20
|
||
|
|
||
| let traceId = TraceId(fromHexString: String(parts[1])) | ||
| let spanId = SpanId(fromHexString: String(parts[2])) | ||
| guard traceId.isValid, spanId.isValid else { | ||
| return nil | ||
| } | ||
|
|
||
| let sampled = UInt8(String(parts[3]), radix: 16).map { $0 & 0x01 != 0 } ?? false | ||
| var traceFlags = TraceFlags() | ||
| traceFlags.setIsSampled(sampled) | ||
|
|
||
| var state = TraceState() | ||
| if let tracestateHeader = tracestate { | ||
| for entry in tracestateHeader.split(separator: ",") { | ||
| let kv = entry.split(separator: "=", maxSplits: 1) | ||
| if kv.count == 2 { | ||
| state = state.setting( | ||
| key: String(kv[0]).trimmingCharacters(in: .whitespaces), | ||
| value: String(kv[1]).trimmingCharacters(in: .whitespaces) | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return SpanContext.createFromRemoteParent( | ||
| traceId: traceId, | ||
| spanId: spanId, | ||
| traceFlags: traceFlags, | ||
| traceState: state | ||
| ) | ||
| } | ||
|
|
||
| /// Serialize a `SpanContext` into W3C `traceparent` and optional `tracestate` header values. | ||
| public static func serialize(_ spanContext: SpanContext) -> (traceparent: String, tracestate: String?) { | ||
| let flags = spanContext.traceFlags.sampled ? "01" : "00" | ||
| let traceparent = "00-\(spanContext.traceId.hexString)-\(spanContext.spanId.hexString)-\(flags)" | ||
|
|
||
| var tracestate: String? = nil | ||
| if !spanContext.traceState.entries.isEmpty { | ||
| tracestate = spanContext.traceState.entries | ||
| .map { "\($0.key)=\($0.value)" } | ||
| .joined(separator: ",") | ||
| } | ||
|
|
||
| return (traceparent, tracestate) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.