1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-03 18:35:08 +02:00
Commit Graph

1162 Commits

Author SHA1 Message Date
David Ashpole 597532c4d4 Add observable instrument variants to semconv v1.41.0 (#8350)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7342

Generates both observable and synchronous variants of instruments per
https://github.com/open-telemetry/opentelemetry-go/issues/7342#issuecomment-3292806559
2026-05-21 06:50:33 +02:00
Saharsh Tibrewala f12c29f68a Generating histogram boundaries from weaver.yaml (#8015)
Adding support for histogram boundaries to be generated from weaver 

fixes #8002

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-05-20 14:42:55 -04:00
Sam Xie 97447f5c54 Add max baggage length as limitation (#8222)
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
cpu: Apple M1 Max
                                 │   /tmp/old.txt    │             /tmp/new.txt             │
                                 │      sec/op       │   sec/op     vs base                 │
New-10                                  413.5n ±  1%   410.1n ± 1%         ~ (p=0.184 n=10)
NewMemberRaw-10                         12.65n ±  1%   12.62n ± 1%         ~ (p=0.270 n=10)
Parse-10                                1.252µ ±  2%   1.254µ ± 1%         ~ (p=0.778 n=10)
String-10                               594.9n ±  1%   593.4n ± 1%         ~ (p=0.279 n=10)
ValueEscape/nothing_to_escape-10        4.890n ±  1%   4.885n ± 0%         ~ (p=0.579 n=10)
ValueEscape/requires_escaping-10        22.02n ±  1%   21.47n ± 1%    -2.50% (p=0.000 n=10)
ValueEscape/long_value-10               507.4n ±  1%   506.6n ± 2%         ~ (p=0.481 n=10)
MemberString-10                         486.7n ± 15%   514.0n ± 5%         ~ (p=0.190 n=10)
ParseOversized-10                  22544795.0n ±  1%   130.8n ± 4%  -100.00% (p=0.000 n=10)
geomean                                 510.0n         133.8n        -73.76%

                                 │   /tmp/old.txt   │              /tmp/new.txt              │
                                 │       B/op       │     B/op      vs base                  │
New-10                                 592.0 ± 0%       592.0 ± 0%        ~ (p=1.000 n=10) ¹
NewMemberRaw-10                        0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Parse-10                             1.039Ki ± 0%     1.039Ki ± 0%        ~ (p=1.000 n=10) ¹
String-10                              840.0 ± 0%       840.0 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/nothing_to_escape-10       0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10       16.00 ± 0%       16.00 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10              576.0 ± 0%       576.0 ± 0%        ~ (p=1.000 n=10) ¹
MemberString-10                        656.0 ± 0%       656.0 ± 0%        ~ (p=1.000 n=10) ¹
ParseOversized-10                  801126.50 ± 0%       88.00 ± 0%  -99.99% (p=0.000 n=10)
geomean                                           ²                 -63.68%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │   /tmp/old.txt    │             /tmp/new.txt              │
                                 │     allocs/op     │ allocs/op   vs base                   │
New-10                                  6.000 ± 0%     6.000 ± 0%         ~ (p=1.000 n=10) ¹
NewMemberRaw-10                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Parse-10                                18.00 ± 0%     18.00 ± 0%         ~ (p=1.000 n=10) ¹
String-10                               8.000 ± 0%     8.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/nothing_to_escape-10        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10        1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10               2.000 ± 0%     2.000 ± 0%         ~ (p=1.000 n=10) ¹
MemberString-10                         4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=10) ¹
ParseOversized-10                  250007.000 ± 0%     3.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                                            ²                -71.61%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-05-20 16:25:54 +02:00
Robert Pająk f12d198f16 Merge commit from fork 2026-05-19 11:05:22 +02:00
Tyler Yahn 442cdbdd94 Generate and upgrade to semconv/v1.41.0 (#8324)
Fix https://github.com/open-telemetry/opentelemetry-go/issues/8299

Relevant upstream v1.41.0 release notes:

> ### 🛑 Breaking changes 🛑
> 
> - `graphql`: Change `graphql.document` attribute requirement level
from Recommended to Opt-In due to sensitive data, cardinality, and size
concerns
([#2985](https://github.com/open-telemetry/semantic-conventions/issues/2985))
> - `process`: Move process.executable to its own entity.
([#3535](https://github.com/open-telemetry/semantic-conventions/issues/3535))
> - `process`: Update requirement levels for process attributes to
ensure consistent identification and description across platforms.
([#864](https://github.com/open-telemetry/semantic-conventions/issues/864))
> - `rpc`: Remove `client.address` and `client.port` attributes from RPC
server spans.
([#3487](https://github.com/open-telemetry/semantic-conventions/issues/3487),
[#3488](https://github.com/open-telemetry/semantic-conventions/issues/3488))
> 
> ### 💡 Enhancements 💡
> 
> - `Go`: Add opt-in go.memory.gc.pause.duration histogram metric.
([#3353](https://github.com/open-telemetry/semantic-conventions/issues/3353))
> - `deployment`: Stabilize `deployment.environment.name` attribute.
([#3339](https://github.com/open-telemetry/semantic-conventions/issues/3339))
> - `deployment`: Add enum values for `deployment.environment.name`
attribute.
([#2910](https://github.com/open-telemetry/semantic-conventions/issues/2910))
> - `go`: Add the go.cpu.time opt-in metric, and add
go.cpu.detailed_state and go.memory.detailed_type attributes to CPU and
memory metrics respectively with wildcard values.
([#3354](https://github.com/open-telemetry/semantic-conventions/issues/3354))
> - `go`: Add the opt-in go.memory.gc.cycles metric.
([#3353](https://github.com/open-telemetry/semantic-conventions/issues/3353))
> - `telemetry`: Promote `telemetry.distro.name` and
`telemetry.distro.version` attributes to 'stable'.
([#3650](https://github.com/open-telemetry/semantic-conventions/issues/3650))

This PR also:
- fixes semconv migration generation to ignore unexported declarations
when computing renames/removals
- upgrades repo imports, depguard, docs, templates, and schema URL
expectations to `go.opentelemetry.io/otel/semconv/v1.41.0`
- adds missing generated-file headers to semconvkit templates and
regenerates the affected `v1.41.0` files via `TAG="v1.41.0" make
semconv-generate`

---------

Co-authored-by: David Ashpole <dashpole@google.com>
2026-05-14 14:06:05 -04:00
David Ashpole 8bc88510d3 Optimize metrics sdk measurement with AlwaysOff exemplar filter (#8267)
Follow-up to
https://github.com/open-telemetry/opentelemetry-go/pull/8211.

Because the exemplar reservoir is an interface, it can't be in-lined
even when it is a no-op, so it has significant overhead. Skip it when a
drop reservoir is used. This seems to have an overhead of something like
~10ns, which shows up mostly on the precomputed benchmarks.

Benchmarks

```
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/metric
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                                                                          │ benchmark_results_before.txt │     benchmark_results_after.txt     │
                                                                          │            sec/op            │    sec/op     vs base               │
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributeSet-24                    62.65n ± 15%   54.59n ± 12%  -12.88% (p=0.026 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributes-24                      63.67n ± 10%   52.21n ±  6%  -17.99% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet-24                        238.8n ± 14%   240.0n ± 10%        ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributes-24                          220.7n ± 14%   245.6n ± 13%        ~ (p=0.180 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Naive/WithAttributes-24                            373.4n ± 26%   352.9n ± 11%        ~ (p=0.240 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributeSet-24                    69.73n ± 16%   48.85n ± 14%  -29.94% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributes-24                      61.32n ±  3%   49.01n ±  5%  -20.08% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet-24                        988.4n ± 48%   759.9n ± 55%  -23.12% (p=0.041 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributes-24                          954.1n ± 90%   667.9n ± 19%  -30.00% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Naive/WithAttributes-24                            1.515µ ± 32%   1.233µ ± 12%        ~ (p=0.240 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributeSet-24                   70.86n ± 11%   53.90n ± 16%  -23.94% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributes-24                     69.20n ± 21%   48.95n ± 12%  -29.27% (p=0.004 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet-24                       1.483µ ± 28%   1.283µ ± 29%        ~ (p=0.310 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributes-24                         1.421µ ± 41%   1.664µ ± 49%        ~ (p=0.394 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Naive/WithAttributes-24                           2.784µ ± 66%   2.109µ ± 19%  -24.23% (p=0.041 n=6)
geomean                                                                                     299.2n         252.1n        -15.75%

```

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-01 11:01:46 -04:00
Arthur Silva Sens f3695d093a Prometheus Exporter: Drop Scope attributes name, version and schema_url (#8264)
The Prometheus SIG is currently working to stabilize the Prometheus
exporter spec and the OTLP<->Prometheus data model compatibility spec.
While working on
https://github.com/open-telemetry/opentelemetry-specification/pull/5052,
I realized the Go SDK is not handling collisions between the Scope
attribute and the Scope Name, Version, and SchemaURL.

This PR address it :)

---------

Signed-off-by: Arthur Silva Sens <arthursens2005@gmail.com>
Co-authored-by: David Ashpole <dashpole@google.com>
2026-04-30 07:48:18 -07:00
Nesterov Yehor 1a877475b7 Apply attribute value limit for BYTESLICE and KindBytes (#7990)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7954

Apply the SDK attribute value limit to the new BYTESLICE attribute type.

The limiter has been implemented for trace and log attributes, ensuring
values are truncated according to the configured attribute size limit
(counting each byte as 1).

```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M1
BenchmarkSpanLimits/None-8         	  275883	      4062 ns/op	   12448 B/op	      38 allocs/op
BenchmarkSpanLimits/AttributeValueLengthLimit-8         	  266834	      4407 ns/op	   13012 B/op	      47 allocs/op
BenchmarkSpanLimits/AttributeCountLimit-8               	  299941	      4025 ns/op	   11616 B/op	      38 allocs/op
BenchmarkSpanLimits/EventCountLimit-8                   	  305880	      3795 ns/op	   11376 B/op	      35 allocs/op
BenchmarkSpanLimits/LinkCountLimit-8                    	  314924	      4375 ns/op	   10976 B/op	      35 allocs/op
BenchmarkSpanLimits/AttributePerEventCountLimit-8       	  275667	      4125 ns/op	   12448 B/op	      38 allocs/op
BenchmarkSpanLimits/AttributePerLinkCountLimit-8        	  285484	      4022 ns/op	   12448 B/op	      38 allocs/op
PASS
ok  	go.opentelemetry.io/otel/sdk/trace	9.394s
```

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-29 14:31:40 +02:00
David Ashpole 4dd8821c94 fix counting of spans/logs in self-observability metrics in otlp trace and log exporters (#8254)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8253
2026-04-24 09:20:58 +02:00
Robert Pająk b4e15cd1c7 Add MaxRequestSize option to OTLP exporters (#8157)
Per https://github.com/open-telemetry/opentelemetry-proto/pull/782

- Introduce WithMaxRequestSize option for OTLP exporters to set a limit
on the size of serialized export requests.
- Implement logic in the HTTP and gRPC clients to check the request
size against the configured maximum before compression and sending.
- The default configuration is that the maximum request size is 32 MiB.
2026-04-23 22:12:44 +02:00
David Ashpole 25ba7a7218 Revert "Optimize fixedsize reservoir (#7447)" (#8249)
This reverts commit 714ca7c32e.

Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8238
2026-04-22 14:51:17 +02:00
Robert Pająk 5f80184b57 sdk/metric: apply default cardinality limit of 2000 (#8247)
Per
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#cardinality-limits:

> If none of the previous values are defined, the default value of 2000
SHOULD be used.
2026-04-22 14:40:51 +02:00
David Ashpole 6f81801cd8 Use a DropReservoir when an exemplar.AlwaysOffFilter is provided (#8211)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/6260,
https://github.com/open-telemetry/opentelemetry-go/issues/6333

The [spec for always
off](https://github.com/open-telemetry/opentelemetry-specification/blob/d500678e4612b56ff2cd5f03e67cd845977d1746/specification/metrics/sdk.md#alwaysoff)
suggests this should "disable" the Exemplar feature:

> An ExemplarFilter which makes no measurements eligible for being an
Exemplar.
Using this ExemplarFilter is as good as disabling the Exemplar feature.

There were a few reports of much higher memory usage when exemplars were
added. I looked into the reports, and it looks like exemplar reservoirs
are expensive in terms of memory compared to the aggregation itself.
Ideally, we shouldn't construct the reservoir when an AlwaysOff exemplar
filter is used.

I couldn't find a super clean way to do this...
`exemplar.AlwaysOffFilter` is a function, so I couldn't easily compare
it without comparing the pointers. I'm open to other suggestions. The
internet says that compiler optimizations could cause this logic to
fail, but worst-case you get the existing behavior.

### Benchmarks

I needed a benchmark that creates a new attribute set for each call to
be able to see how much memory each attribute set uses, so I added a new
one, and ran it against main.

Overall, it reduces the amount of memory used per-attribute-set by
70-88%, which is pretty substantial.

Overall, 

```
                                                  │   old.txt   │               new.txt               │
                                                  │   sec/op    │    sec/op     vs base               │
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Counter-24            3.523µ ± 2%   3.745µ ± 29%   +6.32% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Counter-24          3.714µ ± 6%   3.879µ ±  5%        ~ (p=0.132 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64UpDownCounter-24      3.811µ ± 8%   3.941µ ±  5%        ~ (p=0.065 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64UpDownCounter-24    3.714µ ± 5%   3.822µ ±  1%        ~ (p=0.132 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Histogram-24          3.126µ ± 4%   3.333µ ±  4%   +6.61% (p=0.004 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Histogram-24        3.099µ ± 4%   3.204µ ±  8%        ~ (p=0.093 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Gauge-24              3.745µ ± 7%   3.902µ ±  4%        ~ (p=0.240 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Gauge-24            3.746µ ± 7%   3.862µ ±  2%        ~ (p=0.102 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Counter-24           3.621µ ± 3%   1.665µ ±  1%  -54.00% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Counter-24         3.639µ ± 2%   1.686µ ±  4%  -53.68% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64UpDownCounter-24     3.563µ ± 4%   1.700µ ±  4%  -52.29% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64UpDownCounter-24   3.634µ ± 1%   1.690µ ±  4%  -53.49% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Histogram-24         2.892µ ± 2%   2.005µ ±  2%  -30.66% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Histogram-24       2.962µ ± 5%   2.057µ ±  6%  -30.55% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Gauge-24             3.692µ ± 5%   1.599µ ±  2%  -56.68% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Gauge-24           3.651µ ± 3%   1.612µ ±  2%  -55.86% (p=0.002 n=6)
geomean                                             3.495µ        2.541µ        -27.30%

                                                  │   old.txt    │               new.txt               │
                                                  │     B/op     │     B/op      vs base               │
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Counter-24            3.107Ki ± 0%   3.107Ki ± 0%        ~ (p=0.121 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Counter-24          3.108Ki ± 0%   3.107Ki ± 0%        ~ (p=0.177 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64UpDownCounter-24      3.108Ki ± 0%   3.108Ki ± 0%        ~ (p=0.675 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64UpDownCounter-24    3.107Ki ± 0%   3.107Ki ± 0%        ~ (p=1.000 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Histogram-24          2.622Ki ± 0%   2.622Ki ± 0%        ~ (p=0.394 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Histogram-24        2.622Ki ± 0%   2.622Ki ± 0%        ~ (p=0.636 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Gauge-24              3.108Ki ± 0%   3.107Ki ± 0%        ~ (p=0.167 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Gauge-24            3.107Ki ± 0%   3.108Ki ± 0%        ~ (p=0.182 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Counter-24            3182.0 ± 0%     361.0 ± 0%  -88.65% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Counter-24          3182.5 ± 0%     360.5 ± 0%  -88.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64UpDownCounter-24      3182.0 ± 0%     359.5 ± 1%  -88.70% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64UpDownCounter-24    3182.0 ± 0%     361.0 ± 0%  -88.65% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Histogram-24          2684.0 ± 0%     773.0 ± 0%  -71.20% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Histogram-24        2684.0 ± 0%     773.0 ± 0%  -71.20% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Gauge-24              3182.0 ± 0%     361.0 ± 1%  -88.65% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Gauge-24            3182.0 ± 0%     361.0 ± 0%  -88.65% (p=0.002 n=6)
geomean                                             2.978Ki        1.127Ki       -62.17%

                                                  │   old.txt   │               new.txt               │
                                                  │  allocs/op  │ allocs/op   vs base                 │
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Counter-24             12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Counter-24           12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64UpDownCounter-24       12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64UpDownCounter-24     12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Histogram-24           13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Histogram-24         13.00 ± 0%   13.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Int64Gauge-24               12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOn/Float64Gauge-24             12.00 ± 0%   12.00 ± 0%        ~ (p=1.000 n=6) ¹
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Counter-24           12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Counter-24         12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64UpDownCounter-24     12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64UpDownCounter-24   12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Histogram-24         13.000 ± 0%   9.000 ± 0%  -30.77% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Histogram-24       13.000 ± 0%   9.000 ± 0%  -30.77% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Int64Gauge-24             12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
BenchmarkMeasureNewAttributeSet/AlwaysOff/Float64Gauge-24           12.000 ± 0%   7.000 ± 0%  -41.67% (p=0.002 n=6)
geomean                                              12.24        9.553       -21.97%
¹ all samples are equal
```

Gemini helped me write this.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-21 16:08:33 -04:00
David Ashpole 5ecaa5b54f feat: add self-observability metrics to otlpmetrichttp metric exporters (#8194)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7011

This PR updates
https://github.com/open-telemetry/opentelemetry-go/pull/7493, and
addresses outstanding comments. See commit descriptions for the changes
made on top of that PR. Credit to @tongoss for most of the work.

Benchmark results:

```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/observ
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                                             │ sec/op      │
InstrumentationExportMetrics/NoError-24        787.4n ± 5%
InstrumentationExportMetrics/PartialError-24   4.137µ ± 9%
InstrumentationExportMetrics/FullError-24      3.938µ ± 7%
geomean                                        2.341µ

                                             │  B/op       │
InstrumentationExportMetrics/NoError-24        0.000 ± 0%
InstrumentationExportMetrics/PartialError-24   787.0 ± 0%
InstrumentationExportMetrics/FullError-24      787.0 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                             │ allocs/op   │
InstrumentationExportMetrics/NoError-24        0.000 ± 0%
InstrumentationExportMetrics/PartialError-24   6.000 ± 0%
InstrumentationExportMetrics/FullError-24      6.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean
```
```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                                         │    sec/op     │
ExporterExportMetrics/Observability-24     433.5µ ± 4%
ExporterExportMetrics/NoObservability-24   439.3µ ± 4%
geomean                                    436.4µ

                                         │     B/op      │
ExporterExportMetrics/Observability-24     28.72Ki ± 2%
ExporterExportMetrics/NoObservability-24   28.71Ki ± 2%
geomean                                    28.71Ki

                                         │   allocs/op   │
ExporterExportMetrics/Observability-24     446.0 ± 0%
ExporterExportMetrics/NoObservability-24   446.0 ± 0%
geomean                                    446.0

```

Written with assistance from Gemini.

---------

Co-authored-by: Robert Wu <robertxtw@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Flc゛ <i@flc.io>
2026-04-21 14:58:55 -04:00
David Ashpole 5bd5702ad2 Fix stale status code reporting on self-observability metrics (#8226)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8218

This now omits the status code attribute when a request fails before
getting a response, and doesn't use the previous response's status code
when reporting self-observability metrics.
2026-04-20 18:24:07 +02:00
Robert Pająk fa9276b15e exporters: support SLICE attributes (#8216)
Fixes #8162

Follow-up to #8153 for `attribute.SLICE`.

Add end-to-end exporter handling for `attribute.SLICE` in the remaining
paths that still treated it as invalid or relied on fallback formatting.

Changes:

- encode `attribute.SLICE` as OTLP `AnyValue_ArrayValue` for trace, log,
and metric transforms
- serialize Zipkin `SLICE` attributes using the non-OTLP AnyValue string
representation
- add trace-side coverage for recursive `convAttrValue` slice conversion
2026-04-20 11:03:34 +02:00
Robert Pająk 3384d39f6b prometheus: fix Collect data race for constant resource labels (#8227) 2026-04-20 10:37:32 +02:00
Robert Pająk bec9f66b45 sdk/trace: apply AttributeValueLengthLimit to attribute.SLICE (#8217)
Fixes #7955

Per the OTel spec, attribute value limits must be applied recursively to
array elements. Previously truncateAttr only handled STRING and
STRINGSLICE.

Add a SLICE case to truncateAttr and two unexported helpers:
- truncateValue: recursively truncates STRING, STRINGSLICE, and SLICE
- needsTruncation: pre-scan guard that avoids allocating a new slice
when no element would be modified (mirrors sdk/log's pattern)

```
goarch: amd64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
BenchmarkSpanLimits/None-20                                       205869              6757 ns/op           11296 B/op         38 allocs/op
BenchmarkSpanLimits/AttributeValueLengthLimit-20                  189799              5271 ns/op           11712 B/op         45 allocs/op
BenchmarkSpanLimits/AttributeCountLimit-20                        135494              9970 ns/op           10592 B/op         38 allocs/op
BenchmarkSpanLimits/EventCountLimit-20                            121084              9672 ns/op           10224 B/op         35 allocs/op
BenchmarkSpanLimits/LinkCountLimit-20                             110524              9419 ns/op            9824 B/op         35 allocs/op
BenchmarkSpanLimits/AttributePerEventCountLimit-20                123159              9308 ns/op           11296 B/op         38 allocs/op
BenchmarkSpanLimits/AttributePerLinkCountLimit-20                 146022              9337 ns/op           11296 B/op         38 allocs/op
```

The new `attribute.SLICE` item makes
`BenchmarkSpanLimits/AttributeValueLengthLimit` ~12% slower with 5 extra
allocs in that path compared to `main`. This is fine as 3 strings and 2
arrays need to be allocated because of the limits+truncation.

```
SpanLimits/AttributeValueLengthLimit   5.030µs ± 2%   5.651µs ± 2%  +12.34% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit   10.53KiB ± 0% 11.44KiB ± 0% +8.61%  (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit   40.00 allocs   45.00 allocs +12.50% (p=0.000 n=10)
```
2026-04-17 18:17:45 +02:00
Robert Pająk d13f8ecb2d attribute: add SLICE type support (#8166)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7934

```
$ go test -run=^$ -bench=BenchmarkSlice
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
BenchmarkSlice/Len3/Value-20                    25297926                52.56 ns/op          144 B/op          1 allocs/op
BenchmarkSlice/Len3/KeyValue-20                 21315132                55.97 ns/op          144 B/op          1 allocs/op
BenchmarkSlice/Len3/AsSlice-20                  24214248                50.03 ns/op          144 B/op          1 allocs/op
BenchmarkSlice/Len3/String-20                   14148270                86.48 ns/op           48 B/op          1 allocs/op
BenchmarkSlice/Len3/Emit-20                     13605388                85.18 ns/op           48 B/op          1 allocs/op
BenchmarkSlice/Len5Nested/Value-20              16086171                71.30 ns/op          240 B/op          1 allocs/op
BenchmarkSlice/Len5Nested/KeyValue-20           15547844                75.81 ns/op          240 B/op          1 allocs/op
BenchmarkSlice/Len5Nested/AsSlice-20            17806996                66.16 ns/op          240 B/op          1 allocs/op
BenchmarkSlice/Len5Nested/String-20              7409064               165.2 ns/op            64 B/op          1 allocs/op
BenchmarkSlice/Len5Nested/Emit-20                7666302               161.0 ns/op            64 B/op          1 allocs/op
PASS
ok      go.opentelemetry.io/otel/attribute      12.980s
```

```
$ go test -run=^$ -bench=BenchmarkHashKVs
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
BenchmarkHashKVs-20      1268742               940.5 ns/op             0 B/op          0 allocs/op
PASS
ok      go.opentelemetry.io/otel/attribute      1.198s
```
2026-04-16 12:38:32 +02:00
Ali Asghar c56c84380c sdk/trace: propagate SpanExporter.Shutdown error from BatchSpanProcessor (#8197)
Fixes #6878.

`bsp.e.Shutdown(ctx)` was called with `:=` inside an `if` statement,
creating a new variable that shadowed the outer `err`. The error was
handled via `otel.Handle` but never returned to the caller of
`BatchSpanProcessor.Shutdown`.

### Fix

Use a dedicated `exportErr` variable. The goroutine writes it before
closing the `wait` channel; the caller reads it only in the `<-wait`
select case (where the goroutine is guaranteed done). This is race-free
— addressing the concern raised by @seh in #6878.

All existing `TestBatchSpanProcessor*` tests pass.

---------

Signed-off-by: alliasgher <alliasgher123@gmail.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-15 09:04:18 -07:00
Robert Pająk 0231f02f59 fix(otlpmetrichttp): replay gzipped bodies on redirect (#8185)
Same as https://github.com/open-telemetry/opentelemetry-go/pull/8152 but
for `otlpmetrichttp`

When gzip compression is enabled, the OTLP metric HTTP client compressed
the request body for the initial send but left GetBody wired to the
original uncompressed protobuf payload.

Any redirect or retry path that rebuilt the request from GetBody could
then resend an uncompressed body while still advertising
Content-Encoding: gzip.

Update GetBody to return the gzipped buffer and add a redirect
regression test that verifies the replayed body matches the original
compressed request and can be decompressed successfully.
2026-04-14 08:53:02 +02:00
David Ashpole 48dd8b1a09 Add x.Settable to allow reusing attribute options (#8178)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7851

This adopts this proposal from @MrAlias:
https://github.com/open-telemetry/opentelemetry-go/issues/7851#issuecomment-3837399805

This adds a Set function to attrOpt, and changes attrOpt functions to
use a pointer receiver. Users can use this by checking if the attribute
option implements the `Settable` interface in `metric/x`. There are no
public API changes to the metric package, as this is still an
experiment. See the benchmark change and the interface documentation for
how it can be used to avoid calling metric.WithAttributeSet.

I updated the benchmark in
https://github.com/open-telemetry/opentelemetry-go/commit/448394b549375f4f6742201e199e0339d0b78524,
but didn't commit it here to avoid a dependency between the SDK and the
`metric/x` package.

As expected, this removes one allocation from the Dynamic case!

The results are:

```
                                                                          │    main.txt    │            resettable.txt            │
                                                                          │     sec/op     │     sec/op        vs base        │
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet-24         238.2n ±  5%    220.7n ±  9%   -7.39% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet-24         611.1n ±  4%    620.3n ±  2%        ~ (p=0.394 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet-24        1.147µ ±  7%    1.171µ ±  5%        ~ (p=0.258 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet-24         363.8n ±  6%    363.5n ±  6%        ~ (p=1.000 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet-24         1.464µ ±  5%    1.475µ ± 10%        ~ (p=0.727 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet-24        2.924µ ±  7%    2.589µ ±  6%  -11.47% (p=0.002 n=6)
                                                                          │    main.txt    │            resettable.txt            │
                                                                          │      B/op      │      B/op         vs base        │
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet-24          88.00 ± 0%      64.00 ± 0%  -27.27% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet-24          344.0 ± 0%      321.0 ± 0%   -6.69% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet-24         729.0 ± 0%      706.0 ± 0%   -3.16% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet-24          152.0 ± 0%      128.0 ± 0%  -15.79% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet-24          921.0 ± 0%      899.0 ± 0%   -2.39% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet-24       2.026Ki ± 0%    2.006Ki ± 0%   -1.01% (p=0.002 n=6)
                                                                          │    main.txt    │            resettable.txt            │
                                                                          │   allocs/op    │   allocs/op       vs base        │
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet-24          2.000 ± 0%      1.000 ± 0%  -50.00% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet-24          2.000 ± 0%      1.000 ± 0%  -50.00% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet-24         2.000 ± 0%      1.000 ± 0%  -50.00% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet-24          3.000 ± 0%      2.000 ± 0%  -33.33% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet-24          4.000 ± 0%      3.000 ± 0%  -25.00% (p=0.002 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet-24         4.000 ± 0%      3.000 ± 0%  -25.00% (p=0.002 n=6)
```

---------

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2026-04-13 12:47:46 -04:00
Robert Pająk 866dd2504c attribute: deprecate Value.Emit (#8176)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8145
2026-04-13 08:24:39 +02:00
David Ashpole d96b420138 Add support for the development attributes advisory parameter (#8135)
From [the
spec](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-advisory-parameter-attributes):

> ##### Instrument advisory parameter: `Attributes`

> **Status**: [Development](../document-status.md)

> Applies to all instrument types.

> `Attributes` (a list of [attribute
keys](../common/README.md#attribute)) is
the recommended set of attribute keys to be used for the resulting
metrics.

We already have `WithAttributes` options, so i've opted to name this
`WithDefaultAttributes` to avoid naming collisions. We could also
consider `WithAttributeKeys`, or `WithDefaultAttributeKeys`

Follows the pattern for experimental options introduced in
https://github.com/open-telemetry/opentelemetry-go/pull/8111

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-10 14:38:44 -04:00
Robert Pająk 73876cb450 prometheus: use Value.String instead of Value.Emit (#8170)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8144

From
https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#metric-attributes:

> non-string Attribute values MUST be converted to string attributes
following the [attribute
specification](https://opentelemetry.io/docs/specs/otel/common/#attribute).
2026-04-10 15:18:46 +02:00
Robert Pająk 1519eb8c33 attribute: Set.MarshalLog to use Value.String instead of Value.Emit (#8169)
Towards https://github.com/open-telemetry/opentelemetry-go/issues/8145
2026-04-10 15:11:31 +02:00
Tyler Yahn b1284dbfaa Support BYTESLICE attributes across trace and exporter paths (#8153)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8164

Supersedes #8042 which does not address the `trace` or `zipkin`
packages, and has unrelated support changes.

Add end-to-end handling for `attribute.BYTESLICE` in the remaining trace
and exporter paths that still dropped, invalidated, or stringified byte
slice attributes.

This change:

- preserves byte slice attributes in `trace/auto`
- encodes byte slice attributes as OTLP `AnyValue_BytesValue` in trace,
log, and metric transforms
- serializes Zipkin byte slice attributes as JSON arrays of byte values
- adds regression tests for each updated path

## Problem

`attribute.BYTESLICE` is public, but several downstream conversions
still did not handle it correctly:

- `trace/auto` dropped byte slice attributes during conversion
- OTLP trace, log, and metric transforms fell through to their invalid
default handling
- Zipkin fell back to `Value.Emit()`, which produced a base64 string
rather than an explicit byte-array representation

That made `BYTESLICE` unusable or inconsistent depending on the export
path.

## Changes

### Trace

- Handle `attribute.BYTESLICE` in `trace/auto` by converting it to an
internal telemetry bytes value.
- Add a regression test covering byte slice conversion.

### OTLP

- Handle `attribute.BYTESLICE` in:
  - trace attribute transform
  - log gRPC attribute transform
  - log HTTP attribute transform
  - metric HTTP attribute transform
  - metric gRPC attribute transform
- Update the shared log and metric transform templates so generated
outputs stay aligned.
- Add regression tests for the trace transform, both log transform
outputs, and both metric transform outputs.

### Zipkin

- Handle `attribute.BYTESLICE` explicitly in Zipkin tag serialization.
- Serialize byte slices as JSON arrays of byte values instead of base64
text.
- Add a regression test for Zipkin byte slice serialization.

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-09 14:04:03 -07:00
David Ashpole 0c09e08e7f Add experimental support for batching in periodic reader (#8071)
Adds experimental support for maxExportBatchSize using the
`OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE=<size>` environment variable.

Previous prototype:
https://github.com/open-telemetry/opentelemetry-go/pull/7930

This preserves existing behavior for timeouts when batching is not used,
but individually applies the timeout to export calls when batching is
used.
2026-04-09 09:31:05 -04:00
Tyler Yahn 552d7ac071 fix(otlploghttp): replay gzipped bodies on redirect (#8152)
When gzip compression is enabled, the OTLP log HTTP client compressed
the request body for the initial send but left GetBody wired to the
original uncompressed protobuf payload.

Any redirect or retry path that rebuilt the request from GetBody could
then resend an uncompressed body while still advertising
Content-Encoding: gzip.

Update GetBody to return the gzipped buffer and add a redirect
regression test that verifies the replayed body matches the original
compressed request and can be decompressed successfully.
2026-04-08 11:48:23 -07:00
Robert Pająk 876f7c51e4 attribute: add String method for Value type (#8142)
Towards https://github.com/open-telemetry/opentelemetry-go/issues/7810

Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8143

String representation follows:
https://opentelemetry.io/docs/specs/otel/common/#anyvalue-representation-for-non-otlp-protocols

This uses optimizations like
https://github.com/open-telemetry/opentelemetry-go/pull/8039 and we
inline the JSON-array/string encoding logic so we avoid the extra
allocations and reflection overhead of marshaling through encoding/json
(the code is inlined here not to reimplement JSON broadly, but to
provide a spec-specific, allocation-conscious formatter for a
constrained data model).

Benchmarks of both `String` and `Emit` (that is going to be deprecated)
showcase that `String` is even more efficient.

```
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
BenchmarkBool/String-20                 100000000               10.20 ns/op            0 B/op          0 allocs/op
BenchmarkBool/Emit-20                   100000000               10.33 ns/op            0 B/op          0 allocs/op
BenchmarkBoolSlice/Len2/String-20               28427863                36.15 ns/op           16 B/op          1 allocs/op
BenchmarkBoolSlice/Len2/Emit-20                  5433291               201.8 ns/op            40 B/op          5 allocs/op
BenchmarkBoolSlice/Len8/String-20               12453201                99.46 ns/op           48 B/op          1 allocs/op
BenchmarkBoolSlice/Len8/Emit-20                  2185160               546.0 ns/op            88 B/op         11 allocs/op
BenchmarkInt/String-20                          100000000               10.73 ns/op            0 B/op          0 allocs/op
BenchmarkInt/Emit-20                            100000000               11.03 ns/op            0 B/op          0 allocs/op
BenchmarkIntSlice/Len2/String-20                17855926                61.57 ns/op           48 B/op          1 allocs/op
BenchmarkIntSlice/Len2/Emit-20                   6237072               184.9 ns/op            56 B/op          4 allocs/op
BenchmarkIntSlice/Len8/String-20                 6573506               192.1 ns/op           176 B/op          1 allocs/op
BenchmarkIntSlice/Len8/Emit-20                   3620901               332.8 ns/op           136 B/op          4 allocs/op
BenchmarkInt64/String-20                        100000000               10.90 ns/op            0 B/op          0 allocs/op
BenchmarkInt64/Emit-20                          100000000               10.91 ns/op            0 B/op          0 allocs/op
BenchmarkInt64Slice/Len2/String-20              20924970                59.59 ns/op           48 B/op          1 allocs/op
BenchmarkInt64Slice/Len2/Emit-20                 6755516               184.2 ns/op            56 B/op          4 allocs/op
BenchmarkInt64Slice/Len8/String-20               6033630               207.9 ns/op           176 B/op          1 allocs/op
BenchmarkInt64Slice/Len8/Emit-20                 3491808               327.2 ns/op           136 B/op          4 allocs/op
BenchmarkFloat64/String-20                      23607802                52.21 ns/op            2 B/op          1 allocs/op
BenchmarkFloat64/Emit-20                        13578472                93.34 ns/op           16 B/op          2 allocs/op
BenchmarkFloat64Slice/Len2/String-20                    12066591               111.0 ns/op            64 B/op          1 allocs/op
BenchmarkFloat64Slice/Len2/Emit-20                       5177293               234.3 ns/op            56 B/op          4 allocs/op
BenchmarkFloat64Slice/Len8/String-20                     3041408               381.9 ns/op           208 B/op          1 allocs/op
BenchmarkFloat64Slice/Len8/Emit-20                       2369974               548.3 ns/op           136 B/op          4 allocs/op
BenchmarkString/String-20                               137506468                8.578 ns/op           0 B/op          0 allocs/op
BenchmarkString/Emit-20                                 139229646                8.542 ns/op           0 B/op          0 allocs/op
BenchmarkStringSlice/Len2/Emit-20                        5809321               228.9 ns/op           120 B/op          4 allocs/op
BenchmarkStringSlice/Len8/String-20                      5089977               240.0 ns/op            96 B/op          1 allocs/op
BenchmarkStringSlice/Len8/Emit-20                        2569848               480.0 ns/op           344 B/op          4 allocs/op
BenchmarkByteSlice/String-20                            32244670                34.31 ns/op           16 B/op          1 allocs/op
BenchmarkByteSlice/Emit-20                              36643321                34.63 ns/op           16 B/op          1 allocs/op
```
2026-04-08 09:50:54 +02:00
Robert Pająk 99b2206d11 log/logtest: add Error field to Record type (#8148)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/8147
2026-04-08 09:41:26 +02:00
Robert Pająk 3b18b21580 unwrap error chains created with fmt.Errorf (#8133)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7975

Per
https://github.com/open-telemetry/opentelemetry-go/issues/7975#issuecomment-4183251694

Per https://github.com/open-telemetry/semantic-conventions/issues/3588

Credits:
- Balaji01-4D for
https://github.com/open-telemetry/opentelemetry-go/pull/8018
- seh for providing valuable feedback
2026-04-07 20:03:30 +02:00
Nesterov Yehor 5e9a80b3ce attribute: add BYTESLICE type support (#7948)
Fixes #7933 

Add BYTES type to https://pkg.go.dev/go.opentelemetry.io/otel/attribute

- Introduces BYTES type and byte 
- Adds Bytes / BytesValue constructors
- Implements hashing support
- Adds base64 representation in Emit()
- Adds test coverage for constructors, hashing, and set equality

```
$ go test -run=^$ -bench=BenchmarkByteSlice
goos: linux
goarch: amd64
pkg: go.opentelemetry.io/otel/attribute
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
BenchmarkByteSlice/Value-20             149529567                7.993 ns/op           0 B/op          0 allocs/op
BenchmarkByteSlice/KeyValue-20          136973736                8.768 ns/op           0 B/op          0 allocs/op
BenchmarkByteSlice/AsByteSlice-20       562915658                2.120 ns/op           0 B/op          0 allocs/op
BenchmarkByteSlice/Emit-20              29149410                40.26 ns/op           16 B/op          1 allocs/op
PASS
```

---------

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-07 09:39:32 +02:00
Damien Mathieu 9276201a64 Release v1.43.0 / v0.65.0 / v0.19.0 (#8128)
Release issue:
https://github.com/open-telemetry/opentelemetry-go/issues/8127

## Added

- Add `IsRandom` and `WithRandom` on `TraceFlags`, and `IsRandom` on
`SpanContext` in `go.opentelemetry.io/otel/trace`
for [W3C Trace Context Level 2 Random Trace ID
Flag](https://www.w3.org/TR/trace-context-2/#random-trace-id-flag)
support. (#8012)
- Add service detection with `WithService` in
`go.opentelemetry.io/otel/sdk/resource`. (#7642)
- Add `DefaultWithContext` and `EnvironmentWithContext` in
`go.opentelemetry.io/otel/sdk/resource` to support plumbing
`context.Context` through default and environment detectors. (#8051)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`.
(#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`.
(#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`.
(#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`.
(#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#8038)
- Support attributes with empty value (`attribute.EMPTY`) in
`go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8038)
- Add support for per-series start time tracking for cumulative metrics
in `go.opentelemetry.io/otel/sdk/metric`.
  Set `OTEL_GO_X_PER_SERIES_START_TIMESTAMPS=true` to enable. (#8060)
- Add `WithCardinalityLimitSelector` for metric reader for configuring
cardinality limits specific to the instrument kind. (#7855)

## Changed

- Introduce the `EMPTY` Type in `go.opentelemetry.io/otel/attribute` to
reflect that an empty value is now a valid value, with `INVALID`
remaining as a deprecated alias of `EMPTY`. (#8038)
- Refactor slice handling in `go.opentelemetry.io/otel/attribute` to
optimize short slice values with fixed-size fast paths. (#8039)
- Improve performance of span metric recording in
`go.opentelemetry.io/otel/sdk/trace` by returning early if
self-observability is not enabled. (#8067)
- Improve formatting of metric data diffs in
`go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest`. (#8073)

## Deprecated

- Deprecate `INVALID` in `go.opentelemetry.io/otel/attribute`. Use
`EMPTY` instead. (#8038)

## Fixed

- Return spec-compliant `TraceIdRatioBased` description. This is a
breaking behavioral change, but it is necessary to
make the implementation
[spec-compliant](https://opentelemetry.io/docs/specs/otel/trace/sdk/#traceidratiobased).
(#8027)
- Fix a race condition in `go.opentelemetry.io/otel/sdk/metric` where
the lastvalue aggregation could collect the value 0 even when no
zero-value measurements were recorded. (#8056)
- Limit HTTP response body to 4 MiB in
`go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` to
mitigate excessive memory usage caused by a misconfigured or malicious
server.
Responses exceeding the limit are treated as non-retryable errors.
(#8108)
- Limit HTTP response body to 4 MiB in
`go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` to
mitigate excessive memory usage caused by a misconfigured or malicious
server.
Responses exceeding the limit are treated as non-retryable errors.
(#8108)
- Limit HTTP response body to 4 MiB in
`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` to
mitigate excessive memory usage caused by a misconfigured or malicious
server.
Responses exceeding the limit are treated as non-retryable errors.
(#8108)
- `WithHostID` detector in `go.opentelemetry.io/otel/sdk/resource` to
use full path for `kenv` command on BSD. (#8113)
- Fix missing `request.GetBody` in
`go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` to
correctly handle HTTP2 GOAWAY frame. (#8096)

---------

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2026-04-03 10:30:03 +02:00
Robert Pająk 5e363de517 limit response body size for OTLP HTTP exporters (#8108)
Per https://github.com/open-telemetry/opentelemetry-proto/pull/781
2026-04-01 11:48:05 +02:00
Damien Mathieu 35214b6013 Use an absolute path when calling bsd kenv (#8113)
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-04-01 11:05:13 +02:00
Toma Puljak e70658e098 fix: support getBody in otelploghttp (#8096)
Based on #7931

Adding another `getBody` PR to the chain 😄.

This one is harder to catch if it's a problem since logs aren't being
sent in case of error.

---------

Signed-off-by: Toma Puljak <toma.puljak@hotmail.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-04-01 09:48:12 +02:00
David Ashpole ab27913693 metricdatatest: Improve printing of diffs (#8073)
I've been getting tired of trying to parse blobs of OTLP-like text when
debugging metrics SDK test failures. This PR updating the printing of
diffs between metrics.

### Changes

This combines the `compareDiff`, and `diffSlices` functions into a
single `diffSlices` function. The `compare` parameter now returns a
`[]string` instead of a bool, to allow us to get a list of specific
differences between elements. `diffSlices` now also accepts a
`formatContext` parameter that provides the context (e.g. which scope,
which metric, etc) to print before printing the difference itself.

I've chosen to use the scope name, metric name, and attributes as the
context for scope, metric, and datapoint respectively. We could print
out more (as those are not the only identifying fields), but that is
usually enough to point to the problem.

### Example

I "broke" one of the OpenCensus tests by changing the expected SpanID
from 2 -> 1. You can see the resulting error message before and after
below:

Before:
```
--- FAIL: TestConvertMetrics (0.00s)
    --- FAIL: TestConvertMetrics/normal_Histogram,_summary,_gauges,_and_sums (0.00s)
        metric_test.go:940: [ScopeMetrics Metrics not equal:
            missing expected values:
            metricdata.Metrics{Name:"foo.com/histogram-a", Description:"a testing histogram", Unit:"1", 
Data:metricdata.Histogram[float64]{DataPoints:[]metricdata.HistogramDataPoint[float64]
{metricdata.HistogramDataPoint[float64]{Attributes:attribute.Set{hash:0x83dbf482c8017da3, data:
[2]attribute.KeyValue{attribute.KeyValue{Key:"a", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"hello", 
slice:interface {}(nil)}}, attribute.KeyValue{Key:"b", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"world", 
slice:interface {}(nil)}}}}, StartTime:time.Date(2026, time.March, 18, 15, 46, 53, 76753334, time.Local), 
Time:time.Date(2026, time.March, 18, 15, 47, 53, 77753334, time.Local), Count:0x8, Bounds:[]float64{1, 2, 3}, 
BucketCounts:[]uint64{0x1, 0x2, 0x5}, Min:metricdata.Extrema[float64]{value:0, valid:false}, 
Max:metricdata.Extrema[float64]{value:0, valid:false}, Sum:100, Exemplars:[]metricdata.Exemplar[float64]
{metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue{attribute.KeyValue{Key:"bool", 
Value:attribute.Value{vtype:1, numeric:0x1, stringly:"", slice:interface {}(nil)}}}, Time:time.Date(2026, time.March, 18, 15, 
47, 43, 77753334, time.Local), Value:0.8, SpanID:[]uint8{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x1, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:
[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 43, 77753334, time.Local), Value:1.5, SpanID:
[]uint8{0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, 
time.March, 18, 15, 47, 43, 77753334, time.Local), Value:2.6, SpanID:[]uint8{0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
TraceID:[]uint8{0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}}, 
metricdata.HistogramDataPoint[float64]{Attributes:attribute.Set{hash:0x83dbf482c8017da3, data:
[2]attribute.KeyValue{attribute.KeyValue{Key:"a", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"hello", 
slice:interface {}(nil)}}, attribute.KeyValue{Key:"b", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"world", 
slice:interface {}(nil)}}}}, StartTime:time.Date(2026, time.March, 18, 15, 46, 53, 76753334, time.Local), 
Time:time.Date(2026, time.March, 18, 15, 47, 53, 76753334, time.Local), Count:0xa, Bounds:[]float64{1, 2, 3}, 
BucketCounts:[]uint64{0x1, 0x4, 0x5}, Min:metricdata.Extrema[float64]{value:0, valid:false}, 
Max:metricdata.Extrema[float64]{value:0, valid:false}, Sum:110, Exemplars:[]metricdata.Exemplar[float64]
{metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 
43, 77753334, time.Local), Value:0.9, SpanID:[]uint8{0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x7, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:
[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 43, 77753334, time.Local), Value:1.1, SpanID:
[]uint8{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, 
time.March, 18, 15, 47, 43, 77753334, time.Local), Value:2.7, SpanID:[]uint8{0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
TraceID:[]uint8{0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}}}, Temporality:0x1}}
            unexpected additional values:
            metricdata.Metrics{Name:"foo.com/histogram-a", Description:"a testing histogram", Unit:"1", 
Data:metricdata.Histogram[float64]{DataPoints:[]metricdata.HistogramDataPoint[float64]
{metricdata.HistogramDataPoint[float64]{Attributes:attribute.Set{hash:0x83dbf482c8017da3, data:
[2]attribute.KeyValue{attribute.KeyValue{Key:"a", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"hello", 
slice:interface {}(nil)}}, attribute.KeyValue{Key:"b", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"world", 
slice:interface {}(nil)}}}}, StartTime:time.Date(2026, time.March, 18, 15, 46, 53, 76753334, time.Local), 
Time:time.Date(2026, time.March, 18, 15, 47, 53, 77753334, time.Local), Count:0x8, Bounds:[]float64{1, 2, 3}, 
BucketCounts:[]uint64{0x1, 0x2, 0x5}, Min:metricdata.Extrema[float64]{value:0, valid:false}, 
Max:metricdata.Extrema[float64]{value:0, valid:false}, Sum:100, Exemplars:[]metricdata.Exemplar[float64]
{metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue{attribute.KeyValue{Key:"bool", 
Value:attribute.Value{vtype:1, numeric:0x1, stringly:"", slice:interface {}(nil)}}}, Time:time.Date(2026, time.March, 18, 15, 
47, 43, 77753334, time.Local), Value:0.8, SpanID:[]uint8{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x1, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:
[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 43, 77753334, time.Local), Value:1.5, SpanID:
[]uint8{0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, 
time.March, 18, 15, 47, 43, 77753334, time.Local), Value:2.6, SpanID:[]uint8{0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
TraceID:[]uint8{0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}}, 
metricdata.HistogramDataPoint[float64]{Attributes:attribute.Set{hash:0x83dbf482c8017da3, data:
[2]attribute.KeyValue{attribute.KeyValue{Key:"a", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"hello", 
slice:interface {}(nil)}}, attribute.KeyValue{Key:"b", Value:attribute.Value{vtype:4, numeric:0x0, stringly:"world", 
slice:interface {}(nil)}}}}, StartTime:time.Date(2026, time.March, 18, 15, 46, 53, 76753334, time.Local), 
Time:time.Date(2026, time.March, 18, 15, 47, 53, 76753334, time.Local), Count:0xa, Bounds:[]float64{1, 2, 3}, 
BucketCounts:[]uint64{0x1, 0x4, 0x5}, Min:metricdata.Extrema[float64]{value:0, valid:false}, 
Max:metricdata.Extrema[float64]{value:0, valid:false}, Sum:110, Exemplars:[]metricdata.Exemplar[float64]
{metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 
43, 77753334, time.Local), Value:0.9, SpanID:[]uint8{0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x7, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:
[]attribute.KeyValue(nil), Time:time.Date(2026, time.March, 18, 15, 47, 43, 77753334, time.Local), Value:1.1, SpanID:
[]uint8{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, TraceID:[]uint8{0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0}}, metricdata.Exemplar[float64]{FilteredAttributes:[]attribute.KeyValue(nil), Time:time.Date(2026, 
time.March, 18, 15, 47, 43, 77753334, time.Local), Value:2.7, SpanID:[]uint8{0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
TraceID:[]uint8{0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}}}}, Temporality:0x1}}
            ]
FAIL
FAIL    go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric    0.037s
```

After:

```
--- FAIL: TestConvertMetrics (0.00s)
    --- FAIL: TestConvertMetrics/normal_Histogram,_summary,_gauges,_and_sums (0.00s)
        metric_test.go:940: [ScopeMetrics Metrics not equal:
            Metric "foo.com/histogram-a":
                Metrics Data not equal:
                Histogram not equal:
                Histogram DataPoints not equal:
                HistogramDataPoint [a=hello,b=world]:
                        Exemplars not equal:
                        Exemplar:
                                SpanID not equal:
                                expected: [2 0 0 0 0 0 0 0]
                                actual: [1 0 0 0 0 0 0 0]
            ]
FAIL
FAIL    go.opentelemetry.io/otel/bridge/opencensus/internal/ocmetric    0.036s
```
2026-03-30 15:51:15 -04:00
Peter Nguyen 015ed1a7a4 sdk/metric: Support specifying cardinality limits per instrument kinds (#7855)
Previously, we only had `WithCardinalityLimit()`, which adds a global
cardinality limit.

This PR adds a new API on the reader `WithCardinalityLimitSelector` that
can be used to specify limits per instrument kinds.


[spec](https://github.com/open-telemetry/opentelemetry-specification/blob/49845849d2d8df07059f82033f39e96c561927cf/specification/metrics/sdk.md?plain=1#L1282)


[schema](https://github.com/open-telemetry/opentelemetry-configuration/blob/3dbebe292912f0c0c96ce5dcfefc45dfe5e20f39/snippets/CardinalityLimits_kitchen_sink.yaml#L11-L18)

closes #7786

---------

Co-authored-by: David Ashpole <dashpole@google.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-20 11:24:19 +01:00
yoshimura 528ebabbf0 sdk/trace/internal/observ: guard SpanStarted and spanLive with Enabled (#8067)
Guards SpanStarted and spanLive with Enabled(ctx) to avoid building
metric
options/attributes when instruments are disabled.

```
BenchmarkTracer (noop MeterProvider):

  SpanStarted: ~1.77 ns/op -> ~0.48 ns/op (~3.7x)
  SpanLive:    ~2.05 ns/op -> ~0.52 ns/op (~3.9x)
  SpanEnded:   ~2.05 ns/op -> ~0.52 ns/op (~3.9x)
```

No behavior change when enabled; existing tests cover enabled path.
~~No CHANGELOG entry, following #7848.~~

Issue: #7800

---------

Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-18 16:11:37 +01:00
David Ashpole 025b01be59 Add support for the development per-series starttime feature (#8060)
Add a feature to use per-series start times to match the spec:
https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#start-timestamps

This is a prerequisite to [finishing /
closing](https://github.com/open-telemetry/opentelemetry-specification/pull/4702).

Previous prototype:
https://github.com/open-telemetry/opentelemetry-go/pull/7719

---------

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-03-18 09:46:12 -04:00
Ijas d5f403cab5 sdk/resource: add WithContext variants for Default and Environment (#7808) (#8051)
## Description
Address issue #7808 by plumbing `context.Context` through
`resource.Environment` and `resource.Default`.

Currently, these functions hardcode `context.Background()`, which
prevents detectors (especially those that might perform network lookups
or OS calls) from respecting timeouts or cancellations provided by the
caller.

## Changes

- Adds `EnvironmentWithContext(ctx context.Context)` as a new public
function.
- Adds `DefaultWithContext(ctx context.Context)` as a new public
function.
- Maintains backward compatibility by making `Environment()` and
`Default()` thin wrappers around the new WithContext variants.

## Testing

- Added unit tests in `sdk/resource/resource_test.go` to verify the new
functions.
- Verified that all `sdk/resource` tests pass.
- Verified that make `golangci-lint` passes repository-wide.

Fixes #7808

---------

Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-17 09:35:03 +01:00
David Ashpole 206ac291d0 Fix race in the lastvalue aggregation where 0 could be observed (#8056)
This initializes the value of the gauge with the correct value before it
is stored in the map. We end up storing the same thing twice on the
first call, but that isn't a big deal performance-wise.

Discovered during
https://github.com/open-telemetry/opentelemetry-go/pull/8021
2026-03-16 09:30:51 -04:00
Yuanyuan Zhao 2ffde5a428 trace: add Random Trace ID Flag (#8012)
## Summary

Adds API support for the W3C tracecontext random flag on `TraceFlags`
and `SpanContext` in `go.opentelemetry.io/otel/trace`:

- **`TraceFlags.IsRandom()`** — reports whether the random bit is set
- **`TraceFlags.WithRandom(bool)`** — sets or clears the random bit in a
copy of the flags
- **`SpanContext.IsRandom()`** — reports whether the random bit is set
in the span context's trace flags

These mirror the existing `IsSampled` / `WithSampled` pattern.

## Motivation

The W3C Trace Context spec defines a random bit in trace flags to
indicate probabilistic sampling. This is required for [TraceIdRatioBased
sampler](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk.md#traceidratiobased)
support, where the random bit is set when a trace is probabilistically
sampled and is used for extrapolated span metrics.

## Related

Part of #7928 (Support TraceIdRatioBased Sampler). This PR adds the
trace API needed for that work; sampler implementation and tracestate
`th` handling will follow in separate PRs.

## Co-Author
Joshua MacDonald <jmacd@users.noreply.github.com>

---------

Co-authored-by: Joshua MacDonald <jmacd@users.noreply.github.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-13 09:22:56 +01:00
Tyler Yahn 9587c57d48 Optimize attribute slice conversion (#8039)
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>
2026-03-12 09:33:23 -07:00
Mikhail Mazurskiy ddd2b0e398 fix(sdk/trace): return spec-compliant TraceIdRatioBased description (#8027)
Optimize performance when sampling is disabled - no need to calculate
fraction based on trace id (in `traceIDRatioSampler`) if fraction is
zero.

---------

Co-authored-by: David Ashpole <dashpole@google.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-12 10:11:33 +01:00
Robert Pająk f4da59e651 attribute: change INVALID Type to EMPTY and mark INVALID as deprecated (#8038)
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7932

Noticeable comment from previous PR:
https://github.com/open-telemetry/opentelemetry-go/pull/7942#discussion_r2913179215

Print the empty value as empty string per
https://opentelemetry.io/docs/specs/otel/common/#empty-values
2026-03-12 09:43:04 +01:00
Alex Boten fabe66658f resource: add WithService detector option (#7642)
I was looking at implementing resource detection in otelconf and was
finding that all the detectors were implemented in a similar way except
for the service detector. Added the resource options in this PR for
feedback. Will add tests if the go approvers/maintainers support this
approach.

---------

Signed-off-by: alex boten <223565+codeboten@users.noreply.github.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-10 10:22:06 +01:00
Robert Pająk a3941ff595 Release v1.42.0/v0.64.0/v0.18.0/v0.0.16 (#8006)
### Added

- Add `go.opentelemetry.io/otel/semconv/v1.40.0` package.
The package contains semantic conventions from the `v1.40.0` version of
the OpenTelemetry Semantic Conventions.
See the [migration documentation](./semconv/v1.40.0/MIGRATION.md) for
information on how to upgrade from
`go.opentelemetry.io/otel/semconv/v1.39.0`. (#7985)
- Add `Err` and `SetErr` on `Record` in `go.opentelemetry.io/otel/log`
to attach an error and set record exception attributes in
`go.opentelemetry.io/otel/log/sdk`. (#7924)

### Changed

- `TracerProvider.ForceFlush` in `go.opentelemetry.io/otel/sdk/trace`
joins errors together and continues iteration through SpanProcessors as
opposed to returning the first encountered error without attempting
exports on subsequent SpanProcessors. (#7856)

### Fixed

- Fix missing `request.GetBody` in
`go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` to
correctly handle HTTP2 GOAWAY frame. (#7931)
- Fix semconv v1.39.0 generated metric helpers skipping required
attributes when extra attributes were empty. (#7964)
- Preserve W3C TraceFlags bitmask (including the random Trace ID flag)
during trace context extraction and injection in
`go.opentelemetry.io/otel/propagation`. (#7834)

### Removed

- Drop support for [Go 1.24]. (#7984)
2026-03-06 20:13:23 +01:00
Israel Blancas c9d20155fc log: add error field to Record and make SDK to emit exception attributes (#7924)
Fixes #7923


```sh
$ go test -run=^$ -bench=BenchmarkLoggerEmitExceptionAttributes -benchmem -count=5 -benchtime=500ms -cpu=1
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/log
cpu: Apple M4 Pro
BenchmarkLoggerSetErrAndEmit                 	  628162	      1023 ns/op	    5371 B/op	       1 allocs/op
BenchmarkLoggerSetErrAndEmit                 	  663955	       863.3 ns/op	    5105 B/op	       1 allocs/op
BenchmarkLoggerSetErrAndEmit                 	  653888	      1067 ns/op	    5177 B/op	       1 allocs/op
BenchmarkLoggerSetErrAndEmit                 	  716438	       824.8 ns/op	    4764 B/op	       1 allocs/op
BenchmarkLoggerSetErrAndEmit                 	  746902	       999.2 ns/op	    5630 B/op	       1 allocs/op
BenchmarkLoggerSetExceptionAttributesAndEmit 	  650696	      1042 ns/op	    5200 B/op	       1 allocs/op
BenchmarkLoggerSetExceptionAttributesAndEmit 	  574962	       980.7 ns/op	    4743 B/op	       1 allocs/op
BenchmarkLoggerSetExceptionAttributesAndEmit 	  536736	       989.2 ns/op	    5049 B/op	       1 allocs/op
BenchmarkLoggerSetExceptionAttributesAndEmit 	  558511	      1190 ns/op	    4870 B/op	       1 allocs/op
BenchmarkLoggerSetExceptionAttributesAndEmit 	  669452	       978.8 ns/op	    5067 B/op	       1 allocs/op
PASS
ok  	go.opentelemetry.io/otel/sdk/log	6.994s
```

TODO after merged:
-
https://github.com/open-telemetry/opentelemetry-go/pull/7924#discussion_r2832906451

---------

Signed-off-by: Israel Blancas <iblancasa@gmail.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Damien Mathieu <42@dmathieu.com>
2026-03-05 10:24:05 +01:00