You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-27 22:49:15 +02:00
trace: optimize id parsing and string functions (#6791)
With specialized routines, we can avoid the allocation of hex.DecodeString since we know the structure of the IDs. We can use `==` instead of bytes.Equal for arrays. From the Go [spec]: > Array types are comparable if their array element types are comparable. Two > array values are equal if their corresponding element values are equal. The > elements are compared in ascending index order, and comparison stops as soon > as two element values differ (or all elements have been compared). [spec]: https://go.dev/ref/spec#Comparison_operators ### Benchstat To generate: ```sh mkdir private cd sdk go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/base.txt go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/new.txt benchstat ../private/base.txt ../private/new.txt ``` ### Results as of 2025-08-21 ``` goos: darwin goarch: arm64 pkg: go.opentelemetry.io/otel/sdk/trace cpu: Apple M2 Max │ ../private/base.txt │ ../private/new.txt │ │ sec/op │ sec/op vs base │ Truncate/Unlimited-12 0.2274n ± 2% 0.2262n ± 1% ~ (p=0.971 n=10) Truncate/Zero-12 0.3252n ± 1% 0.3267n ± 1% ~ (p=0.171 n=10) Truncate/Short-12 0.2250n ± 1% 0.2247n ± 1% ~ (p=0.897 n=10) Truncate/ASCII-12 0.7280n ± 0% 0.7297n ± 0% ~ (p=0.159 n=10) Truncate/ValidUTF-8-12 1.373n ± 3% 1.376n ± 9% ~ (p=0.084 n=10) Truncate/InvalidUTF-8-12 9.605n ± 4% 9.724n ± 7% ~ (p=0.289 n=10) Truncate/MixedUTF-8-12 17.54n ± 2% 17.56n ± 1% ~ (p=0.839 n=10) RecordingSpanSetAttributes/WithLimit/false-12 2.046µ ± 1% 2.055µ ± 1% ~ (p=0.383 n=10) RecordingSpanSetAttributes/WithLimit/true-12 4.329µ ± 0% 4.335µ ± 0% ~ (p=0.108 n=10) SpanEnd-12 90.10n ± 30% 102.26n ± 20% ~ (p=0.143 n=10) TraceStart/with_a_simple_span-12 300.4n ± 7% 290.1n ± 4% ~ (p=0.353 n=10) TraceStart/with_several_links-12 416.8n ± 3% 407.0n ± 2% -2.34% (p=0.014 n=10) TraceStart/with_attributes-12 460.6n ± 1% 446.5n ± 2% -3.04% (p=0.000 n=10) SpanLimits/AttributeValueLengthLimit-12 4.425µ ± 3% 4.254µ ± 1% -3.86% (p=0.000 n=10) SpanLimits/AttributeCountLimit-12 4.138µ ± 1% 3.986µ ± 1% -3.65% (p=0.000 n=10) SpanLimits/EventCountLimit-12 3.926µ ± 1% 3.780µ ± 1% -3.73% (p=0.000 n=10) SpanLimits/LinkCountLimit-12 3.879µ ± 1% 3.738µ ± 1% -3.64% (p=0.000 n=10) SpanLimits/AttributePerEventCountLimit-12 4.249µ ± 1% 4.216µ ± 1% ~ (p=0.066 n=10) SpanLimits/AttributePerLinkCountLimit-12 4.175µ ± 1% 4.226µ ± 0% +1.22% (p=0.037 n=10) SpanSetAttributesOverCapacity-12 1.648µ ± 0% 1.635µ ± 6% ~ (p=0.382 n=10) StartEndSpan/AlwaysSample-12 305.3n ± 1% 298.9n ± 2% -2.10% (p=0.045 n=10) StartEndSpan/NeverSample-12 137.0n ± 0% 132.9n ± 0% -3.03% (p=0.000 n=10) SpanWithAttributes_4/AlwaysSample-12 516.3n ± 1% 507.6n ± 0% -1.68% (p=0.000 n=10) SpanWithAttributes_4/NeverSample-12 228.7n ± 1% 221.8n ± 1% -3.00% (p=0.000 n=10) SpanWithAttributes_8/AlwaysSample-12 706.6n ± 1% 689.0n ± 0% -2.50% (p=0.000 n=10) SpanWithAttributes_8/NeverSample-12 313.0n ± 1% 307.1n ± 0% -1.87% (p=0.000 n=10) SpanWithAttributes_all/AlwaysSample-12 565.0n ± 1% 560.8n ± 0% -0.75% (p=0.002 n=10) SpanWithAttributes_all/NeverSample-12 251.2n ± 1% 247.5n ± 4% -1.45% (p=0.034 n=10) SpanWithAttributes_all_2x/AlwaysSample-12 823.4n ± 1% 812.0n ± 1% -1.39% (p=0.028 n=10) SpanWithAttributes_all_2x/NeverSample-12 368.8n ± 1% 360.6n ± 0% -2.22% (p=0.000 n=10) SpanWithEvents_4/AlwaysSample-12 709.3n ± 0% 699.6n ± 0% -1.37% (p=0.000 n=10) SpanWithEvents_4/NeverSample-12 139.4n ± 0% 137.0n ± 0% -1.72% (p=0.000 n=10) SpanWithEvents_8/AlwaysSample-12 1.091µ ± 1% 1.073µ ± 0% -1.60% (p=0.000 n=10) SpanWithEvents_8/NeverSample-12 142.1n ± 0% 140.1n ± 0% -1.41% (p=0.000 n=10) SpanWithEvents_WithStackTrace/AlwaysSample-12 424.6n ± 0% 417.9n ± 0% -1.57% (p=0.000 n=10) SpanWithEvents_WithStackTrace/NeverSample-12 151.3n ± 0% 148.1n ± 0% -2.15% (p=0.000 n=10) SpanWithEvents_WithTimestamp/AlwaysSample-12 412.6n ± 0% 407.6n ± 0% -1.19% (p=0.000 n=10) SpanWithEvents_WithTimestamp/NeverSample-12 174.5n ± 0% 172.7n ± 0% -1.03% (p=0.000 n=10) TraceIDFromHex-12 57.22n ± 0% 15.88n ± 0% -72.25% (p=0.000 n=10) SpanIDFromHex-12 35.000n ± 0% 8.676n ± 0% -75.21% (p=0.000 n=10) TraceID_DotString-12 42.39n ± 0% 24.22n ± 0% -42.85% (p=0.000 n=10) SpanID_DotString-12 31.41n ± 0% 16.98n ± 0% -45.94% (p=0.000 n=10) SpanProcessorOnEnd/batch:_10,_spans:_10-12 164.0n ± 0% 163.8n ± 0% -0.12% (p=0.021 n=10) SpanProcessorOnEnd/batch:_10,_spans:_100-12 1.640µ ± 0% 1.637µ ± 0% -0.18% (p=0.016 n=10) SpanProcessorOnEnd/batch:_100,_spans:_10-12 164.0n ± 0% 163.7n ± 0% -0.18% (p=0.000 n=10) SpanProcessorOnEnd/batch:_100,_spans:_100-12 1.641µ ± 0% 1.636µ ± 0% -0.30% (p=0.000 n=10) SpanProcessorVerboseLogging-12 6.413µ ± 2% 6.444µ ± 5% ~ (p=0.424 n=10) geomean 204.9n 187.0n -8.69% │ ../private/base.txt │ ../private/new.txt │ │ B/op │ B/op vs base │ Truncate/Unlimited-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/Zero-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/Short-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/ASCII-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/ValidUTF-8-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/InvalidUTF-8-12 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=10) ¹ Truncate/MixedUTF-8-12 32.00 ± 0% 32.00 ± 0% ~ (p=1.000 n=10) ¹ RecordingSpanSetAttributes/WithLimit/false-12 6.891Ki ± 0% 6.891Ki ± 0% ~ (p=1.000 n=10) ¹ RecordingSpanSetAttributes/WithLimit/true-12 7.023Ki ± 0% 7.023Ki ± 0% ~ (p=1.000 n=10) ¹ SpanEnd-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_a_simple_span-12 528.0 ± 0% 528.0 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_several_links-12 704.0 ± 0% 704.0 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_attributes-12 784.0 ± 0% 784.0 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributeValueLengthLimit-12 10.56Ki ± 0% 10.56Ki ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributeCountLimit-12 9.844Ki ± 0% 9.844Ki ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/EventCountLimit-12 9.422Ki ± 0% 9.422Ki ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/LinkCountLimit-12 9.031Ki ± 0% 9.031Ki ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributePerEventCountLimit-12 10.47Ki ± 0% 10.47Ki ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributePerLinkCountLimit-12 10.47Ki ± 0% 10.47Ki ± 0% ~ (p=1.000 n=10) ¹ SpanSetAttributesOverCapacity-12 592.0 ± 0% 592.0 ± 0% ~ (p=1.000 n=10) ¹ StartEndSpan/AlwaysSample-12 528.0 ± 0% 528.0 ± 0% ~ (p=1.000 n=10) ¹ StartEndSpan/NeverSample-12 144.0 ± 0% 144.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_4/AlwaysSample-12 1.016Ki ± 0% 1.016Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_4/NeverSample-12 400.0 ± 0% 400.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_8/AlwaysSample-12 1.516Ki ± 0% 1.516Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_8/NeverSample-12 656.0 ± 0% 656.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all/AlwaysSample-12 1.141Ki ± 0% 1.141Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all/NeverSample-12 464.0 ± 0% 464.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all_2x/AlwaysSample-12 1.891Ki ± 0% 1.891Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all_2x/NeverSample-12 848.0 ± 0% 848.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_4/AlwaysSample-12 1.016Ki ± 0% 1.016Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_4/NeverSample-12 144.0 ± 0% 144.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_8/AlwaysSample-12 1.641Ki ± 0% 1.641Ki ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_8/NeverSample-12 144.0 ± 0% 144.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithStackTrace/AlwaysSample-12 624.0 ± 0% 624.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithStackTrace/NeverSample-12 160.0 ± 0% 160.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithTimestamp/AlwaysSample-12 648.0 ± 0% 648.0 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithTimestamp/NeverSample-12 184.0 ± 0% 184.0 ± 0% ~ (p=1.000 n=10) ¹ TraceIDFromHex-12 16.00 ± 0% 0.00 ± 0% -100.00% (p=0.000 n=10) SpanIDFromHex-12 8.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) SpanProcessorOnEnd/batch:_10,_spans:_10-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_10,_spans:_100-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_100,_spans:_10-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_100,_spans:_100-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorVerboseLogging-12 9.562Ki ± 0% 9.562Ki ± 0% ~ (p=1.000 n=10) ¹ geomean ² ? ² ³ ¹ all samples are equal ² summaries must be >0 to compute geomean ³ ratios must be >0 to compute geomean │ ../private/base.txt │ ../private/new.txt │ │ allocs/op │ allocs/op vs base │ Truncate/Unlimited-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/Zero-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/Short-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/ASCII-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/ValidUTF-8-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/InvalidUTF-8-12 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ Truncate/MixedUTF-8-12 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ RecordingSpanSetAttributes/WithLimit/false-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ RecordingSpanSetAttributes/WithLimit/true-12 10.00 ± 0% 10.00 ± 0% ~ (p=1.000 n=10) ¹ SpanEnd-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_a_simple_span-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_several_links-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ TraceStart/with_attributes-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributeValueLengthLimit-12 41.00 ± 0% 41.00 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributeCountLimit-12 38.00 ± 0% 38.00 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/EventCountLimit-12 35.00 ± 0% 35.00 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/LinkCountLimit-12 35.00 ± 0% 35.00 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributePerEventCountLimit-12 38.00 ± 0% 38.00 ± 0% ~ (p=1.000 n=10) ¹ SpanLimits/AttributePerLinkCountLimit-12 38.00 ± 0% 38.00 ± 0% ~ (p=1.000 n=10) ¹ SpanSetAttributesOverCapacity-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ StartEndSpan/AlwaysSample-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ StartEndSpan/NeverSample-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_4/AlwaysSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_4/NeverSample-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_8/AlwaysSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_8/NeverSample-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all/AlwaysSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all/NeverSample-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all_2x/AlwaysSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithAttributes_all_2x/NeverSample-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_4/AlwaysSample-12 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_4/NeverSample-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_8/AlwaysSample-12 6.000 ± 0% 6.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_8/NeverSample-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithStackTrace/AlwaysSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithStackTrace/NeverSample-12 3.000 ± 0% 3.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithTimestamp/AlwaysSample-12 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=10) ¹ SpanWithEvents_WithTimestamp/NeverSample-12 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹ TraceIDFromHex-12 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) SpanIDFromHex-12 1.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10) SpanProcessorOnEnd/batch:_10,_spans:_10-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_10,_spans:_100-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_100,_spans:_10-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorOnEnd/batch:_100,_spans:_100-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ SpanProcessorVerboseLogging-12 36.00 ± 0% 36.00 ± 0% ~ (p=1.000 n=10) ¹ geomean ² ? ² ³ ¹ all samples are equal ² summaries must be >0 to compute geomean ³ ratios must be >0 to compute geomean ``` Issue: #6721
This commit is contained in:
@@ -63,6 +63,7 @@ The next release will require at least [Go 1.24].
|
||||
- Change `AssertEqual` in `go.opentelemetry.io/otel/log/logtest` to accept `TestingT` in order to support benchmarks and fuzz tests. (#6908)
|
||||
- Change `SDKProcessorLogQueueCapacity`, `SDKProcessorLogQueueSize`, `SDKProcessorSpanQueueSize`, and `SDKProcessorSpanQueueCapacity` in `go.opentelemetry.io/otel/semconv/v1.36.0/otelconv` to use a `Int64ObservableUpDownCounter`. (#7041)
|
||||
- Change `DefaultExemplarReservoirProviderSelector` in `go.opentelemetry.io/otel/sdk/metric` to use `runtime.GOMAXPROCS(0)` instead of `runtime.NumCPU()` for the `FixedSizeReservoirProvider` default size. (#7094)
|
||||
- Optimize `TraceIDFromHex` and `SpanIDFromHex` in `go.opentelemetry.io/otel/sdk/trace`. (#6791)
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
||||
@@ -293,6 +293,45 @@ func BenchmarkSpanWithEvents_WithTimestamp(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkTraceIDFromHex(b *testing.B) {
|
||||
want := trace.TraceID{
|
||||
0xde,
|
||||
0xad,
|
||||
0xbe,
|
||||
0xef,
|
||||
0x01,
|
||||
0x23,
|
||||
0x45,
|
||||
0x67,
|
||||
0x89,
|
||||
0xab,
|
||||
0xcd,
|
||||
0xef,
|
||||
0x01,
|
||||
0x23,
|
||||
0x45,
|
||||
0x67,
|
||||
}
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
got, _ := trace.TraceIDFromHex("deadbeef0123456789abcdef01234567")
|
||||
if got != want {
|
||||
b.Fatalf("got = %q want = %q", got.String(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSpanIDFromHex(b *testing.B) {
|
||||
want := trace.SpanID{0xde, 0xad, 0xbe, 0xef, 0x01, 0x23, 0x45, 0x67}
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
got, _ := trace.SpanIDFromHex("deadbeef01234567")
|
||||
if got != want {
|
||||
b.Fatalf("got = %q want = %q", got.String(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTraceID_DotString(b *testing.B) {
|
||||
t, _ := trace.TraceIDFromHex("0000000000000001000000000000002a")
|
||||
sc := trace.NewSpanContext(trace.SpanContextConfig{TraceID: t})
|
||||
|
||||
38
trace/hex.go
Normal file
38
trace/hex.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package trace // import "go.opentelemetry.io/otel/trace"
|
||||
|
||||
const (
|
||||
// hexLU is a hex lookup table of the 16 lowercase hex digits.
|
||||
// The character values of the string are indexed at the equivalent
|
||||
// hexadecimal value they represent. This table efficiently encodes byte data
|
||||
// into a string representation of hexadecimal.
|
||||
hexLU = "0123456789abcdef"
|
||||
|
||||
// hexRev is a reverse hex lookup table for lowercase hex digits.
|
||||
// The table is efficiently decodes a hexadecimal string into bytes.
|
||||
// Valid hexadecimal characters are indexed at their respective values. All
|
||||
// other invalid ASCII characters are represented with '\xff'.
|
||||
//
|
||||
// The '\xff' character is used as invalid because no valid character has
|
||||
// the upper 4 bits set. Meaning, an efficient validation can be performed
|
||||
// over multiple character parsing by checking these bits remain zero.
|
||||
hexRev = "" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
)
|
||||
138
trace/trace.go
138
trace/trace.go
@@ -4,8 +4,6 @@
|
||||
package trace // import "go.opentelemetry.io/otel/trace"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
@@ -41,18 +39,44 @@ var (
|
||||
// IsValid reports whether the trace TraceID is valid. A valid trace ID does
|
||||
// not consist of zeros only.
|
||||
func (t TraceID) IsValid() bool {
|
||||
return !bytes.Equal(t[:], nilTraceID[:])
|
||||
return t != nilTraceID
|
||||
}
|
||||
|
||||
// MarshalJSON implements a custom marshal function to encode TraceID
|
||||
// as a hex string.
|
||||
func (t TraceID) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.String())
|
||||
b := [32 + 2]byte{0: '"', 33: '"'}
|
||||
h := t.hexBytes()
|
||||
copy(b[1:], h[:])
|
||||
return b[:], nil
|
||||
}
|
||||
|
||||
// String returns the hex string representation form of a TraceID.
|
||||
func (t TraceID) String() string {
|
||||
return hex.EncodeToString(t[:])
|
||||
h := t.hexBytes()
|
||||
return string(h[:])
|
||||
}
|
||||
|
||||
// hexBytes returns the hex string representation form of a TraceID.
|
||||
func (t TraceID) hexBytes() [32]byte {
|
||||
return [32]byte{
|
||||
hexLU[t[0x0]>>4], hexLU[t[0x0]&0xf],
|
||||
hexLU[t[0x1]>>4], hexLU[t[0x1]&0xf],
|
||||
hexLU[t[0x2]>>4], hexLU[t[0x2]&0xf],
|
||||
hexLU[t[0x3]>>4], hexLU[t[0x3]&0xf],
|
||||
hexLU[t[0x4]>>4], hexLU[t[0x4]&0xf],
|
||||
hexLU[t[0x5]>>4], hexLU[t[0x5]&0xf],
|
||||
hexLU[t[0x6]>>4], hexLU[t[0x6]&0xf],
|
||||
hexLU[t[0x7]>>4], hexLU[t[0x7]&0xf],
|
||||
hexLU[t[0x8]>>4], hexLU[t[0x8]&0xf],
|
||||
hexLU[t[0x9]>>4], hexLU[t[0x9]&0xf],
|
||||
hexLU[t[0xa]>>4], hexLU[t[0xa]&0xf],
|
||||
hexLU[t[0xb]>>4], hexLU[t[0xb]&0xf],
|
||||
hexLU[t[0xc]>>4], hexLU[t[0xc]&0xf],
|
||||
hexLU[t[0xd]>>4], hexLU[t[0xd]&0xf],
|
||||
hexLU[t[0xe]>>4], hexLU[t[0xe]&0xf],
|
||||
hexLU[t[0xf]>>4], hexLU[t[0xf]&0xf],
|
||||
}
|
||||
}
|
||||
|
||||
// SpanID is a unique identity of a span in a trace.
|
||||
@@ -66,18 +90,35 @@ var (
|
||||
// IsValid reports whether the SpanID is valid. A valid SpanID does not consist
|
||||
// of zeros only.
|
||||
func (s SpanID) IsValid() bool {
|
||||
return !bytes.Equal(s[:], nilSpanID[:])
|
||||
return s != nilSpanID
|
||||
}
|
||||
|
||||
// MarshalJSON implements a custom marshal function to encode SpanID
|
||||
// as a hex string.
|
||||
func (s SpanID) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.String())
|
||||
b := [16 + 2]byte{0: '"', 17: '"'}
|
||||
h := s.hexBytes()
|
||||
copy(b[1:], h[:])
|
||||
return b[:], nil
|
||||
}
|
||||
|
||||
// String returns the hex string representation form of a SpanID.
|
||||
func (s SpanID) String() string {
|
||||
return hex.EncodeToString(s[:])
|
||||
b := s.hexBytes()
|
||||
return string(b[:])
|
||||
}
|
||||
|
||||
func (s SpanID) hexBytes() [16]byte {
|
||||
return [16]byte{
|
||||
hexLU[s[0]>>4], hexLU[s[0]&0xf],
|
||||
hexLU[s[1]>>4], hexLU[s[1]&0xf],
|
||||
hexLU[s[2]>>4], hexLU[s[2]&0xf],
|
||||
hexLU[s[3]>>4], hexLU[s[3]&0xf],
|
||||
hexLU[s[4]>>4], hexLU[s[4]&0xf],
|
||||
hexLU[s[5]>>4], hexLU[s[5]&0xf],
|
||||
hexLU[s[6]>>4], hexLU[s[6]&0xf],
|
||||
hexLU[s[7]>>4], hexLU[s[7]&0xf],
|
||||
}
|
||||
}
|
||||
|
||||
// TraceIDFromHex returns a TraceID from a hex string if it is compliant with
|
||||
@@ -85,59 +126,52 @@ func (s SpanID) String() string {
|
||||
// https://www.w3.org/TR/trace-context/#trace-id
|
||||
// nolint:revive // revive complains about stutter of `trace.TraceIDFromHex`.
|
||||
func TraceIDFromHex(h string) (TraceID, error) {
|
||||
t := TraceID{}
|
||||
if len(h) != 32 {
|
||||
return t, errInvalidTraceIDLength
|
||||
return [16]byte{}, errInvalidTraceIDLength
|
||||
}
|
||||
|
||||
if err := decodeHex(h, t[:]); err != nil {
|
||||
return t, err
|
||||
var b [16]byte
|
||||
invalidMark := byte(0)
|
||||
for i := 0; i < len(h); i += 4 {
|
||||
b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]]
|
||||
b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]]
|
||||
invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]]
|
||||
}
|
||||
|
||||
if !t.IsValid() {
|
||||
return t, errNilTraceID
|
||||
// If the upper 4 bits of any byte are not zero, there was an invalid hex
|
||||
// character since invalid hex characters are 0xff in hexRev.
|
||||
if invalidMark&0xf0 != 0 {
|
||||
return [16]byte{}, errInvalidHexID
|
||||
}
|
||||
return t, nil
|
||||
// If we didn't set any bits, then h was all zeros.
|
||||
if invalidMark == 0 {
|
||||
return [16]byte{}, errNilTraceID
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// SpanIDFromHex returns a SpanID from a hex string if it is compliant
|
||||
// with the w3c trace-context specification.
|
||||
// See more at https://www.w3.org/TR/trace-context/#parent-id
|
||||
func SpanIDFromHex(h string) (SpanID, error) {
|
||||
s := SpanID{}
|
||||
if len(h) != 16 {
|
||||
return s, errInvalidSpanIDLength
|
||||
return [8]byte{}, errInvalidSpanIDLength
|
||||
}
|
||||
|
||||
if err := decodeHex(h, s[:]); err != nil {
|
||||
return s, err
|
||||
var b [8]byte
|
||||
invalidMark := byte(0)
|
||||
for i := 0; i < len(h); i += 4 {
|
||||
b[i/2] = (hexRev[h[i]] << 4) | hexRev[h[i+1]]
|
||||
b[i/2+1] = (hexRev[h[i+2]] << 4) | hexRev[h[i+3]]
|
||||
invalidMark |= hexRev[h[i]] | hexRev[h[i+1]] | hexRev[h[i+2]] | hexRev[h[i+3]]
|
||||
}
|
||||
|
||||
if !s.IsValid() {
|
||||
return s, errNilSpanID
|
||||
// If the upper 4 bits of any byte are not zero, there was an invalid hex
|
||||
// character since invalid hex characters are 0xff in hexRev.
|
||||
if invalidMark&0xf0 != 0 {
|
||||
return [8]byte{}, errInvalidHexID
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func decodeHex(h string, b []byte) error {
|
||||
for _, r := range h {
|
||||
switch {
|
||||
case 'a' <= r && r <= 'f':
|
||||
continue
|
||||
case '0' <= r && r <= '9':
|
||||
continue
|
||||
default:
|
||||
return errInvalidHexID
|
||||
}
|
||||
// If we didn't set any bits, then h was all zeros.
|
||||
if invalidMark == 0 {
|
||||
return [8]byte{}, errNilSpanID
|
||||
}
|
||||
|
||||
decoded, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(b, decoded)
|
||||
return nil
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// TraceFlags contains flags that can be set on a SpanContext.
|
||||
@@ -160,12 +194,20 @@ func (tf TraceFlags) WithSampled(sampled bool) TraceFlags { // nolint:revive //
|
||||
// MarshalJSON implements a custom marshal function to encode TraceFlags
|
||||
// as a hex string.
|
||||
func (tf TraceFlags) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(tf.String())
|
||||
b := [2 + 2]byte{0: '"', 3: '"'}
|
||||
h := tf.hexBytes()
|
||||
copy(b[1:], h[:])
|
||||
return b[:], nil
|
||||
}
|
||||
|
||||
// String returns the hex string representation form of TraceFlags.
|
||||
func (tf TraceFlags) String() string {
|
||||
return hex.EncodeToString([]byte{byte(tf)})
|
||||
h := tf.hexBytes()
|
||||
return string(h[:])
|
||||
}
|
||||
|
||||
func (tf TraceFlags) hexBytes() [2]byte {
|
||||
return [2]byte{hexLU[tf>>4], hexLU[tf&0xf]}
|
||||
}
|
||||
|
||||
// SpanContextConfig contains mutable fields usable for constructing
|
||||
|
||||
Reference in New Issue
Block a user