This PR refactors the internal slice conversion helpers in
`attribute/internal` to use generics and adds explicit short-length fast
paths for slice-backed attribute values.
The main changes are:
- replace the old type-specific internal helpers with generic
`SliceValue[T]` and `AsSlice[T]`
- preserve the comparable-array storage model used by `Value` and
`KeyValue`
- add fixed-size fast paths for lengths `0..3`
- add a matching short-length fast path in `IntSliceValue` before
falling back to `[]int64` conversion
- keep reflection as the fallback for larger slice lengths
- keep the existing `Value.As*Slice()` methods in `attribute` as thin
wrappers over the generic internal helpers
- add type-mismatch coverage for `AsSlice[T]`
- expand the benchmark suite so it measures both:
- short slices that hit the new fixed-size path
- longer slices that still use the reflective fallback
## Rationale
The package still needs reflection for arbitrary runtime lengths because
slice values are stored as comparable arrays behind `any`, and Go cannot
construct a runtime-sized array type without `reflect.ArrayOf`.
The fast path is intentionally small. The cutoff of `0..3` is based on a
combination of:
- benchmark gains for short slices
- semantic convention examples where `1..3` values are common
- downstream source analysis, which found that most external call sites
pass variables rather than inline literals, so static source scanning
does not justify a larger cutoff
## External Usage Validation
Downstream scan:
- sampled repos cloned and scanned: `285`
- most external call sites pass dynamic slice variables, not inline
literals
- final literal counts recovered statically:
- `StringSlice`: total `131`, dynamic `121`, literal len `0`: `1`, len
`1`: `8`, len `2`: `1`
- `IntSlice`: total `5`, all dynamic
- `Int64Slice`: total `6`, all dynamic
- `BoolSlice`: total `3`, all dynamic
- `Float64Slice`: total `3`, all dynamic
Semantic conventions reviewed locally in `semantic-conventions` include
several slice-valued attributes where short lists are normal, for
example:
- `browser.brands`
- `gen_ai.request.stop_sequences`
- `gen_ai.request.encoding_formats`
- `gen_ai.response.finish_reasons`
- `user.roles`
- `file.attributes`
There are also clearly unbounded cases like headers, metadata, command
args, and some cloud/provider arrays. That combination supports a small
fast path, but not an assumption that all real-world slices are tiny.
## Benchmarks
Changes to the benchmarks:
- internal microbenchmarks now run both `Len2` and `Len8`
- public `attribute` benchmarks now run both `Len2` and `Len8`
- repeated benchmark runs were compared with `benchstat`
`Len2` exercises the new fixed-size path. `Len8` exercises the
reflective fallback path.
Headline result:
- short slices improve substantially
- large slices stay close to baseline because they still use reflection
- `IntSlice` now gets the same short-slice win as the other slice types,
but larger `[]int` values still pay the `[]int` to `[]int64` conversion
cost
### Internal Helpers
```text
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute/internal
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
│ /tmp/bench-internal-base-v2.txt │ /tmp/bench-internal-current-v2.txt │
│ sec/op │ sec/op vs base │
BoolSliceValue/Len2-8 124.00n ± 4% 19.36n ± 12% -84.39% (p=0.000 n=12)
BoolSliceValue/Len8-8 129.9n ± 2% 136.8n ± 3% +5.31% (p=0.000 n=12)
Int64SliceValue/Len2-8 146.00n ± 26% 26.13n ± 3% -82.10% (p=0.000 n=12)
Int64SliceValue/Len8-8 172.1n ± 4% 174.9n ± 5% ~ (p=0.443 n=12)
Float64SliceValue/Len2-8 151.70n ± 2% 26.25n ± 2% -82.70% (p=0.000 n=12)
Float64SliceValue/Len8-8 173.6n ± 2% 169.7n ± 4% ~ (p=0.155 n=12)
StringSliceValue/Len2-8 177.15n ± 2% 42.03n ± 3% -76.27% (p=0.000 n=12)
StringSliceValue/Len8-8 217.2n ± 6% 219.1n ± 6% ~ (p=0.504 n=12)
AsFloat64Slice/Len2-8 96.77n ± 3% 63.05n ± 27% -34.84% (p=0.000 n=12)
AsFloat64Slice/Len8-8 123.8n ± 18% 117.1n ± 4% ~ (p=1.000 n=12)
geomean 147.6n 71.85n -51.33%
│ /tmp/bench-internal-base-v2.txt │ /tmp/bench-internal-current-v2.txt │
│ B/op │ B/op vs base │
BoolSliceValue/Len2-8 4.000 ± 0% 2.000 ± 0% -50.00% (p=0.000 n=12)
BoolSliceValue/Len8-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=12) ¹
Int64SliceValue/Len2-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Int64SliceValue/Len8-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
Float64SliceValue/Len2-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Float64SliceValue/Len8-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
StringSliceValue/Len2-8 64.00 ± 0% 32.00 ± 0% -50.00% (p=0.000 n=12)
StringSliceValue/Len8-8 256.0 ± 0% 256.0 ± 0% ~ (p=1.000 n=12) ¹
AsFloat64Slice/Len2-8 40.00 ± 0% 40.00 ± 0% ~ (p=1.000 n=12) ¹
AsFloat64Slice/Len8-8 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=12) ¹
geomean 47.77 36.21 -24.21%
¹ all samples are equal
│ /tmp/bench-internal-base-v2.txt │ /tmp/bench-internal-current-v2.txt │
│ allocs/op │ allocs/op vs base │
BoolSliceValue/Len2-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
BoolSliceValue/Len8-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Int64SliceValue/Len2-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Int64SliceValue/Len8-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Float64SliceValue/Len2-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Float64SliceValue/Len8-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
StringSliceValue/Len2-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
StringSliceValue/Len8-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
AsFloat64Slice/Len2-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
AsFloat64Slice/Len8-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
geomean 2.000 1.516 -24.21%
¹ all samples are equal
```
### Public `attribute` API
```text
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
│ /tmp/bench-attr-base-v2.txt │ /tmp/bench-attr-current-v3.txt │
│ sec/op │ sec/op vs base │
BoolSlice/Len2/Value-8 130.65n ± 3% 16.90n ± 3% -87.06% (p=0.000 n=12)
BoolSlice/Len2/KeyValue-8 135.85n ± 14% 23.49n ± 2% -82.71% (p=0.000 n=12)
BoolSlice/Len2/AsBoolSlice-8 50.22n ± 1% 19.12n ± 15% -61.92% (p=0.000 n=12)
BoolSlice/Len2/Emit-8 343.9n ± 1% 293.4n ± 1% -14.68% (p=0.000 n=12)
BoolSlice/Len8/Value-8 134.7n ± 2% 136.4n ± 2% +1.22% (p=0.011 n=12)
BoolSlice/Len8/KeyValue-8 137.7n ± 2% 140.6n ± 2% +2.11% (p=0.046 n=12)
BoolSlice/Len8/AsBoolSlice-8 53.59n ± 22% 61.15n ± 22% +14.11% (p=0.020 n=12)
BoolSlice/Len8/Emit-8 773.5n ± 1% 788.5n ± 2% +1.93% (p=0.028 n=12)
IntSlice/Len2/Value-8 140.85n ± 2% 36.20n ± 3% -74.30% (p=0.000 n=12)
IntSlice/Len2/KeyValue-8 149.65n ± 2% 42.84n ± 3% -71.37% (p=0.000 n=12)
IntSlice/Len2/Emit-8 318.2n ± 3% 279.6n ± 15% -12.15% (p=0.012 n=12)
IntSlice/Len8/Value-8 217.9n ± 1% 228.8n ± 2% +5.00% (p=0.001 n=12)
IntSlice/Len8/KeyValue-8 225.6n ± 29% 232.3n ± 3% ~ (p=0.767 n=12)
IntSlice/Len8/Emit-8 480.0n ± 1% 478.6n ± 2% ~ (p=0.899 n=12)
Int64Slice/Len2/Value-8 150.90n ± 1% 27.43n ± 3% -81.82% (p=0.000 n=12)
Int64Slice/Len2/KeyValue-8 152.05n ± 1% 34.34n ± 3% -77.42% (p=0.000 n=12)
Int64Slice/Len2/AsInt64Slice-8 58.69n ± 4% 28.58n ± 3% -51.30% (p=0.000 n=12)
Int64Slice/Len2/Emit-8 318.4n ± 3% 273.9n ± 1% -13.99% (p=0.000 n=12)
Int64Slice/Len8/Value-8 173.0n ± 8% 177.8n ± 2% ~ (p=0.173 n=12)
Int64Slice/Len8/KeyValue-8 184.0n ± 24% 184.3n ± 2% ~ (p=0.701 n=12)
Int64Slice/Len8/AsInt64Slice-8 72.04n ± 2% 83.05n ± 2% +15.30% (p=0.000 n=12)
Int64Slice/Len8/Emit-8 474.9n ± 19% 501.9n ± 18% +5.67% (p=0.020 n=12)
Float64Slice/Len2/Value-8 150.95n ± 3% 26.92n ± 3% -82.17% (p=0.000 n=12)
Float64Slice/Len2/KeyValue-8 153.95n ± 3% 33.08n ± 2% -78.52% (p=0.000 n=12)
Float64Slice/Len2/AsFloat64Slice-8 60.31n ± 24% 27.02n ± 1% -55.19% (p=0.000 n=12)
Float64Slice/Len2/Emit-8 434.2n ± 2% 380.4n ± 1% -12.40% (p=0.000 n=12)
Float64Slice/Len8/Value-8 173.7n ± 2% 175.2n ± 25% ~ (p=0.248 n=12)
Float64Slice/Len8/KeyValue-8 174.0n ± 4% 175.2n ± 2% ~ (p=0.702 n=12)
Float64Slice/Len8/AsFloat64Slice-8 71.17n ± 8% 78.00n ± 4% +9.58% (p=0.007 n=12)
Float64Slice/Len8/Emit-8 920.6n ± 20% 909.9n ± 8% ~ (p=0.378 n=12)
StringSlice/Len2/Value-8 174.00n ± 5% 41.97n ± 20% -75.88% (p=0.000 n=12)
StringSlice/Len2/KeyValue-8 179.85n ± 2% 46.76n ± 2% -74.00% (p=0.000 n=12)
StringSlice/Len2/AsStringSlice-8 76.03n ± 5% 39.83n ± 3% -47.61% (p=0.000 n=12)
StringSlice/Len2/Emit-8 386.0n ± 2% 332.3n ± 3% -13.91% (p=0.000 n=12)
StringSlice/Len8/Value-8 225.4n ± 4% 226.2n ± 4% ~ (p=0.311 n=12)
StringSlice/Len8/KeyValue-8 228.1n ± 7% 234.2n ± 4% ~ (p=0.386 n=12)
StringSlice/Len8/AsStringSlice-8 110.8n ± 25% 117.8n ± 4% ~ (p=0.173 n=12)
StringSlice/Len8/Emit-8 658.7n ± 3% 647.9n ± 5% ~ (p=0.319 n=12)
geomean 181.7n 110.7n -39.08%
│ /tmp/bench-attr-base-v2.txt │ /tmp/bench-attr-current-v3.txt │
│ B/op │ B/op vs base │
BoolSlice/Len2/Value-8 4.000 ± 0% 2.000 ± 0% -50.00% (p=0.000 n=12)
BoolSlice/Len2/KeyValue-8 4.000 ± 0% 2.000 ± 0% -50.00% (p=0.000 n=12)
BoolSlice/Len2/AsBoolSlice-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len2/Emit-8 40.00 ± 0% 40.00 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/Value-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/KeyValue-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/AsBoolSlice-8 8.000 ± 0% 8.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/Emit-8 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=12) ¹
IntSlice/Len2/Value-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
IntSlice/Len2/KeyValue-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
IntSlice/Len2/Emit-8 56.00 ± 0% 56.00 ± 0% ~ (p=1.000 n=12) ¹
IntSlice/Len8/Value-8 128.0 ± 0% 192.0 ± 0% +50.00% (p=0.000 n=12)
IntSlice/Len8/KeyValue-8 128.0 ± 0% 192.0 ± 0% +50.00% (p=0.000 n=12)
IntSlice/Len8/Emit-8 136.0 ± 0% 136.0 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len2/Value-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Int64Slice/Len2/KeyValue-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Int64Slice/Len2/AsInt64Slice-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len2/Emit-8 56.00 ± 0% 56.00 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/Value-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/KeyValue-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/AsInt64Slice-8 64.00 ± 0% 64.00 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/Emit-8 136.0 ± 0% 136.0 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len2/Value-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Float64Slice/Len2/KeyValue-8 32.00 ± 0% 16.00 ± 0% -50.00% (p=0.000 n=12)
Float64Slice/Len2/AsFloat64Slice-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len2/Emit-8 56.00 ± 0% 56.00 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/Value-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/KeyValue-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/AsFloat64Slice-8 64.00 ± 0% 64.00 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/Emit-8 136.0 ± 0% 136.0 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len2/Value-8 64.00 ± 0% 32.00 ± 0% -50.00% (p=0.000 n=12)
StringSlice/Len2/KeyValue-8 64.00 ± 0% 32.00 ± 0% -50.00% (p=0.000 n=12)
StringSlice/Len2/AsStringSlice-8 32.00 ± 0% 32.00 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len2/Emit-8 120.0 ± 0% 120.0 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/Value-8 256.0 ± 0% 256.0 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/KeyValue-8 256.0 ± 0% 256.0 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/AsStringSlice-8 128.0 ± 0% 128.0 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/Emit-8 344.0 ± 0% 344.0 ± 0% ~ (p=1.000 n=12) ¹
geomean 49.39 42.05 -14.88%
¹ all samples are equal
│ /tmp/bench-attr-base-v2.txt │ /tmp/bench-attr-current-v3.txt │
│ allocs/op │ allocs/op vs base │
BoolSlice/Len2/Value-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
BoolSlice/Len2/KeyValue-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
BoolSlice/Len2/AsBoolSlice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len2/Emit-8 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/Value-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/KeyValue-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/AsBoolSlice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
BoolSlice/Len8/Emit-8 11.00 ± 0% 11.00 ± 0% ~ (p=1.000 n=12) ¹
IntSlice/Len2/Value-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
IntSlice/Len2/KeyValue-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
IntSlice/Len2/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
IntSlice/Len8/Value-8 2.000 ± 0% 3.000 ± 0% +50.00% (p=0.000 n=12)
IntSlice/Len8/KeyValue-8 2.000 ± 0% 3.000 ± 0% +50.00% (p=0.000 n=12)
IntSlice/Len8/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len2/Value-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Int64Slice/Len2/KeyValue-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Int64Slice/Len2/AsInt64Slice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len2/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/Value-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/KeyValue-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/AsInt64Slice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
Int64Slice/Len8/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len2/Value-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Float64Slice/Len2/KeyValue-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
Float64Slice/Len2/AsFloat64Slice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len2/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/Value-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/KeyValue-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/AsFloat64Slice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
Float64Slice/Len8/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len2/Value-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
StringSlice/Len2/KeyValue-8 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=12)
StringSlice/Len2/AsStringSlice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len2/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/Value-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/KeyValue-8 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/AsStringSlice-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=12) ¹
StringSlice/Len8/Emit-8 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=12) ¹
geomean 2.143 1.824 -14.88%
¹ all samples are equal
```
## Notes
- `Len2` is where the wins show up because those calls avoid
`reflect.ArrayOf` and one allocation.
- `Len8` stays much closer to baseline because it still uses the
reflective path.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: David Ashpole <dashpole@google.com>
OpenTelemetry-Go
OpenTelemetry-Go is the Go implementation of OpenTelemetry. It provides a set of APIs to directly measure performance and behavior of your software and send this data to observability platforms.
Project Status
| Signal | Status |
|---|---|
| Traces | Stable |
| Metrics | Stable |
| Logs | Beta1 |
Progress and status specific to this repository is tracked in our project boards and milestones.
Project versioning information and stability guarantees can be found in the versioning documentation.
Compatibility
OpenTelemetry-Go ensures compatibility with the current supported versions of the Go language:
Each major Go release is supported until there are two newer major releases. For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release.
For versions of Go that are no longer supported upstream, opentelemetry-go will stop ensuring compatibility with these versions in the following manner:
- A minor release of opentelemetry-go will be made to add support for the new supported release of Go.
- The following minor release of opentelemetry-go will remove compatibility testing for the oldest (now archived upstream) version of Go. This, and future, releases of opentelemetry-go may include features only supported by the currently supported versions of Go.
Currently, this project supports the following environments.
| OS | Go Version | Architecture |
|---|---|---|
| Ubuntu | 1.26 | amd64 |
| Ubuntu | 1.25 | amd64 |
| Ubuntu | 1.26 | 386 |
| Ubuntu | 1.25 | 386 |
| Ubuntu | 1.26 | arm64 |
| Ubuntu | 1.25 | arm64 |
| macOS | 1.26 | amd64 |
| macOS | 1.25 | amd64 |
| macOS | 1.26 | arm64 |
| macOS | 1.25 | arm64 |
| Windows | 1.26 | amd64 |
| Windows | 1.25 | amd64 |
| Windows | 1.26 | 386 |
| Windows | 1.25 | 386 |
While this project should work for other systems, no compatibility guarantees are made for those systems currently.
Getting Started
You can find a getting started guide on opentelemetry.io.
OpenTelemetry's goal is to provide a single set of APIs to capture distributed traces and metrics from your application and send them to an observability platform. This project allows you to do just that for applications written in Go. There are two steps to this process: instrument your application, and configure an exporter.
Instrumentation
To start capturing distributed traces and metric events from your application it first needs to be instrumented. The easiest way to do this is by using an instrumentation library for your code. Be sure to check out the officially supported instrumentation libraries.
If you need to extend the telemetry an instrumentation library provides or want to build your own instrumentation for your application directly you will need to use the Go otel package. The examples are a good way to see some practical uses of this process.
Export
Now that your application is instrumented to collect telemetry, it needs an export pipeline to send that telemetry to an observability platform.
All officially supported exporters for the OpenTelemetry project are contained in the exporters directory.
| Exporter | Logs | Metrics | Traces |
|---|---|---|---|
| OTLP | ✓ | ✓ | ✓ |
| Prometheus | ✓ | ||
| stdout | ✓ | ✓ | ✓ |
| Zipkin | ✓ |
Contributing
See the contributing documentation.