Skip to content

Commit d235a93

Browse files
authored
Merge branch 'main' into cirilla/fix_b3_propagator_panic
2 parents 5819ac6 + 2dc32c1 commit d235a93

File tree

17 files changed

+742
-33
lines changed

17 files changed

+742
-33
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
cp coverage.txt $TEST_RESULTS
8787
cp coverage.html $TEST_RESULTS
8888
- name: Upload coverage report
89-
uses: codecov/codecov-action@v4.4.1
89+
uses: codecov/codecov-action@v4.5.0
9090
env:
9191
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
9292
with:
@@ -160,7 +160,7 @@ jobs:
160160
find . -name 'coverage.html' > "${TEST_RESULTS}/coverage.lst"
161161
tar -n -cf - -T "${TEST_RESULTS}/coverage.lst" | tar -C "${TEST_RESULTS}" -xvf -
162162
- name: Upload coverage report
163-
uses: codecov/codecov-action@v4.4.1
163+
uses: codecov/codecov-action@v4.5.0
164164
if: hashFiles('coverage.out') != ''
165165
with:
166166
file: ./coverage.out

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1111
### Added
1212

1313
- The `go.opentelemetry.io/contrib/config` add support to configure periodic reader interval and timeout. (#5661)
14+
- Add the new `go.opentelemetry.io/contrib/detectors/azure/azurevm` package to provide a resource detector for Azure VMs. (#5422)
1415
- Add support to configure views when creating MeterProvider using the config package. (#5654)
1516
- Add log support for the autoexport package. (#5733)
1617
- Add support for disabling the old runtime metrics using the `OTEL_GO_X_DEPRECATED_RUNTIME_METRICS=false` environment variable. (#5747)

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ detectors/aws/ec2 @open-te
3636
detectors/aws/ecs @open-telemetry/go-approvers @pyohannes @akats7
3737
detectors/aws/eks @open-telemetry/go-approvers @pyohannes
3838
detectors/aws/lambda @open-telemetry/go-approvers @akats7
39+
detectors/azure/ @open-telemetry/go-approvers @pyohannes
3940
detectors/gcp/ @open-telemetry/go-approvers @dashpole
4041

4142
exporters/autoexport @open-telemetry/go-approvers @MikeGoldsmith @pellared

detectors/azure/azurevm/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Azure VM Resource detector
2+
3+
<!--[![PkgGoDev](https://pkg.go.dev/badge/go.opentelemetry.io/contrib/detectors/azure/azurevm)](https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/azure/azurevm)-->

detectors/azure/azurevm/doc.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/*
5+
Package azurevm provides a [resource.Detector] which supports detecting
6+
attributes specific to Azure VMs.
7+
8+
According to semantic conventions for [host], [cloud], and [os] attributes,
9+
each of the following attributes is added if it is available:
10+
11+
- cloud.provider
12+
- cloud.platform
13+
- cloud.region
14+
- cloud.resource_id
15+
- host.id
16+
- host.name
17+
- host.type
18+
- os.type
19+
- os.version
20+
21+
[host]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/host.md
22+
[cloud]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/cloud.md
23+
[os]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/os.md
24+
*/
25+
package azurevm // import "go.opentelemetry.io/contrib/detectors/azure/azurevm"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package azurevm_test
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"go.opentelemetry.io/contrib/detectors/azure/azurevm"
11+
)
12+
13+
func ExampleNew() {
14+
azureVMResourceDetector := azurevm.New()
15+
resource, err := azureVMResourceDetector.Detect(context.Background())
16+
if err != nil {
17+
panic(err)
18+
}
19+
20+
// Now, you can use the resource (e.g. pass it to a tracer or meter provider).
21+
fmt.Println(resource.SchemaURL())
22+
}

detectors/azure/azurevm/go.mod

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module go.opentelemetry.io/contrib/detectors/azure/azurevm
2+
3+
go 1.21
4+
5+
require (
6+
github.com/stretchr/testify v1.9.0
7+
go.opentelemetry.io/otel v1.27.0
8+
go.opentelemetry.io/otel/sdk v1.25.0
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/go-logr/logr v1.4.1 // indirect
14+
github.com/go-logr/stdr v1.2.2 // indirect
15+
github.com/pmezard/go-difflib v1.0.0 // indirect
16+
go.opentelemetry.io/otel/metric v1.27.0 // indirect
17+
go.opentelemetry.io/otel/trace v1.27.0 // indirect
18+
golang.org/x/sys v0.18.0 // indirect
19+
gopkg.in/yaml.v3 v3.0.1 // indirect
20+
)

detectors/azure/azurevm/go.sum

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
4+
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
5+
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
6+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
7+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
8+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
9+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
10+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
11+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
12+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
13+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
14+
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
15+
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
16+
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
17+
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
18+
go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
19+
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
20+
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
21+
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
22+
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
23+
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
24+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
25+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
26+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
27+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

detectors/azure/azurevm/vm.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package azurevm // import "go.opentelemetry.io/contrib/detectors/azure/azurevm"
5+
6+
import (
7+
"context"
8+
"encoding/json"
9+
"errors"
10+
"io"
11+
"net/http"
12+
13+
"go.opentelemetry.io/otel/attribute"
14+
"go.opentelemetry.io/otel/sdk/resource"
15+
semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
16+
)
17+
18+
const defaultAzureVMMetadataEndpoint = "http://169.254.169.254/metadata/instance/compute?api-version=2021-12-13&format=json"
19+
20+
// ResourceDetector collects resource information of Azure VMs.
21+
type ResourceDetector struct {
22+
endpoint string
23+
}
24+
25+
type vmMetadata struct {
26+
VMId *string `json:"vmId"`
27+
Location *string `json:"location"`
28+
ResourceId *string `json:"resourceId"`
29+
Name *string `json:"name"`
30+
VMSize *string `json:"vmSize"`
31+
OsType *string `json:"osType"`
32+
Version *string `json:"version"`
33+
}
34+
35+
// New returns a [ResourceDetector] that will detect Azure VM resources.
36+
func New() *ResourceDetector {
37+
return &ResourceDetector{defaultAzureVMMetadataEndpoint}
38+
}
39+
40+
// Detect detects associated resources when running on an Azure VM.
41+
func (detector *ResourceDetector) Detect(ctx context.Context) (*resource.Resource, error) {
42+
jsonMetadata, runningInAzure, err := detector.getJSONMetadata(ctx)
43+
if err != nil {
44+
if !runningInAzure {
45+
return resource.Empty(), nil
46+
}
47+
48+
return nil, err
49+
}
50+
51+
var metadata vmMetadata
52+
err = json.Unmarshal(jsonMetadata, &metadata)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
attributes := []attribute.KeyValue{
58+
semconv.CloudProviderAzure,
59+
semconv.CloudPlatformAzureVM,
60+
}
61+
62+
if metadata.VMId != nil {
63+
attributes = append(attributes, semconv.HostID(*metadata.VMId))
64+
}
65+
if metadata.Location != nil {
66+
attributes = append(attributes, semconv.CloudRegion(*metadata.Location))
67+
}
68+
if metadata.ResourceId != nil {
69+
attributes = append(attributes, semconv.CloudResourceID(*metadata.ResourceId))
70+
}
71+
if metadata.Name != nil {
72+
attributes = append(attributes, semconv.HostName(*metadata.Name))
73+
}
74+
if metadata.VMSize != nil {
75+
attributes = append(attributes, semconv.HostType(*metadata.VMSize))
76+
}
77+
if metadata.OsType != nil {
78+
attributes = append(attributes, semconv.OSTypeKey.String(*metadata.OsType))
79+
}
80+
if metadata.Version != nil {
81+
attributes = append(attributes, semconv.OSVersion(*metadata.Version))
82+
}
83+
84+
return resource.NewWithAttributes(semconv.SchemaURL, attributes...), nil
85+
}
86+
87+
func (detector *ResourceDetector) getJSONMetadata(ctx context.Context) ([]byte, bool, error) {
88+
pTransport := &http.Transport{Proxy: nil}
89+
90+
client := http.Client{Transport: pTransport}
91+
92+
req, err := http.NewRequestWithContext(ctx, "GET", detector.endpoint, nil)
93+
if err != nil {
94+
return nil, false, err
95+
}
96+
97+
req.Header.Add("Metadata", "True")
98+
99+
resp, err := client.Do(req)
100+
if err != nil {
101+
return nil, false, err
102+
}
103+
104+
defer resp.Body.Close()
105+
106+
if resp.StatusCode == http.StatusOK {
107+
bytes, err := io.ReadAll(resp.Body)
108+
return bytes, true, err
109+
}
110+
111+
runningInAzure := resp.StatusCode < 400 || resp.StatusCode > 499
112+
113+
return nil, runningInAzure, errors.New(http.StatusText(resp.StatusCode))
114+
}

detectors/azure/azurevm/vm_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package azurevm
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"net/http"
10+
"net/http/httptest"
11+
"testing"
12+
13+
"github.com/stretchr/testify/assert"
14+
15+
"go.opentelemetry.io/otel/attribute"
16+
"go.opentelemetry.io/otel/sdk/resource"
17+
semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
18+
)
19+
20+
func TestDetect(t *testing.T) {
21+
type input struct {
22+
jsonMetadata string
23+
statusCode int
24+
}
25+
type expected struct {
26+
resource *resource.Resource
27+
err bool
28+
}
29+
type testCase struct {
30+
input input
31+
expected expected
32+
}
33+
34+
testTable := []testCase{
35+
{
36+
input: input{
37+
jsonMetadata: `{
38+
"location": "us-west3",
39+
"resourceId": "/subscriptions/sid/resourceGroups/rid/providers/pname/name",
40+
"vmId": "43f65c49-8715-4639-88a9-be6d7eb749a5",
41+
"name": "localhost-3",
42+
"vmSize": "Standard_D2s_v3",
43+
"osType": "linux",
44+
"version": "6.5.0-26-generic"
45+
}`,
46+
statusCode: http.StatusOK,
47+
},
48+
expected: expected{
49+
resource: resource.NewWithAttributes(semconv.SchemaURL, []attribute.KeyValue{
50+
semconv.CloudProviderAzure,
51+
semconv.CloudPlatformAzureVM,
52+
semconv.CloudRegion("us-west3"),
53+
semconv.CloudResourceID("/subscriptions/sid/resourceGroups/rid/providers/pname/name"),
54+
semconv.HostID("43f65c49-8715-4639-88a9-be6d7eb749a5"),
55+
semconv.HostName("localhost-3"),
56+
semconv.HostType("Standard_D2s_v3"),
57+
semconv.OSTypeKey.String("linux"),
58+
semconv.OSVersion("6.5.0-26-generic"),
59+
}...),
60+
err: false,
61+
},
62+
},
63+
{
64+
input: input{
65+
jsonMetadata: `{`,
66+
statusCode: http.StatusOK,
67+
},
68+
expected: expected{
69+
resource: nil,
70+
err: true,
71+
},
72+
},
73+
{
74+
input: input{
75+
jsonMetadata: "",
76+
statusCode: http.StatusNotFound,
77+
},
78+
expected: expected{
79+
resource: resource.Empty(),
80+
err: false,
81+
},
82+
},
83+
{
84+
input: input{
85+
jsonMetadata: "",
86+
statusCode: http.StatusInternalServerError,
87+
},
88+
expected: expected{
89+
resource: nil,
90+
err: true,
91+
},
92+
},
93+
}
94+
95+
for _, tCase := range testTable {
96+
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
97+
w.WriteHeader(tCase.input.statusCode)
98+
99+
if r.Header.Get("Metadata") == "True" {
100+
fmt.Fprintf(w, tCase.input.jsonMetadata)
101+
}
102+
}))
103+
104+
detector := New()
105+
detector.endpoint = svr.URL
106+
107+
azureResource, err := detector.Detect(context.Background())
108+
109+
svr.Close()
110+
111+
assert.Equal(t, err != nil, tCase.expected.err)
112+
assert.Equal(t, tCase.expected.resource, azureResource)
113+
}
114+
}

0 commit comments

Comments
 (0)