chore(deps): bump go.podman.io/image/v5 from 5.37.0 to 5.38.0

Bumps [go.podman.io/image/v5](https://github.com/containers/container-libs) from 5.37.0 to 5.38.0.
- [Commits](https://github.com/containers/container-libs/compare/image/v5.37.0...image/v5.38.0)

---
updated-dependencies:
- dependency-name: go.podman.io/image/v5
  dependency-version: 5.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2025-11-10 07:01:50 +00:00
committed by GitHub
parent cfc7fdb6b8
commit e656c2082a
36 changed files with 281 additions and 205 deletions

11
go.mod
View File

@@ -38,7 +38,7 @@ require (
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/tidwall/pretty v1.2.1 github.com/tidwall/pretty v1.2.1
go.etcd.io/bbolt v1.4.3 go.etcd.io/bbolt v1.4.3
go.podman.io/image/v5 v5.37.0 go.podman.io/image/v5 v5.38.0
golang.org/x/mod v0.29.0 golang.org/x/mod v0.29.0
golang.org/x/sys v0.38.0 golang.org/x/sys v0.38.0
google.golang.org/grpc v1.74.2 google.golang.org/grpc v1.74.2
@@ -71,7 +71,7 @@ require (
github.com/containers/ocicrypt v1.2.1 // indirect github.com/containers/ocicrypt v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/docker/docker-credential-helpers v0.9.4 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/felixge/fgprof v0.9.5 // indirect github.com/felixge/fgprof v0.9.5 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -111,6 +111,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/sys/capability v0.4.0 // indirect github.com/moby/sys/capability v0.4.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/sys/user v0.4.0 // indirect github.com/moby/sys/user v0.4.0 // indirect
@@ -133,17 +134,17 @@ require (
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.mau.fi/util v0.9.2 // indirect go.mau.fi/util v0.9.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.podman.io/storage v1.60.0 // indirect go.podman.io/storage v1.61.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.43.0 // indirect golang.org/x/crypto v0.43.0 // indirect
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
golang.org/x/net v0.46.0 // indirect golang.org/x/net v0.46.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect
golang.org/x/sync v0.17.0 // indirect golang.org/x/sync v0.17.0 // indirect
golang.org/x/term v0.36.0 // indirect golang.org/x/term v0.36.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.30.0 // indirect

28
go.sum
View File

@@ -84,14 +84,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY= github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
@@ -296,8 +296,8 @@ github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
@@ -366,8 +366,8 @@ go.mau.fi/util v0.9.2 h1:+S4Z03iCsGqU2WY8X2gySFsFjaLlUHFRDVCYvVwynKM=
go.mau.fi/util v0.9.2/go.mod h1:055elBBCJSdhRsmub7ci9hXZPgGr1U6dYg44cSgRgoU= go.mau.fi/util v0.9.2/go.mod h1:055elBBCJSdhRsmub7ci9hXZPgGr1U6dYg44cSgRgoU=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
@@ -384,10 +384,10 @@ go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKr
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.podman.io/image/v5 v5.37.0 h1:yzgQybwuWIIeK63hu+mQqna/wOh96XD5cpVc6j8Dg5M= go.podman.io/image/v5 v5.38.0 h1:aUKrCANkPvze1bnhLJsaubcfz0d9v/bSDLnwsXJm6G4=
go.podman.io/image/v5 v5.37.0/go.mod h1:+s2Sx5dia/jVeT8tI3r2NAPrARMiDdbEq3QPIQogx3I= go.podman.io/image/v5 v5.38.0/go.mod h1:hSIoIUzgBnmc4DjoIdzk63aloqVbD7QXDMkSE/cvG90=
go.podman.io/storage v1.60.0 h1:bWNSrR58nxg39VNFDSx3m0AswbvyzPGOo5XsUfomTao= go.podman.io/storage v1.61.0 h1:5hD/oyRYt1f1gxgvect+8syZBQhGhV28dCw2+CZpx0Q=
go.podman.io/storage v1.60.0/go.mod h1:NK+rsWJVuQeCM7ifv7cxD3abegWxwtW/3OkuSUJJoE4= go.podman.io/storage v1.61.0/go.mod h1:A3UBK0XypjNZ6pghRhuxg62+2NIm5lcUGv/7XyMhMUI=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
@@ -423,8 +423,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -176,6 +176,10 @@ func WithMessageEvents(events ...event) Option {
// WithSpanNameFormatter takes a function that will be called on every // WithSpanNameFormatter takes a function that will be called on every
// request and the returned string will become the Span Name. // request and the returned string will become the Span Name.
//
// When using [http.ServeMux] (or any middleware that sets the Pattern of [http.Request]),
// the span name formatter will run twice. Once when the span is created, and
// second time after the middleware, so the pattern can be used.
func WithSpanNameFormatter(f func(operation string, r *http.Request) string) Option { func WithSpanNameFormatter(f func(operation string, r *http.Request) string) Option {
return optionFunc(func(c *config) { return optionFunc(func(c *config) {
c.SpanNameFormatter = f c.SpanNameFormatter = f

View File

@@ -98,7 +98,7 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http
ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header)) ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
opts := []trace.SpanStartOption{ opts := []trace.SpanStartOption{
trace.WithAttributes(h.semconv.RequestTraceAttrs(h.server, r)...), trace.WithAttributes(h.semconv.RequestTraceAttrs(h.server, r, semconv.RequestTraceAttrsOpts{})...),
} }
opts = append(opts, h.spanStartOptions...) opts = append(opts, h.spanStartOptions...)
@@ -176,7 +176,12 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http
ctx = ContextWithLabeler(ctx, labeler) ctx = ContextWithLabeler(ctx, labeler)
} }
next.ServeHTTP(w, r.WithContext(ctx)) r = r.WithContext(ctx)
next.ServeHTTP(w, r)
if r.Pattern != "" {
span.SetName(h.spanNameFormatter(h.operation, r))
}
statusCode := rww.StatusCode() statusCode := rww.StatusCode()
bytesWritten := rww.BytesWritten() bytesWritten := rww.BytesWritten()

View File

@@ -1,9 +1,11 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/request/body_wrapper.go.tmpl // source: internal/shared/request/body_wrapper.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package request provides types and functionality to handle HTTP request
// handling.
package request // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request" package request // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request"
import ( import (
@@ -56,7 +58,7 @@ func (w *BodyWrapper) updateReadData(n int64, err error) {
} }
} }
// Closes closes the io.ReadCloser. // Close closes the io.ReadCloser.
func (w *BodyWrapper) Close() error { func (w *BodyWrapper) Close() error {
return w.ReadCloser.Close() return w.ReadCloser.Close()
} }

View File

@@ -1,4 +1,4 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/request/resp_writer_wrapper.go.tmpl // source: internal/shared/request/resp_writer_wrapper.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
@@ -105,7 +105,7 @@ func (w *RespWriterWrapper) BytesWritten() int64 {
return w.written return w.written
} }
// BytesWritten returns the HTTP status code that was sent. // StatusCode returns the HTTP status code that was sent.
func (w *RespWriterWrapper) StatusCode() int { func (w *RespWriterWrapper) StatusCode() int {
w.mu.RLock() w.mu.RLock()
defer w.mu.RUnlock() defer w.mu.RUnlock()

View File

@@ -1,4 +1,4 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/env.go.tmpl // source: internal/shared/semconv/env.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
@@ -20,7 +20,7 @@ import (
) )
// OTelSemConvStabilityOptIn is an environment variable. // OTelSemConvStabilityOptIn is an environment variable.
// That can be set to "old" or "http/dup" to opt into the new HTTP semantic conventions. // That can be set to "http/dup" to keep getting the old HTTP semantic conventions.
const OTelSemConvStabilityOptIn = "OTEL_SEMCONV_STABILITY_OPT_IN" const OTelSemConvStabilityOptIn = "OTEL_SEMCONV_STABILITY_OPT_IN"
type ResponseTelemetry struct { type ResponseTelemetry struct {
@@ -61,19 +61,23 @@ type HTTPServer struct {
// //
// If the primary server name is not known, server should be an empty string. // If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
func (s HTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue { func (s HTTPServer) RequestTraceAttrs(server string, req *http.Request, opts RequestTraceAttrsOpts) []attribute.KeyValue {
attrs := CurrentHTTPServer{}.RequestTraceAttrs(server, req, opts)
if s.duplicate { if s.duplicate {
return append(OldHTTPServer{}.RequestTraceAttrs(server, req), CurrentHTTPServer{}.RequestTraceAttrs(server, req)...) return OldHTTPServer{}.RequestTraceAttrs(server, req, attrs)
} }
return OldHTTPServer{}.RequestTraceAttrs(server, req) return attrs
} }
func (s HTTPServer) NetworkTransportAttr(network string) []attribute.KeyValue { func (s HTTPServer) NetworkTransportAttr(network string) []attribute.KeyValue {
if s.duplicate { if s.duplicate {
return append([]attribute.KeyValue{OldHTTPServer{}.NetworkTransportAttr(network)}, CurrentHTTPServer{}.NetworkTransportAttr(network))
}
return []attribute.KeyValue{ return []attribute.KeyValue{
OldHTTPServer{}.NetworkTransportAttr(network), OldHTTPServer{}.NetworkTransportAttr(network),
CurrentHTTPServer{}.NetworkTransportAttr(network),
}
}
return []attribute.KeyValue{
CurrentHTTPServer{}.NetworkTransportAttr(network),
} }
} }
@@ -81,15 +85,16 @@ func (s HTTPServer) NetworkTransportAttr(network string) []attribute.KeyValue {
// //
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted. // If any of the fields in the ResponseTelemetry are not set the attribute will be omitted.
func (s HTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue { func (s HTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue {
attrs := CurrentHTTPServer{}.ResponseTraceAttrs(resp)
if s.duplicate { if s.duplicate {
return append(OldHTTPServer{}.ResponseTraceAttrs(resp), CurrentHTTPServer{}.ResponseTraceAttrs(resp)...) return OldHTTPServer{}.ResponseTraceAttrs(resp, attrs)
} }
return OldHTTPServer{}.ResponseTraceAttrs(resp) return attrs
} }
// Route returns the attribute for the route. // Route returns the attribute for the route.
func (s HTTPServer) Route(route string) attribute.KeyValue { func (s HTTPServer) Route(route string) attribute.KeyValue {
return OldHTTPServer{}.Route(route) return CurrentHTTPServer{}.Route(route)
} }
// Status returns a span status code and message for an HTTP status code // Status returns a span status code and message for an HTTP status code
@@ -121,6 +126,8 @@ type MetricAttributes struct {
type MetricData struct { type MetricData struct {
RequestSize int64 RequestSize int64
// The request duration, in milliseconds
ElapsedTime float64 ElapsedTime float64
} }
@@ -139,7 +146,19 @@ var (
) )
func (s HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) { func (s HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) {
if s.requestBytesCounter != nil && s.responseBytesCounter != nil && s.serverLatencyMeasure != nil { if s.requestDurationHistogram != nil && s.requestBodySizeHistogram != nil && s.responseBodySizeHistogram != nil {
attributes := CurrentHTTPServer{}.MetricAttributes(md.ServerName, md.Req, md.StatusCode, md.AdditionalAttributes)
o := metric.WithAttributeSet(attribute.NewSet(attributes...))
recordOpts := metricRecordOptionPool.Get().(*[]metric.RecordOption)
*recordOpts = append(*recordOpts, o)
s.requestBodySizeHistogram.Record(ctx, md.RequestSize, *recordOpts...)
s.responseBodySizeHistogram.Record(ctx, md.ResponseSize, *recordOpts...)
s.requestDurationHistogram.Record(ctx, md.ElapsedTime/1000.0, o)
*recordOpts = (*recordOpts)[:0]
metricRecordOptionPool.Put(recordOpts)
}
if s.duplicate && s.requestBytesCounter != nil && s.responseBytesCounter != nil && s.serverLatencyMeasure != nil {
attributes := OldHTTPServer{}.MetricAttributes(md.ServerName, md.Req, md.StatusCode, md.AdditionalAttributes) attributes := OldHTTPServer{}.MetricAttributes(md.ServerName, md.Req, md.StatusCode, md.AdditionalAttributes)
o := metric.WithAttributeSet(attribute.NewSet(attributes...)) o := metric.WithAttributeSet(attribute.NewSet(attributes...))
addOpts := metricAddOptionPool.Get().(*[]metric.AddOption) addOpts := metricAddOptionPool.Get().(*[]metric.AddOption)
@@ -150,29 +169,28 @@ func (s HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) {
*addOpts = (*addOpts)[:0] *addOpts = (*addOpts)[:0]
metricAddOptionPool.Put(addOpts) metricAddOptionPool.Put(addOpts)
} }
}
if s.duplicate && s.requestDurationHistogram != nil && s.requestBodySizeHistogram != nil && s.responseBodySizeHistogram != nil { // hasOptIn returns true if the comma-separated version string contains the
attributes := CurrentHTTPServer{}.MetricAttributes(md.ServerName, md.Req, md.StatusCode, md.AdditionalAttributes) // exact optIn value.
o := metric.WithAttributeSet(attribute.NewSet(attributes...)) func hasOptIn(version, optIn string) bool {
recordOpts := metricRecordOptionPool.Get().(*[]metric.RecordOption) for _, v := range strings.Split(version, ",") {
*recordOpts = append(*recordOpts, o) if strings.TrimSpace(v) == optIn {
s.requestBodySizeHistogram.Record(ctx, md.RequestSize, *recordOpts...) return true
s.responseBodySizeHistogram.Record(ctx, md.ResponseSize, *recordOpts...)
s.requestDurationHistogram.Record(ctx, md.ElapsedTime, o)
*recordOpts = (*recordOpts)[:0]
metricRecordOptionPool.Put(recordOpts)
} }
}
return false
} }
func NewHTTPServer(meter metric.Meter) HTTPServer { func NewHTTPServer(meter metric.Meter) HTTPServer {
env := strings.ToLower(os.Getenv(OTelSemConvStabilityOptIn)) env := strings.ToLower(os.Getenv(OTelSemConvStabilityOptIn))
duplicate := env == "http/dup" duplicate := hasOptIn(env, "http/dup")
server := HTTPServer{ server := HTTPServer{
duplicate: duplicate, duplicate: duplicate,
} }
server.requestBytesCounter, server.responseBytesCounter, server.serverLatencyMeasure = OldHTTPServer{}.createMeasures(meter)
if duplicate {
server.requestBodySizeHistogram, server.responseBodySizeHistogram, server.requestDurationHistogram = CurrentHTTPServer{}.createMeasures(meter) server.requestBodySizeHistogram, server.responseBodySizeHistogram, server.requestDurationHistogram = CurrentHTTPServer{}.createMeasures(meter)
if duplicate {
server.requestBytesCounter, server.responseBytesCounter, server.serverLatencyMeasure = OldHTTPServer{}.createMeasures(meter)
} }
return server return server
} }
@@ -192,13 +210,13 @@ type HTTPClient struct {
func NewHTTPClient(meter metric.Meter) HTTPClient { func NewHTTPClient(meter metric.Meter) HTTPClient {
env := strings.ToLower(os.Getenv(OTelSemConvStabilityOptIn)) env := strings.ToLower(os.Getenv(OTelSemConvStabilityOptIn))
duplicate := env == "http/dup" duplicate := hasOptIn(env, "http/dup")
client := HTTPClient{ client := HTTPClient{
duplicate: duplicate, duplicate: duplicate,
} }
client.requestBytesCounter, client.responseBytesCounter, client.latencyMeasure = OldHTTPClient{}.createMeasures(meter)
if duplicate {
client.requestBodySize, client.requestDuration = CurrentHTTPClient{}.createMeasures(meter) client.requestBodySize, client.requestDuration = CurrentHTTPClient{}.createMeasures(meter)
if duplicate {
client.requestBytesCounter, client.responseBytesCounter, client.latencyMeasure = OldHTTPClient{}.createMeasures(meter)
} }
return client return client
@@ -206,19 +224,20 @@ func NewHTTPClient(meter metric.Meter) HTTPClient {
// RequestTraceAttrs returns attributes for an HTTP request made by a client. // RequestTraceAttrs returns attributes for an HTTP request made by a client.
func (c HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue { func (c HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue {
attrs := CurrentHTTPClient{}.RequestTraceAttrs(req)
if c.duplicate { if c.duplicate {
return append(OldHTTPClient{}.RequestTraceAttrs(req), CurrentHTTPClient{}.RequestTraceAttrs(req)...) return OldHTTPClient{}.RequestTraceAttrs(req, attrs)
} }
return OldHTTPClient{}.RequestTraceAttrs(req) return attrs
} }
// ResponseTraceAttrs returns metric attributes for an HTTP request made by a client. // ResponseTraceAttrs returns metric attributes for an HTTP request made by a client.
func (c HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue { func (c HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue {
attrs := CurrentHTTPClient{}.ResponseTraceAttrs(resp)
if c.duplicate { if c.duplicate {
return append(OldHTTPClient{}.ResponseTraceAttrs(resp), CurrentHTTPClient{}.ResponseTraceAttrs(resp)...) return OldHTTPClient{}.ResponseTraceAttrs(resp, attrs)
} }
return attrs
return OldHTTPClient{}.ResponseTraceAttrs(resp)
} }
func (c HTTPClient) Status(code int) (codes.Code, string) { func (c HTTPClient) Status(code int) (codes.Code, string) {
@@ -232,11 +251,7 @@ func (c HTTPClient) Status(code int) (codes.Code, string) {
} }
func (c HTTPClient) ErrorType(err error) attribute.KeyValue { func (c HTTPClient) ErrorType(err error) attribute.KeyValue {
if c.duplicate {
return CurrentHTTPClient{}.ErrorType(err) return CurrentHTTPClient{}.ErrorType(err)
}
return attribute.KeyValue{}
} }
type MetricOpts struct { type MetricOpts struct {
@@ -255,17 +270,17 @@ func (o MetricOpts) AddOptions() metric.AddOption {
func (c HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts { func (c HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts {
opts := map[string]MetricOpts{} opts := map[string]MetricOpts{}
attributes := OldHTTPClient{}.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes) attributes := CurrentHTTPClient{}.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes)
set := metric.WithAttributeSet(attribute.NewSet(attributes...)) set := metric.WithAttributeSet(attribute.NewSet(attributes...))
opts["old"] = MetricOpts{ opts["new"] = MetricOpts{
measurement: set, measurement: set,
addOptions: set, addOptions: set,
} }
if c.duplicate { if c.duplicate {
attributes := CurrentHTTPClient{}.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes) attributes := OldHTTPClient{}.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes)
set := metric.WithAttributeSet(attribute.NewSet(attributes...)) set := metric.WithAttributeSet(attribute.NewSet(attributes...))
opts["new"] = MetricOpts{ opts["old"] = MetricOpts{
measurement: set, measurement: set,
addOptions: set, addOptions: set,
} }
@@ -275,17 +290,17 @@ func (c HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts {
} }
func (s HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts map[string]MetricOpts) { func (s HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts map[string]MetricOpts) {
if s.requestBytesCounter == nil || s.latencyMeasure == nil { if s.requestBodySize == nil || s.requestDuration == nil {
// This will happen if an HTTPClient{} is used instead of NewHTTPClient(). // This will happen if an HTTPClient{} is used instead of NewHTTPClient().
return return
} }
s.requestBytesCounter.Add(ctx, md.RequestSize, opts["old"].AddOptions()) s.requestBodySize.Record(ctx, md.RequestSize, opts["new"].MeasurementOption())
s.latencyMeasure.Record(ctx, md.ElapsedTime, opts["old"].MeasurementOption()) s.requestDuration.Record(ctx, md.ElapsedTime/1000, opts["new"].MeasurementOption())
if s.duplicate { if s.duplicate {
s.requestBodySize.Record(ctx, md.RequestSize, opts["new"].MeasurementOption()) s.requestBytesCounter.Add(ctx, md.RequestSize, opts["old"].AddOptions())
s.requestDuration.Record(ctx, md.ElapsedTime, opts["new"].MeasurementOption()) s.latencyMeasure.Record(ctx, md.ElapsedTime, opts["old"].MeasurementOption())
} }
} }
@@ -299,9 +314,10 @@ func (s HTTPClient) RecordResponseSize(ctx context.Context, responseData int64,
} }
func (s HTTPClient) TraceAttributes(host string) []attribute.KeyValue { func (s HTTPClient) TraceAttributes(host string) []attribute.KeyValue {
attrs := CurrentHTTPClient{}.TraceAttributes(host)
if s.duplicate { if s.duplicate {
return append(OldHTTPClient{}.TraceAttributes(host), CurrentHTTPClient{}.TraceAttributes(host)...) return OldHTTPClient{}.TraceAttributes(host, attrs)
} }
return OldHTTPClient{}.TraceAttributes(host) return attrs
} }

View File

@@ -1,9 +1,11 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/httpconv.go.tmpl // source: internal/shared/semconv/httpconv.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package semconv provides OpenTelemetry semantic convention types and
// functionality.
package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv" package semconv // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv"
import ( import (
@@ -20,9 +22,14 @@ import (
semconvNew "go.opentelemetry.io/otel/semconv/v1.26.0" semconvNew "go.opentelemetry.io/otel/semconv/v1.26.0"
) )
type RequestTraceAttrsOpts struct {
// If set, this is used as value for the "http.client_ip" attribute.
HTTPClientIP string
}
type CurrentHTTPServer struct{} type CurrentHTTPServer struct{}
// TraceRequest returns trace attributes for an HTTP request received by a // RequestTraceAttrs returns trace attributes for an HTTP request received by a
// server. // server.
// //
// The server must be the primary server name if it is known. For example this // The server must be the primary server name if it is known. For example this
@@ -38,7 +45,7 @@ type CurrentHTTPServer struct{}
// //
// If the primary server name is not known, server should be an empty string. // If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue { func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request, opts RequestTraceAttrsOpts) []attribute.KeyValue {
count := 3 // ServerAddress, Method, Scheme count := 3 // ServerAddress, Method, Scheme
var host string var host string
@@ -65,7 +72,8 @@ func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) [
scheme := n.scheme(req.TLS != nil) scheme := n.scheme(req.TLS != nil)
if peer, peerPort := SplitHostPort(req.RemoteAddr); peer != "" { peer, peerPort := SplitHostPort(req.RemoteAddr)
if peer != "" {
// The Go HTTP server sets RemoteAddr to "IP:port", this will not be a // The Go HTTP server sets RemoteAddr to "IP:port", this will not be a
// file-path that would be interpreted with a sock family. // file-path that would be interpreted with a sock family.
count++ count++
@@ -79,7 +87,17 @@ func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) [
count++ count++
} }
clientIP := serverClientIP(req.Header.Get("X-Forwarded-For")) // For client IP, use, in order:
// 1. The value passed in the options
// 2. The value in the X-Forwarded-For header
// 3. The peer address
clientIP := opts.HTTPClientIP
if clientIP == "" {
clientIP = serverClientIP(req.Header.Get("X-Forwarded-For"))
if clientIP == "" {
clientIP = peer
}
}
if clientIP != "" { if clientIP != "" {
count++ count++
} }
@@ -96,6 +114,11 @@ func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) [
count++ count++
} }
route := httpRoute(req.Pattern)
if route != "" {
count++
}
attrs := make([]attribute.KeyValue, 0, count) attrs := make([]attribute.KeyValue, 0, count)
attrs = append(attrs, attrs = append(attrs,
semconvNew.ServerAddress(host), semconvNew.ServerAddress(host),
@@ -119,7 +142,7 @@ func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) [
} }
} }
if useragent := req.UserAgent(); useragent != "" { if useragent != "" {
attrs = append(attrs, semconvNew.UserAgentOriginal(useragent)) attrs = append(attrs, semconvNew.UserAgentOriginal(useragent))
} }
@@ -138,10 +161,14 @@ func (n CurrentHTTPServer) RequestTraceAttrs(server string, req *http.Request) [
attrs = append(attrs, semconvNew.NetworkProtocolVersion(protoVersion)) attrs = append(attrs, semconvNew.NetworkProtocolVersion(protoVersion))
} }
if route != "" {
attrs = append(attrs, n.Route(route))
}
return attrs return attrs
} }
func (o CurrentHTTPServer) NetworkTransportAttr(network string) attribute.KeyValue { func (n CurrentHTTPServer) NetworkTransportAttr(network string) attribute.KeyValue {
switch network { switch network {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
return semconvNew.NetworkTransportTCP return semconvNew.NetworkTransportTCP
@@ -176,9 +203,11 @@ func (n CurrentHTTPServer) scheme(https bool) attribute.KeyValue { // nolint:rev
return semconvNew.URLScheme("http") return semconvNew.URLScheme("http")
} }
// TraceResponse returns trace attributes for telemetry from an HTTP response. // ResponseTraceAttrs returns trace attributes for telemetry from an HTTP
// response.
// //
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted. // If any of the fields in the ResponseTelemetry are not set the attribute will
// be omitted.
func (n CurrentHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue { func (n CurrentHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue {
var count int var count int
@@ -241,6 +270,7 @@ func (n CurrentHTTPServer) createMeasures(meter metric.Meter) (metric.Int64Histo
semconvNew.HTTPServerRequestDurationName, semconvNew.HTTPServerRequestDurationName,
metric.WithUnit(semconvNew.HTTPServerRequestDurationUnit), metric.WithUnit(semconvNew.HTTPServerRequestDurationUnit),
metric.WithDescription(semconvNew.HTTPServerRequestDurationDescription), metric.WithDescription(semconvNew.HTTPServerRequestDurationDescription),
metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10),
) )
handleErr(err) handleErr(err)
@@ -459,6 +489,7 @@ func (n CurrentHTTPClient) createMeasures(meter metric.Meter) (metric.Int64Histo
semconvNew.HTTPClientRequestDurationName, semconvNew.HTTPClientRequestDurationName,
metric.WithUnit(semconvNew.HTTPClientRequestDurationUnit), metric.WithUnit(semconvNew.HTTPClientRequestDurationUnit),
metric.WithDescription(semconvNew.HTTPClientRequestDurationDescription), metric.WithDescription(semconvNew.HTTPClientRequestDurationDescription),
metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10),
) )
handleErr(err) handleErr(err)
@@ -501,7 +532,7 @@ func (n CurrentHTTPClient) MetricAttributes(req *http.Request, statusCode int, a
attributes = append(attributes, attributes = append(attributes,
semconvNew.HTTPRequestMethodKey.String(standardizeHTTPMethod(req.Method)), semconvNew.HTTPRequestMethodKey.String(standardizeHTTPMethod(req.Method)),
semconvNew.ServerAddress(requestHost), semconvNew.ServerAddress(requestHost),
n.scheme(req.TLS != nil), n.scheme(req),
) )
if port > 0 { if port > 0 {
@@ -520,15 +551,18 @@ func (n CurrentHTTPClient) MetricAttributes(req *http.Request, statusCode int, a
return attributes return attributes
} }
// Attributes for httptrace. // TraceAttributes returns attributes for httptrace.
func (n CurrentHTTPClient) TraceAttributes(host string) []attribute.KeyValue { func (n CurrentHTTPClient) TraceAttributes(host string) []attribute.KeyValue {
return []attribute.KeyValue{ return []attribute.KeyValue{
semconvNew.ServerAddress(host), semconvNew.ServerAddress(host),
} }
} }
func (n CurrentHTTPClient) scheme(https bool) attribute.KeyValue { // nolint:revive func (n CurrentHTTPClient) scheme(req *http.Request) attribute.KeyValue {
if https { if req.URL != nil && req.URL.Scheme != "" {
return semconvNew.URLScheme(req.URL.Scheme)
}
if req.TLS != nil {
return semconvNew.URLScheme("https") return semconvNew.URLScheme("https")
} }
return semconvNew.URLScheme("http") return semconvNew.URLScheme("http")

View File

@@ -1,4 +1,4 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/util.go.tmpl // source: internal/shared/semconv/util.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
@@ -28,17 +28,17 @@ func SplitHostPort(hostport string) (host string, port int) {
port = -1 port = -1
if strings.HasPrefix(hostport, "[") { if strings.HasPrefix(hostport, "[") {
addrEnd := strings.LastIndex(hostport, "]") addrEnd := strings.LastIndexByte(hostport, ']')
if addrEnd < 0 { if addrEnd < 0 {
// Invalid hostport. // Invalid hostport.
return return
} }
if i := strings.LastIndex(hostport[addrEnd:], ":"); i < 0 { if i := strings.LastIndexByte(hostport[addrEnd:], ':'); i < 0 {
host = hostport[1:addrEnd] host = hostport[1:addrEnd]
return return
} }
} else { } else {
if i := strings.LastIndex(hostport, ":"); i < 0 { if i := strings.LastIndexByte(hostport, ':'); i < 0 {
host = hostport host = hostport
return return
} }
@@ -70,12 +70,19 @@ func requiredHTTPPort(https bool, port int) int { // nolint:revive
} }
func serverClientIP(xForwardedFor string) string { func serverClientIP(xForwardedFor string) string {
if idx := strings.Index(xForwardedFor, ","); idx >= 0 { if idx := strings.IndexByte(xForwardedFor, ','); idx >= 0 {
xForwardedFor = xForwardedFor[:idx] xForwardedFor = xForwardedFor[:idx]
} }
return xForwardedFor return xForwardedFor
} }
func httpRoute(pattern string) string {
if idx := strings.IndexByte(pattern, '/'); idx >= 0 {
return pattern[idx:]
}
return ""
}
func netProtocol(proto string) (name string, version string) { func netProtocol(proto string) (name string, version string) {
name, version, _ = strings.Cut(proto, "/") name, version, _ = strings.Cut(proto, "/")
switch name { switch name {

View File

@@ -1,4 +1,4 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconv/v120.0.go.tmpl // source: internal/shared/semconv/v120.0.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
@@ -37,8 +37,8 @@ type OldHTTPServer struct{}
// //
// If the primary server name is not known, server should be an empty string. // If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead. // The req Host will be used to determine the server instead.
func (o OldHTTPServer) RequestTraceAttrs(server string, req *http.Request) []attribute.KeyValue { func (o OldHTTPServer) RequestTraceAttrs(server string, req *http.Request, attrs []attribute.KeyValue) []attribute.KeyValue {
return semconvutil.HTTPServerRequest(server, req) return semconvutil.HTTPServerRequest(server, req, semconvutil.HTTPServerRequestOptions{}, attrs)
} }
func (o OldHTTPServer) NetworkTransportAttr(network string) attribute.KeyValue { func (o OldHTTPServer) NetworkTransportAttr(network string) attribute.KeyValue {
@@ -48,9 +48,7 @@ func (o OldHTTPServer) NetworkTransportAttr(network string) attribute.KeyValue {
// ResponseTraceAttrs returns trace attributes for telemetry from an HTTP response. // ResponseTraceAttrs returns trace attributes for telemetry from an HTTP response.
// //
// If any of the fields in the ResponseTelemetry are not set the attribute will be omitted. // If any of the fields in the ResponseTelemetry are not set the attribute will be omitted.
func (o OldHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry) []attribute.KeyValue { func (o OldHTTPServer) ResponseTraceAttrs(resp ResponseTelemetry, attributes []attribute.KeyValue) []attribute.KeyValue {
attributes := []attribute.KeyValue{}
if resp.ReadBytes > 0 { if resp.ReadBytes > 0 {
attributes = append(attributes, semconv.HTTPRequestContentLength(int(resp.ReadBytes))) attributes = append(attributes, semconv.HTTPRequestContentLength(int(resp.ReadBytes)))
} }
@@ -179,12 +177,12 @@ func (o OldHTTPServer) scheme(https bool) attribute.KeyValue { // nolint:revive
type OldHTTPClient struct{} type OldHTTPClient struct{}
func (o OldHTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue { func (o OldHTTPClient) RequestTraceAttrs(req *http.Request, attrs []attribute.KeyValue) []attribute.KeyValue {
return semconvutil.HTTPClientRequest(req) return semconvutil.HTTPClientRequest(req, attrs)
} }
func (o OldHTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue { func (o OldHTTPClient) ResponseTraceAttrs(resp *http.Response, attrs []attribute.KeyValue) []attribute.KeyValue {
return semconvutil.HTTPClientResponse(resp) return semconvutil.HTTPClientResponse(resp, attrs)
} }
func (o OldHTTPClient) MetricAttributes(req *http.Request, statusCode int, additionalAttributes []attribute.KeyValue) []attribute.KeyValue { func (o OldHTTPClient) MetricAttributes(req *http.Request, statusCode int, additionalAttributes []attribute.KeyValue) []attribute.KeyValue {
@@ -269,9 +267,7 @@ func (o OldHTTPClient) createMeasures(meter metric.Meter) (metric.Int64Counter,
return requestBytesCounter, responseBytesCounter, latencyMeasure return requestBytesCounter, responseBytesCounter, latencyMeasure
} }
// Attributes for httptrace. // TraceAttributes returns attributes for httptrace.
func (c OldHTTPClient) TraceAttributes(host string) []attribute.KeyValue { func (c OldHTTPClient) TraceAttributes(host string, attrs []attribute.KeyValue) []attribute.KeyValue {
return []attribute.KeyValue{ return append(attrs, semconv.NetHostName(host))
semconv.NetHostName(host),
}
} }

View File

@@ -1,14 +1,16 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconvutil/httpconv.go.tmpl // source: internal/shared/semconvutil/httpconv.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package semconvutil provides OpenTelemetry semantic convention utilities.
package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil" package semconvutil // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil"
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"slices"
"strings" "strings"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
@@ -16,6 +18,11 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.20.0" semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
) )
type HTTPServerRequestOptions struct {
// If set, this is used as value for the "http.client_ip" attribute.
HTTPClientIP string
}
// HTTPClientResponse returns trace attributes for an HTTP response received by a // HTTPClientResponse returns trace attributes for an HTTP response received by a
// client from a server. It will return the following attributes if the related // client from a server. It will return the following attributes if the related
// values are defined in resp: "http.status.code", // values are defined in resp: "http.status.code",
@@ -26,9 +33,9 @@ import (
// attributes. If a complete set of attributes can be generated using the // attributes. If a complete set of attributes can be generated using the
// request contained in resp. For example: // request contained in resp. For example:
// //
// append(HTTPClientResponse(resp), ClientRequest(resp.Request)...) // HTTPClientResponse(resp, ClientRequest(resp.Request)))
func HTTPClientResponse(resp *http.Response) []attribute.KeyValue { func HTTPClientResponse(resp *http.Response, attrs []attribute.KeyValue) []attribute.KeyValue {
return hc.ClientResponse(resp) return hc.ClientResponse(resp, attrs)
} }
// HTTPClientRequest returns trace attributes for an HTTP request made by a client. // HTTPClientRequest returns trace attributes for an HTTP request made by a client.
@@ -36,8 +43,8 @@ func HTTPClientResponse(resp *http.Response) []attribute.KeyValue {
// "net.peer.name". The following attributes are returned if the related values // "net.peer.name". The following attributes are returned if the related values
// are defined in req: "net.peer.port", "user_agent.original", // are defined in req: "net.peer.port", "user_agent.original",
// "http.request_content_length". // "http.request_content_length".
func HTTPClientRequest(req *http.Request) []attribute.KeyValue { func HTTPClientRequest(req *http.Request, attrs []attribute.KeyValue) []attribute.KeyValue {
return hc.ClientRequest(req) return hc.ClientRequest(req, attrs)
} }
// HTTPClientRequestMetrics returns metric attributes for an HTTP request made by a client. // HTTPClientRequestMetrics returns metric attributes for an HTTP request made by a client.
@@ -75,8 +82,8 @@ func HTTPClientStatus(code int) (codes.Code, string) {
// "http.target", "net.host.name". The following attributes are returned if // "http.target", "net.host.name". The following attributes are returned if
// they related values are defined in req: "net.host.port", "net.sock.peer.addr", // they related values are defined in req: "net.host.port", "net.sock.peer.addr",
// "net.sock.peer.port", "user_agent.original", "http.client_ip". // "net.sock.peer.port", "user_agent.original", "http.client_ip".
func HTTPServerRequest(server string, req *http.Request) []attribute.KeyValue { func HTTPServerRequest(server string, req *http.Request, opts HTTPServerRequestOptions, attrs []attribute.KeyValue) []attribute.KeyValue {
return hc.ServerRequest(server, req) return hc.ServerRequest(server, req, opts, attrs)
} }
// HTTPServerRequestMetrics returns metric attributes for an HTTP request received by a // HTTPServerRequestMetrics returns metric attributes for an HTTP request received by a
@@ -153,8 +160,8 @@ var hc = &httpConv{
// attributes. If a complete set of attributes can be generated using the // attributes. If a complete set of attributes can be generated using the
// request contained in resp. For example: // request contained in resp. For example:
// //
// append(ClientResponse(resp), ClientRequest(resp.Request)...) // ClientResponse(resp, ClientRequest(resp.Request))
func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue { func (c *httpConv) ClientResponse(resp *http.Response, attrs []attribute.KeyValue) []attribute.KeyValue {
/* The following semantic conventions are returned if present: /* The following semantic conventions are returned if present:
http.status_code int http.status_code int
http.response_content_length int http.response_content_length int
@@ -166,8 +173,11 @@ func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue {
if resp.ContentLength > 0 { if resp.ContentLength > 0 {
n++ n++
} }
if n == 0 {
return attrs
}
attrs := make([]attribute.KeyValue, 0, n) attrs = slices.Grow(attrs, n)
if resp.StatusCode > 0 { if resp.StatusCode > 0 {
attrs = append(attrs, c.HTTPStatusCodeKey.Int(resp.StatusCode)) attrs = append(attrs, c.HTTPStatusCodeKey.Int(resp.StatusCode))
} }
@@ -182,7 +192,7 @@ func (c *httpConv) ClientResponse(resp *http.Response) []attribute.KeyValue {
// "net.peer.name". The following attributes are returned if the related values // "net.peer.name". The following attributes are returned if the related values
// are defined in req: "net.peer.port", "user_agent.original", // are defined in req: "net.peer.port", "user_agent.original",
// "http.request_content_length", "user_agent.original". // "http.request_content_length", "user_agent.original".
func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue { func (c *httpConv) ClientRequest(req *http.Request, attrs []attribute.KeyValue) []attribute.KeyValue {
/* The following semantic conventions are returned if present: /* The following semantic conventions are returned if present:
http.method string http.method string
user_agent.original string user_agent.original string
@@ -221,8 +231,7 @@ func (c *httpConv) ClientRequest(req *http.Request) []attribute.KeyValue {
n++ n++
} }
attrs := make([]attribute.KeyValue, 0, n) attrs = slices.Grow(attrs, n)
attrs = append(attrs, c.method(req.Method)) attrs = append(attrs, c.method(req.Method))
var u string var u string
@@ -305,7 +314,7 @@ func (c *httpConv) ClientRequestMetrics(req *http.Request) []attribute.KeyValue
// related values are defined in req: "net.host.port", "net.sock.peer.addr", // related values are defined in req: "net.host.port", "net.sock.peer.addr",
// "net.sock.peer.port", "user_agent.original", "http.client_ip", // "net.sock.peer.port", "user_agent.original", "http.client_ip",
// "net.protocol.name", "net.protocol.version". // "net.protocol.name", "net.protocol.version".
func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.KeyValue { func (c *httpConv) ServerRequest(server string, req *http.Request, opts HTTPServerRequestOptions, attrs []attribute.KeyValue) []attribute.KeyValue {
/* The following semantic conventions are returned if present: /* The following semantic conventions are returned if present:
http.method string http.method string
http.scheme string http.scheme string
@@ -358,7 +367,17 @@ func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.K
n++ n++
} }
clientIP := serverClientIP(req.Header.Get("X-Forwarded-For")) // For client IP, use, in order:
// 1. The value passed in the options
// 2. The value in the X-Forwarded-For header
// 3. The peer address
clientIP := opts.HTTPClientIP
if clientIP == "" {
clientIP = serverClientIP(req.Header.Get("X-Forwarded-For"))
if clientIP == "" {
clientIP = peer
}
}
if clientIP != "" { if clientIP != "" {
n++ n++
} }
@@ -378,7 +397,7 @@ func (c *httpConv) ServerRequest(server string, req *http.Request) []attribute.K
n++ n++
} }
attrs := make([]attribute.KeyValue, 0, n) attrs = slices.Grow(attrs, n)
attrs = append(attrs, c.method(req.Method)) attrs = append(attrs, c.method(req.Method))
attrs = append(attrs, c.scheme(req.TLS != nil)) attrs = append(attrs, c.scheme(req.TLS != nil))

View File

@@ -1,4 +1,4 @@
// Code created by gotmpl. DO NOT MODIFY. // Code generated by gotmpl. DO NOT MODIFY.
// source: internal/shared/semconvutil/netconv.go.tmpl // source: internal/shared/semconvutil/netconv.go.tmpl
// Copyright The OpenTelemetry Authors // Copyright The OpenTelemetry Authors

View File

@@ -35,14 +35,14 @@ func (l *Labeler) Get() []attribute.KeyValue {
type labelerContextKeyType int type labelerContextKeyType int
const lablelerContextKey labelerContextKeyType = 0 const labelerContextKey labelerContextKeyType = 0
// ContextWithLabeler returns a new context with the provided Labeler instance. // ContextWithLabeler returns a new context with the provided Labeler instance.
// Attributes added to the specified labeler will be injected into metrics // Attributes added to the specified labeler will be injected into metrics
// emitted by the instrumentation. Only one labeller can be injected into the // emitted by the instrumentation. Only one labeller can be injected into the
// context. Injecting it multiple times will override the previous calls. // context. Injecting it multiple times will override the previous calls.
func ContextWithLabeler(parent context.Context, l *Labeler) context.Context { func ContextWithLabeler(parent context.Context, l *Labeler) context.Context {
return context.WithValue(parent, lablelerContextKey, l) return context.WithValue(parent, labelerContextKey, l)
} }
// LabelerFromContext retrieves a Labeler instance from the provided context if // LabelerFromContext retrieves a Labeler instance from the provided context if
@@ -50,7 +50,7 @@ func ContextWithLabeler(parent context.Context, l *Labeler) context.Context {
// Labeler is returned and the second return value is false. In this case it is // Labeler is returned and the second return value is false. In this case it is
// safe to use the Labeler but any attributes added to it will not be used. // safe to use the Labeler but any attributes added to it will not be used.
func LabelerFromContext(ctx context.Context) (*Labeler, bool) { func LabelerFromContext(ctx context.Context) (*Labeler, bool) {
l, ok := ctx.Value(lablelerContextKey).(*Labeler) l, ok := ctx.Value(labelerContextKey).(*Labeler)
if !ok { if !ok {
l = &Labeler{} l = &Labeler{}
} }

View File

@@ -5,13 +5,6 @@ package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http
// Version is the current release version of the otelhttp instrumentation. // Version is the current release version of the otelhttp instrumentation.
func Version() string { func Version() string {
return "0.60.0" return "0.61.0"
// This string is updated by the pre_release.sh script during release // This string is updated by the pre_release.sh script during release
} }
// SemVersion is the semantic version to be supplied to tracer/meter creation.
//
// Deprecated: Use [Version] instead.
func SemVersion() string {
return Version()
}

View File

@@ -1066,6 +1066,8 @@ func (c *dockerClient) getBlob(ctx context.Context, ref dockerReference, info ty
cache.RecordKnownLocation(ref.Transport(), bicTransportScope(ref), info.Digest, newBICLocationReference(ref)) cache.RecordKnownLocation(ref.Transport(), bicTransportScope(ref), info.Digest, newBICLocationReference(ref))
blobSize, err := getBlobSize(res) blobSize, err := getBlobSize(res)
if err != nil { if err != nil {
// See above, we don't guarantee returning a size
logrus.Debugf("failed to get blob size: %v", err)
blobSize = -1 blobSize = -1
} }

View File

@@ -233,6 +233,8 @@ func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context, _ *types.Ma
layers[idx].MediaType = imgspecv1.MediaTypeImageLayer layers[idx].MediaType = imgspecv1.MediaTypeImageLayer
case manifest.DockerV2Schema2LayerMediaType: case manifest.DockerV2Schema2LayerMediaType:
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerGzip layers[idx].MediaType = imgspecv1.MediaTypeImageLayerGzip
case manifest.DockerV2SchemaLayerMediaTypeZstd:
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerZstd
default: default:
return nil, fmt.Errorf("Unknown media type during manifest conversion: %q", m.m.LayersDescriptors[idx].MediaType) return nil, fmt.Errorf("Unknown media type during manifest conversion: %q", m.m.LayersDescriptors[idx].MediaType)
} }

View File

@@ -288,7 +288,7 @@ func (m *manifestOCI1) convertToManifestSchema2(_ context.Context, options *type
case imgspecv1.MediaTypeImageLayerGzip: case imgspecv1.MediaTypeImageLayerGzip:
layers[idx].MediaType = manifest.DockerV2Schema2LayerMediaType layers[idx].MediaType = manifest.DockerV2Schema2LayerMediaType
case imgspecv1.MediaTypeImageLayerZstd: case imgspecv1.MediaTypeImageLayerZstd:
return nil, fmt.Errorf("Error during manifest conversion: %q: zstd compression is not supported for docker images", layers[idx].MediaType) return nil, fmt.Errorf("Error during manifest conversion: %q: zstd compression is not officially supported for docker images", layers[idx].MediaType)
case ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc, ociencspec.MediaTypeLayerZstdEnc, case ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc, ociencspec.MediaTypeLayerZstdEnc,
ociencspec.MediaTypeLayerNonDistributableEnc, ociencspec.MediaTypeLayerNonDistributableGzipEnc, ociencspec.MediaTypeLayerNonDistributableZstdEnc: ociencspec.MediaTypeLayerNonDistributableEnc, ociencspec.MediaTypeLayerNonDistributableGzipEnc, ociencspec.MediaTypeLayerNonDistributableZstdEnc:
return nil, fmt.Errorf("during manifest conversion: encrypted layers (%q) are not supported in docker images", layers[idx].MediaType) return nil, fmt.Errorf("during manifest conversion: encrypted layers (%q) are not supported in docker images", layers[idx].MediaType)

View File

@@ -26,6 +26,8 @@ const (
DockerV2Schema2LayerMediaType = "application/vnd.docker.image.rootfs.diff.tar.gzip" DockerV2Schema2LayerMediaType = "application/vnd.docker.image.rootfs.diff.tar.gzip"
// DockerV2SchemaLayerMediaTypeUncompressed is the mediaType used for uncompressed layers. // DockerV2SchemaLayerMediaTypeUncompressed is the mediaType used for uncompressed layers.
DockerV2SchemaLayerMediaTypeUncompressed = "application/vnd.docker.image.rootfs.diff.tar" DockerV2SchemaLayerMediaTypeUncompressed = "application/vnd.docker.image.rootfs.diff.tar"
// DockerV2Schema2LayerMediaType is the MIME type used for schema 2 layers.
DockerV2SchemaLayerMediaTypeZstd = "application/vnd.docker.image.rootfs.diff.tar.zstd"
// DockerV2ListMediaType MIME type represents Docker manifest schema 2 list // DockerV2ListMediaType MIME type represents Docker manifest schema 2 list
DockerV2ListMediaType = "application/vnd.docker.distribution.manifest.list.v2+json" DockerV2ListMediaType = "application/vnd.docker.distribution.manifest.list.v2+json"
// DockerV2Schema2ForeignLayerMediaType is the MIME type used for schema 2 foreign layers. // DockerV2Schema2ForeignLayerMediaType is the MIME type used for schema 2 foreign layers.

View File

@@ -26,6 +26,9 @@ const (
DockerV2Schema2LayerMediaType = manifest.DockerV2Schema2LayerMediaType DockerV2Schema2LayerMediaType = manifest.DockerV2Schema2LayerMediaType
// DockerV2SchemaLayerMediaTypeUncompressed is the mediaType used for uncompressed layers. // DockerV2SchemaLayerMediaTypeUncompressed is the mediaType used for uncompressed layers.
DockerV2SchemaLayerMediaTypeUncompressed = manifest.DockerV2SchemaLayerMediaTypeUncompressed DockerV2SchemaLayerMediaTypeUncompressed = manifest.DockerV2SchemaLayerMediaTypeUncompressed
// DockerV2SchemaLayerMediaTypeZstd is the mediaType used for zstd layers.
// Warning: This mediaType is not officially supported in https://github.com/distribution/distribution/blob/main/docs/content/spec/manifest-v2-2.md but some images may exhibit it. Support is partial.
DockerV2SchemaLayerMediaTypeZstd = manifest.DockerV2SchemaLayerMediaTypeZstd
// DockerV2ListMediaType MIME type represents Docker manifest schema 2 list // DockerV2ListMediaType MIME type represents Docker manifest schema 2 list
DockerV2ListMediaType = manifest.DockerV2ListMediaType DockerV2ListMediaType = manifest.DockerV2ListMediaType
// DockerV2Schema2ForeignLayerMediaType is the MIME type used for schema 2 foreign layers. // DockerV2Schema2ForeignLayerMediaType is the MIME type used for schema 2 foreign layers.
@@ -41,7 +44,7 @@ type NonImageArtifactError = manifest.NonImageArtifactError
// SupportedSchema2MediaType checks if the specified string is a supported Docker v2s2 media type. // SupportedSchema2MediaType checks if the specified string is a supported Docker v2s2 media type.
func SupportedSchema2MediaType(m string) error { func SupportedSchema2MediaType(m string) error {
switch m { switch m {
case DockerV2ListMediaType, DockerV2Schema1MediaType, DockerV2Schema1SignedMediaType, DockerV2Schema2ConfigMediaType, DockerV2Schema2ForeignLayerMediaType, DockerV2Schema2ForeignLayerMediaTypeGzip, DockerV2Schema2LayerMediaType, DockerV2Schema2MediaType, DockerV2SchemaLayerMediaTypeUncompressed: case DockerV2ListMediaType, DockerV2Schema1MediaType, DockerV2Schema1SignedMediaType, DockerV2Schema2ConfigMediaType, DockerV2Schema2ForeignLayerMediaType, DockerV2Schema2ForeignLayerMediaTypeGzip, DockerV2Schema2LayerMediaType, DockerV2Schema2MediaType, DockerV2SchemaLayerMediaTypeUncompressed, DockerV2SchemaLayerMediaTypeZstd:
return nil return nil
default: default:
return fmt.Errorf("unsupported docker v2s2 media type: %q", m) return fmt.Errorf("unsupported docker v2s2 media type: %q", m)

View File

@@ -6,7 +6,7 @@ const (
// VersionMajor is for an API incompatible changes // VersionMajor is for an API incompatible changes
VersionMajor = 5 VersionMajor = 5
// VersionMinor is for functionality in a backwards-compatible manner // VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 37 VersionMinor = 38
// VersionPatch is for backwards-compatible bug fixes // VersionPatch is for backwards-compatible bug fixes
VersionPatch = 0 VersionPatch = 0

View File

@@ -51,7 +51,6 @@ func NewPatternMatcher(patterns []string) (*PatternMatcher, error) {
return nil, err return nil, err
} }
newp.cleanedPattern = p newp.cleanedPattern = p
newp.dirs = strings.Split(p, string(os.PathSeparator))
pm.patterns = append(pm.patterns, newp) pm.patterns = append(pm.patterns, newp)
} }
return pm, nil return pm, nil
@@ -168,7 +167,6 @@ func (pm *PatternMatcher) Patterns() []*Pattern {
// Pattern defines a single regexp used to filter file paths. // Pattern defines a single regexp used to filter file paths.
type Pattern struct { type Pattern struct {
cleanedPattern string cleanedPattern string
dirs []string
regexp *regexp.Regexp regexp *regexp.Regexp
exclusion bool exclusion bool
} }

View File

@@ -8,7 +8,6 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"syscall" "syscall"
@@ -112,7 +111,7 @@ func LookupUser(username string) (user.User, error) {
return usr, nil return usr, nil
} }
// local files lookup failed; attempt to call `getent` to query configured passwd dbs // local files lookup failed; attempt to call `getent` to query configured passwd dbs
usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username)) usr, err = getentUser(username)
if err != nil { if err != nil {
return user.User{}, err return user.User{}, err
} }
@@ -128,11 +127,11 @@ func LookupUID(uid int) (user.User, error) {
return usr, nil return usr, nil
} }
// local files lookup failed; attempt to call `getent` to query configured passwd dbs // local files lookup failed; attempt to call `getent` to query configured passwd dbs
return getentUser(fmt.Sprintf("%s %d", "passwd", uid)) return getentUser(fmt.Sprintf("%d", uid))
} }
func getentUser(args string) (user.User, error) { func getentUser(key string) (user.User, error) {
reader, err := callGetent(args) reader, err := callGetent("passwd", key)
if err != nil { if err != nil {
return user.User{}, err return user.User{}, err
} }
@@ -141,7 +140,7 @@ func getentUser(args string) (user.User, error) {
return user.User{}, err return user.User{}, err
} }
if len(users) == 0 { if len(users) == 0 {
return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1]) return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", key)
} }
return users[0], nil return users[0], nil
} }
@@ -155,7 +154,7 @@ func LookupGroup(groupname string) (user.Group, error) {
return group, nil return group, nil
} }
// local files lookup failed; attempt to call `getent` to query configured group dbs // local files lookup failed; attempt to call `getent` to query configured group dbs
return getentGroup(fmt.Sprintf("%s %s", "group", groupname)) return getentGroup(groupname)
} }
// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, // LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID,
@@ -167,11 +166,11 @@ func LookupGID(gid int) (user.Group, error) {
return group, nil return group, nil
} }
// local files lookup failed; attempt to call `getent` to query configured group dbs // local files lookup failed; attempt to call `getent` to query configured group dbs
return getentGroup(fmt.Sprintf("%s %d", "group", gid)) return getentGroup(fmt.Sprintf("%d", gid))
} }
func getentGroup(args string) (user.Group, error) { func getentGroup(key string) (user.Group, error) {
reader, err := callGetent(args) reader, err := callGetent("group", key)
if err != nil { if err != nil {
return user.Group{}, err return user.Group{}, err
} }
@@ -180,18 +179,18 @@ func getentGroup(args string) (user.Group, error) {
return user.Group{}, err return user.Group{}, err
} }
if len(groups) == 0 { if len(groups) == 0 {
return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1]) return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", key)
} }
return groups[0], nil return groups[0], nil
} }
func callGetent(args string) (io.Reader, error) { func callGetent(db, key string) (io.Reader, error) {
entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") }) entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") })
// if no `getent` command on host, can't do anything else // if no `getent` command on host, can't do anything else
if getentCmd == "" { if getentCmd == "" {
return nil, fmt.Errorf("") return nil, fmt.Errorf("")
} }
out, err := execCmd(getentCmd, args) out, err := execCmd(getentCmd, db, key)
if err != nil { if err != nil {
exitCode, errC := system.GetExitCode(err) exitCode, errC := system.GetExitCode(err)
if errC != nil { if errC != nil {
@@ -201,8 +200,7 @@ func callGetent(args string) (io.Reader, error) {
case 1: case 1:
return nil, fmt.Errorf("getent reported invalid parameters/database unknown") return nil, fmt.Errorf("getent reported invalid parameters/database unknown")
case 2: case 2:
terms := strings.Split(args, " ") return nil, fmt.Errorf("getent unable to find entry %q in %s database", key, db)
return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0])
case 3: case 3:
return nil, fmt.Errorf("getent database doesn't support enumeration") return nil, fmt.Errorf("getent database doesn't support enumeration")
default: default:

View File

@@ -2,6 +2,7 @@ package idtools
import ( import (
"fmt" "fmt"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -17,19 +18,12 @@ import (
var ( var (
once sync.Once once sync.Once
userCommand string userCommand []string // command, args…, to be finished by adding an user name
cmdTemplates = map[string]string{
"adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s",
"useradd": "-r -s /bin/false %s",
"usermod": "-%s %d-%d %s",
}
idOutRegexp = regexp.Delayed(`uid=([0-9]+).*gid=([0-9]+)`) idOutRegexp = regexp.Delayed(`uid=([0-9]+).*gid=([0-9]+)`)
// default length for a UID/GID subordinate range // default length for a UID/GID subordinate range
defaultRangeLen = 65536 defaultRangeLen = 65536
defaultRangeStart = 100000 defaultRangeStart = 100000
userMod = "usermod"
) )
// AddNamespaceRangesUser takes a username and uses the standard system // AddNamespaceRangesUser takes a username and uses the standard system
@@ -72,16 +66,16 @@ func addUser(userName string) error {
once.Do(func() { once.Do(func() {
// set up which commands are used for adding users/groups dependent on distro // set up which commands are used for adding users/groups dependent on distro
if _, err := resolveBinary("adduser"); err == nil { if _, err := resolveBinary("adduser"); err == nil {
userCommand = "adduser" userCommand = []string{"adduser", "--system", "--shell", "/bin/false", "--no-create-home", "--disabled-login", "--disabled-password", "--group"}
} else if _, err := resolveBinary("useradd"); err == nil { } else if _, err := resolveBinary("useradd"); err == nil {
userCommand = "useradd" userCommand = []string{"useradd", "-r", "-s", "/bin/false"}
} }
}) })
if userCommand == "" { if userCommand == nil {
return fmt.Errorf("cannot add user; no useradd/adduser binary found") return fmt.Errorf("cannot add user; no useradd/adduser binary found")
} }
args := fmt.Sprintf(cmdTemplates[userCommand], userName) args := append(slices.Clone(userCommand), userName)
out, err := execCmd(userCommand, args) out, err := execCmd(args[0], args[1:]...)
if err != nil { if err != nil {
return fmt.Errorf("failed to add user with error: %w; output: %q", err, string(out)) return fmt.Errorf("failed to add user with error: %w; output: %q", err, string(out))
} }
@@ -101,7 +95,7 @@ func createSubordinateRanges(name string) error {
if err != nil { if err != nil {
return fmt.Errorf("can't find available subuid range: %w", err) return fmt.Errorf("can't find available subuid range: %w", err)
} }
out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name)) out, err := execCmd("usermod", "-v", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name)
if err != nil { if err != nil {
return fmt.Errorf("unable to add subuid range to user: %q; output: %s, err: %w", name, out, err) return fmt.Errorf("unable to add subuid range to user: %q; output: %s, err: %w", name, out, err)
} }
@@ -117,7 +111,7 @@ func createSubordinateRanges(name string) error {
if err != nil { if err != nil {
return fmt.Errorf("can't find available subgid range: %w", err) return fmt.Errorf("can't find available subgid range: %w", err)
} }
out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name)) out, err := execCmd("usermod", "-w", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name)
if err != nil { if err != nil {
return fmt.Errorf("unable to add subgid range to user: %q; output: %s, err: %w", name, out, err) return fmt.Errorf("unable to add subgid range to user: %q; output: %s, err: %w", name, out, err)
} }

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings"
) )
func resolveBinary(binname string) (string, error) { func resolveBinary(binname string) (string, error) {
@@ -26,7 +25,7 @@ func resolveBinary(binname string) (string, error) {
return "", fmt.Errorf("binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) return "", fmt.Errorf("binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath)
} }
func execCmd(cmd, args string) ([]byte, error) { func execCmd(cmd string, args ...string) ([]byte, error) {
execCmd := exec.Command(cmd, strings.Split(args, " ")...) execCmd := exec.Command(cmd, args...)
return execCmd.CombinedOutput() return execCmd.CombinedOutput()
} }

View File

@@ -121,7 +121,8 @@ func (bp *BytesPipe) Close() error {
// Read reads bytes from BytesPipe. // Read reads bytes from BytesPipe.
// Data could be read only once. // Data could be read only once.
func (bp *BytesPipe) Read(p []byte) (n int, err error) { func (bp *BytesPipe) Read(p []byte) (int, error) {
var n int
bp.mu.Lock() bp.mu.Lock()
if bp.bufLen == 0 { if bp.bufLen == 0 {
if bp.closeErr != nil { if bp.closeErr != nil {
@@ -158,7 +159,7 @@ func (bp *BytesPipe) Read(p []byte) (n int, err error) {
bp.wait.Broadcast() bp.wait.Broadcast()
bp.mu.Unlock() bp.mu.Unlock()
return return n, nil
} }
func returnBuffer(b *fixedBuffer) { func returnBuffer(b *fixedBuffer) {

View File

@@ -83,7 +83,7 @@ func (r *OnEOFReader) Read(p []byte) (n int, err error) {
if err == io.EOF { if err == io.EOF {
r.runFunc() r.runFunc()
} }
return return n, err
} }
// Close closes the file and run the function. // Close closes the file and run the function.

View File

@@ -59,8 +59,8 @@ func NewWriteCounter(w io.Writer) *WriteCounter {
} }
} }
func (wc *WriteCounter) Write(p []byte) (count int, err error) { func (wc *WriteCounter) Write(p []byte) (int, error) {
count, err = wc.Writer.Write(p) count, err := wc.Writer.Write(p)
wc.Count += int64(count) wc.Count += int64(count)
return return count, err
} }

View File

@@ -119,7 +119,7 @@ func ParseOptions(options string) (int, string) {
data []string data []string
) )
for _, o := range strings.Split(options, ",") { for o := range strings.SplitSeq(options, ",") {
// If the option does not exist in the flags table or the flag // If the option does not exist in the flags table or the flag
// is not supported on the platform, // is not supported on the platform,
// then it is a data value for a specific fs type // then it is a data value for a specific fs type
@@ -139,7 +139,7 @@ func ParseOptions(options string) (int, string) {
// ParseTmpfsOptions parse fstab type mount options into flags and data // ParseTmpfsOptions parse fstab type mount options into flags and data
func ParseTmpfsOptions(options string) (int, string, error) { func ParseTmpfsOptions(options string) (int, string, error) {
flags, data := ParseOptions(options) flags, data := ParseOptions(options)
for _, o := range strings.Split(data, ",") { for o := range strings.SplitSeq(data, ",") {
opt, _, _ := strings.Cut(o, "=") opt, _, _ := strings.Cut(o, "=")
if !validFlags[opt] { if !validFlags[opt] {
return 0, "", fmt.Errorf("invalid tmpfs option %q", opt) return 0, "", fmt.Errorf("invalid tmpfs option %q", opt)

View File

@@ -33,8 +33,7 @@ func mount(device, target, mType string, flag uintptr, data string) error {
options := []string{"fspath", target} options := []string{"fspath", target}
if data != "" { if data != "" {
xs := strings.Split(data, ",") for x := range strings.SplitSeq(data, ",") {
for _, x := range xs {
if x == "bind" { if x == "bind" {
isNullFS = true isNullFS = true
continue continue

View File

@@ -29,5 +29,5 @@ func ProcessExitCode(err error) (exitCode int) {
exitCode = 127 exitCode = 127
} }
} }
return return exitCode
} }

View File

@@ -4,10 +4,12 @@ import "syscall"
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type // fromStatT converts a syscall.Stat_t type to a system.Stat_t type
func fromStatT(s *syscall.Stat_t) (*StatT, error) { func fromStatT(s *syscall.Stat_t) (*StatT, error) {
return &StatT{size: s.Size, return &StatT{
size: s.Size,
mode: uint32(s.Mode), mode: uint32(s.Mode),
uid: s.Uid, uid: s.Uid,
gid: s.Gid, gid: s.Gid,
rdev: uint64(s.Rdev), rdev: uint64(s.Rdev),
mtim: s.Mtimespec}, nil mtim: s.Mtimespec,
}, nil
} }

View File

@@ -74,7 +74,7 @@ func Llistxattr(path string) ([]string, error) {
} }
var attrs []string var attrs []string
for _, token := range bytes.Split(dest[:sz], []byte{0}) { for token := range bytes.SplitSeq(dest[:sz], []byte{0}) {
if len(token) > 0 { if len(token) > 0 {
attrs = append(attrs, string(token)) attrs = append(attrs, string(token))
} }

View File

@@ -17,12 +17,10 @@ const (
EOVERFLOW unix.Errno = unix.EOVERFLOW EOVERFLOW unix.Errno = unix.EOVERFLOW
) )
var ( var namespaceMap = map[string]int{
namespaceMap = map[string]int{
"user": EXTATTR_NAMESPACE_USER, "user": EXTATTR_NAMESPACE_USER,
"system": EXTATTR_NAMESPACE_SYSTEM, "system": EXTATTR_NAMESPACE_SYSTEM,
} }
)
func xattrToExtattr(xattr string) (namespace int, extattr string, err error) { func xattrToExtattr(xattr string) (namespace int, extattr string, err error) {
namespaceName, extattr, found := strings.Cut(xattr, ".") namespaceName, extattr, found := strings.Cut(xattr, ".")

View File

@@ -77,7 +77,7 @@ func Llistxattr(path string) ([]string, error) {
} }
var attrs []string var attrs []string
for _, token := range bytes.Split(dest[:sz], []byte{0}) { for token := range bytes.SplitSeq(dest[:sz], []byte{0}) {
if len(token) > 0 { if len(token) > 0 {
attrs = append(attrs, string(token)) attrs = append(attrs, string(token))
} }

View File

@@ -9,7 +9,6 @@
package oauth2 // import "golang.org/x/oauth2" package oauth2 // import "golang.org/x/oauth2"
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"net/http" "net/http"
@@ -158,7 +157,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// PKCE), https://www.oauth.com/oauth2-servers/pkce/ and // PKCE), https://www.oauth.com/oauth2-servers/pkce/ and
// https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches) // https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches)
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
var buf bytes.Buffer var buf strings.Builder
buf.WriteString(c.Endpoint.AuthURL) buf.WriteString(c.Endpoint.AuthURL)
v := url.Values{ v := url.Values{
"response_type": {"code"}, "response_type": {"code"},

20
vendor/modules.txt vendored
View File

@@ -124,7 +124,7 @@ github.com/docker/docker/api/types/time
github.com/docker/docker/api/types/versions github.com/docker/docker/api/types/versions
github.com/docker/docker/api/types/volume github.com/docker/docker/api/types/volume
github.com/docker/docker/client github.com/docker/docker/client
# github.com/docker/docker-credential-helpers v0.9.3 # github.com/docker/docker-credential-helpers v0.9.4
## explicit; go 1.21 ## explicit; go 1.21
github.com/docker/docker-credential-helpers/client github.com/docker/docker-credential-helpers/client
github.com/docker/docker-credential-helpers/credentials github.com/docker/docker-credential-helpers/credentials
@@ -313,6 +313,8 @@ github.com/moby/buildkit/util/suggest
# github.com/moby/docker-image-spec v1.3.1 # github.com/moby/docker-image-spec v1.3.1
## explicit; go 1.18 ## explicit; go 1.18
github.com/moby/docker-image-spec/specs-go/v1 github.com/moby/docker-image-spec/specs-go/v1
# github.com/moby/sys/atomicwriter v0.1.0
## explicit; go 1.18
# github.com/moby/sys/capability v0.4.0 # github.com/moby/sys/capability v0.4.0
## explicit; go 1.21 ## explicit; go 1.21
github.com/moby/sys/capability github.com/moby/sys/capability
@@ -443,8 +445,8 @@ go.mau.fi/util/retryafter
## explicit; go 1.22.0 ## explicit; go 1.22.0
go.opentelemetry.io/auto/sdk go.opentelemetry.io/auto/sdk
go.opentelemetry.io/auto/sdk/internal/telemetry go.opentelemetry.io/auto/sdk/internal/telemetry
# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 # go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0
## explicit; go 1.22.0 ## explicit; go 1.23.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv
@@ -472,8 +474,8 @@ go.opentelemetry.io/otel/trace
go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/embedded
go.opentelemetry.io/otel/trace/internal/telemetry go.opentelemetry.io/otel/trace/internal/telemetry
go.opentelemetry.io/otel/trace/noop go.opentelemetry.io/otel/trace/noop
# go.podman.io/image/v5 v5.37.0 # go.podman.io/image/v5 v5.38.0
## explicit; go 1.23.3 ## explicit; go 1.24.0
go.podman.io/image/v5/docker go.podman.io/image/v5/docker
go.podman.io/image/v5/docker/policyconfiguration go.podman.io/image/v5/docker/policyconfiguration
go.podman.io/image/v5/docker/reference go.podman.io/image/v5/docker/reference
@@ -508,8 +510,8 @@ go.podman.io/image/v5/pkg/tlsclientconfig
go.podman.io/image/v5/transports go.podman.io/image/v5/transports
go.podman.io/image/v5/types go.podman.io/image/v5/types
go.podman.io/image/v5/version go.podman.io/image/v5/version
# go.podman.io/storage v1.60.0 # go.podman.io/storage v1.61.0
## explicit; go 1.23.3 ## explicit; go 1.24.0
go.podman.io/storage/internal/rawfilelock go.podman.io/storage/internal/rawfilelock
go.podman.io/storage/pkg/fileutils go.podman.io/storage/pkg/fileutils
go.podman.io/storage/pkg/homedir go.podman.io/storage/pkg/homedir
@@ -555,8 +557,8 @@ golang.org/x/net/internal/socks
golang.org/x/net/internal/timeseries golang.org/x/net/internal/timeseries
golang.org/x/net/proxy golang.org/x/net/proxy
golang.org/x/net/trace golang.org/x/net/trace
# golang.org/x/oauth2 v0.30.0 # golang.org/x/oauth2 v0.32.0
## explicit; go 1.23.0 ## explicit; go 1.24.0
golang.org/x/oauth2 golang.org/x/oauth2
golang.org/x/oauth2/internal golang.org/x/oauth2/internal
# golang.org/x/sync v0.17.0 # golang.org/x/sync v0.17.0