You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	add host.id to resource auto-detection (#3812)
* add platform specific hostIDReaders * add WithHostID option to Resource * add changelog entry * Apply suggestions from code review Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> * linting * combine platform specific readers and tests This allows us to run tests for the BSD, Darwin, and Linux readers on all platforms. * add todo to use assert.AnError after resource.Detect error handling is updated * move HostID test utilities to host_id_test * return assert.AnError from mockHostIDProviderWithError * use assert.ErrorIs Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> --------- Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> Co-authored-by: Aaron Clawson <3766680+MadVikingGod@users.noreply.github.com>
This commit is contained in:
		| @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm | ||||
|  | ||||
| ### Added | ||||
|  | ||||
| - The `WithHostID` option to `go.opentelemetry.io/otel/sdk/resource`. (#3812) | ||||
| - The `WithoutTimestamps` option to `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` to sets all timestamps to zero. (#3828) | ||||
| - The new `Exemplar` type is added to `go.opentelemetry.io/otel/sdk/metric/metricdata`. | ||||
|   Both the `DataPoint` and `HistogramDataPoint` types from that package have a new field of `Exemplars` containing the sampled exemplars for their timeseries. (#3849) | ||||
|   | ||||
| @@ -71,6 +71,11 @@ func WithHost() Option { | ||||
| 	return WithDetectors(host{}) | ||||
| } | ||||
|  | ||||
| // WithHostID adds host ID information to the configured resource. | ||||
| func WithHostID() Option { | ||||
| 	return WithDetectors(hostIDDetector{}) | ||||
| } | ||||
|  | ||||
| // WithTelemetrySDK adds TelemetrySDK version info to the configured resource. | ||||
| func WithTelemetrySDK() Option { | ||||
| 	return WithDetectors(telemetrySDK{}) | ||||
|   | ||||
							
								
								
									
										142
									
								
								sdk/resource/host_id.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								sdk/resource/host_id.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //	http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
|  | ||||
| 	semconv "go.opentelemetry.io/otel/semconv/v1.17.0" | ||||
| ) | ||||
|  | ||||
| type hostIDProvider func() (string, error) | ||||
|  | ||||
| var defaultHostIDProvider hostIDProvider = platformHostIDReader.read | ||||
|  | ||||
| var hostID = defaultHostIDProvider | ||||
|  | ||||
| type hostIDReader interface { | ||||
| 	read() (string, error) | ||||
| } | ||||
|  | ||||
| type fileReader func(string) (string, error) | ||||
|  | ||||
| type commandExecutor func(string, ...string) (string, error) | ||||
|  | ||||
| func readFile(filename string) (string, error) { | ||||
| 	b, err := os.ReadFile(filename) | ||||
| 	if err != nil { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	return string(b), nil | ||||
| } | ||||
|  | ||||
| // nolint: unused  // This is used by the hostReaderBSD, gated by build tags. | ||||
| func execCommand(name string, arg ...string) (string, error) { | ||||
| 	cmd := exec.Command(name, arg...) | ||||
| 	b, err := cmd.Output() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return string(b), nil | ||||
| } | ||||
|  | ||||
| // hostIDReaderBSD implements hostIDReader. | ||||
| type hostIDReaderBSD struct { | ||||
| 	execCommand commandExecutor | ||||
| 	readFile    fileReader | ||||
| } | ||||
|  | ||||
| // read attempts to read the machine-id from /etc/hostid. If not found it will | ||||
| // execute `kenv -q smbios.system.uuid`. If neither location yields an id an | ||||
| // error will be returned. | ||||
| func (r *hostIDReaderBSD) read() (string, error) { | ||||
| 	if result, err := r.readFile("/etc/hostid"); err == nil { | ||||
| 		return strings.TrimSpace(result), nil | ||||
| 	} | ||||
|  | ||||
| 	if result, err := r.execCommand("kenv", "-q", "smbios.system.uuid"); err == nil { | ||||
| 		return strings.TrimSpace(result), nil | ||||
| 	} | ||||
|  | ||||
| 	return "", errors.New("host id not found in: /etc/hostid or kenv") | ||||
| } | ||||
|  | ||||
| // hostIDReaderDarwin implements hostIDReader. | ||||
| type hostIDReaderDarwin struct { | ||||
| 	execCommand commandExecutor | ||||
| } | ||||
|  | ||||
| // read executes `ioreg -rd1 -c "IOPlatformExpertDevice"` and parses host id | ||||
| // from the IOPlatformUUID line. If the command fails or the uuid cannot be | ||||
| // parsed an error will be returned. | ||||
| func (r *hostIDReaderDarwin) read() (string, error) { | ||||
| 	result, err := r.execCommand("ioreg", "-rd1", "-c", "IOPlatformExpertDevice") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	lines := strings.Split(result, "\n") | ||||
| 	for _, line := range lines { | ||||
| 		if strings.Contains(line, "IOPlatformUUID") { | ||||
| 			parts := strings.Split(line, " = ") | ||||
| 			if len(parts) == 2 { | ||||
| 				return strings.Trim(parts[1], "\""), nil | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "", errors.New("could not parse IOPlatformUUID") | ||||
| } | ||||
|  | ||||
| type hostIDReaderLinux struct { | ||||
| 	readFile fileReader | ||||
| } | ||||
|  | ||||
| // read attempts to read the machine-id from /etc/machine-id followed by | ||||
| // /var/lib/dbus/machine-id. If neither location yields an ID an error will | ||||
| // be returned. | ||||
| func (r *hostIDReaderLinux) read() (string, error) { | ||||
| 	if result, err := r.readFile("/etc/machine-id"); err == nil { | ||||
| 		return strings.TrimSpace(result), nil | ||||
| 	} | ||||
|  | ||||
| 	if result, err := r.readFile("/var/lib/dbus/machine-id"); err == nil { | ||||
| 		return strings.TrimSpace(result), nil | ||||
| 	} | ||||
|  | ||||
| 	return "", errors.New("host id not found in: /etc/machine-id or /var/lib/dbus/machine-id") | ||||
| } | ||||
|  | ||||
| type hostIDDetector struct{} | ||||
|  | ||||
| // Detect returns a *Resource containing the platform specific host id. | ||||
| func (hostIDDetector) Detect(ctx context.Context) (*Resource, error) { | ||||
| 	hostID, err := hostID() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return NewWithAttributes( | ||||
| 		semconv.SchemaURL, | ||||
| 		semconv.HostID(hostID), | ||||
| 	), nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								sdk/resource/host_id_bsd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								sdk/resource/host_id_bsd.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| //go:build dragonfly || freebsd || netbsd || openbsd || solaris | ||||
| // +build dragonfly freebsd netbsd openbsd solaris | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var platformHostIDReader hostIDReader = &hostIDReaderBSD{ | ||||
| 	execCommand: execCommand, | ||||
| 	readFile:    readFile, | ||||
| } | ||||
							
								
								
									
										19
									
								
								sdk/resource/host_id_darwin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								sdk/resource/host_id_darwin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| var platformHostIDReader hostIDReader = &hostIDReaderDarwin{ | ||||
| 	execCommand: execCommand, | ||||
| } | ||||
							
								
								
									
										37
									
								
								sdk/resource/host_id_export_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								sdk/resource/host_id_export_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package resource_test | ||||
|  | ||||
| import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| ) | ||||
|  | ||||
| func mockHostIDProvider() { | ||||
| 	resource.SetHostIDProvider( | ||||
| 		func() (string, error) { return "f2c668b579780554f70f72a063dc0864", nil }, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func mockHostIDProviderWithError() { | ||||
| 	resource.SetHostIDProvider( | ||||
| 		func() (string, error) { return "", assert.AnError }, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func restoreHostIDProvider() { | ||||
| 	resource.SetDefaultHostIDProvider() | ||||
| } | ||||
							
								
								
									
										22
									
								
								sdk/resource/host_id_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								sdk/resource/host_id_linux.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| //go:build linux | ||||
| // +build linux | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| var platformHostIDReader hostIDReader = &hostIDReaderLinux{ | ||||
| 	readFile: readFile, | ||||
| } | ||||
							
								
								
									
										222
									
								
								sdk/resource/host_id_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								sdk/resource/host_id_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package resource | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	expectedHostID = "f2c668b579780554f70f72a063dc0864" | ||||
|  | ||||
| 	readFileNoError = func(filename string) (string, error) { | ||||
| 		return expectedHostID + "\n", nil | ||||
| 	} | ||||
|  | ||||
| 	readFileError = func(filename string) (string, error) { | ||||
| 		return "", errors.New("not found") | ||||
| 	} | ||||
|  | ||||
| 	execCommandNoError = func(string, ...string) (string, error) { | ||||
| 		return expectedHostID + "\n", nil | ||||
| 	} | ||||
|  | ||||
| 	execCommandError = func(string, ...string) (string, error) { | ||||
| 		return "", errors.New("not found") | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| func SetDefaultHostIDProvider() { | ||||
| 	SetHostIDProvider(defaultHostIDProvider) | ||||
| } | ||||
|  | ||||
| func SetHostIDProvider(hostIDProvider hostIDProvider) { | ||||
| 	hostID = hostIDProvider | ||||
| } | ||||
|  | ||||
| func TestHostIDReaderBSD(t *testing.T) { | ||||
| 	tt := []struct { | ||||
| 		name            string | ||||
| 		fileReader      fileReader | ||||
| 		commandExecutor commandExecutor | ||||
| 		expectedHostID  string | ||||
| 		expectError     bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:            "hostIDReaderBSD valid primary", | ||||
| 			fileReader:      readFileNoError, | ||||
| 			commandExecutor: execCommandError, | ||||
| 			expectedHostID:  expectedHostID, | ||||
| 			expectError:     false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "hostIDReaderBSD invalid primary", | ||||
| 			fileReader:      readFileError, | ||||
| 			commandExecutor: execCommandNoError, | ||||
| 			expectedHostID:  expectedHostID, | ||||
| 			expectError:     false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "hostIDReaderBSD invalid primary and secondary", | ||||
| 			fileReader:      readFileError, | ||||
| 			commandExecutor: execCommandError, | ||||
| 			expectedHostID:  "", | ||||
| 			expectError:     true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tt { | ||||
| 		tc := tc | ||||
|  | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			reader := hostIDReaderBSD{ | ||||
| 				readFile:    tc.fileReader, | ||||
| 				execCommand: tc.commandExecutor, | ||||
| 			} | ||||
| 			hostID, err := reader.read() | ||||
| 			require.Equal(t, tc.expectError, err != nil) | ||||
| 			require.Equal(t, tc.expectedHostID, hostID) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHostIDReaderLinux(t *testing.T) { | ||||
| 	readFilePrimaryError := func(filename string) (string, error) { | ||||
| 		if filename == "/var/lib/dbus/machine-id" { | ||||
| 			return readFileNoError(filename) | ||||
| 		} | ||||
| 		return readFileError(filename) | ||||
| 	} | ||||
|  | ||||
| 	tt := []struct { | ||||
| 		name           string | ||||
| 		fileReader     fileReader | ||||
| 		expectedHostID string | ||||
| 		expectError    bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:           "hostIDReaderLinux valid primary", | ||||
| 			fileReader:     readFileNoError, | ||||
| 			expectedHostID: expectedHostID, | ||||
| 			expectError:    false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:           "hostIDReaderLinux invalid primary", | ||||
| 			fileReader:     readFilePrimaryError, | ||||
| 			expectedHostID: expectedHostID, | ||||
| 			expectError:    false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:           "hostIDReaderLinux invalid primary and secondary", | ||||
| 			fileReader:     readFileError, | ||||
| 			expectedHostID: "", | ||||
| 			expectError:    true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tt { | ||||
| 		tc := tc | ||||
|  | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			reader := hostIDReaderLinux{ | ||||
| 				readFile: tc.fileReader, | ||||
| 			} | ||||
| 			hostID, err := reader.read() | ||||
| 			require.Equal(t, tc.expectError, err != nil) | ||||
| 			require.Equal(t, tc.expectedHostID, hostID) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestHostIDReaderDarwin(t *testing.T) { | ||||
| 	validOutput := `+-o J316sAP  <class IOPlatformExpertDevice, id 0x10000024d, registered, matched, active, busy 0 (132196 ms), retain 37> | ||||
| { | ||||
| 	"IOPolledInterface" = "AppleARMWatchdogTimerHibernateHandler is not serializable" | ||||
| 	"#address-cells" = <02000000> | ||||
| 	"AAPL,phandle" = <01000000> | ||||
| 	"serial-number" = <94e1c79ec04cd3f153f600000000000000000000000000000000000000000000> | ||||
| 	"IOBusyInterest" = "IOCommand is not serializable" | ||||
| 	"target-type" = <"J316s"> | ||||
| 	"platform-name" = <7436303030000000000000000000000000000000000000000000000000000000> | ||||
| 	"secure-root-prefix" = <"md"> | ||||
| 	"name" = <"device-tree"> | ||||
| 	"region-info" = <4c4c2f4100000000000000000000000000000000000000000000000000000000> | ||||
| 	"manufacturer" = <"Apple Inc."> | ||||
| 	"compatible" = <"J316sAP","MacBookPro18,1","AppleARM"> | ||||
| 	"config-number" = <00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000> | ||||
| 	"IOPlatformSerialNumber" = "HDWLIF2LM7" | ||||
| 	"regulatory-model-number" = <4132343835000000000000000000000000000000000000000000000000000000> | ||||
| 	"time-stamp" = <"Fri Aug 5 20:25:38 PDT 2022"> | ||||
| 	"clock-frequency" = <00366e01> | ||||
| 	"model" = <"MacBookPro18,1"> | ||||
| 	"mlb-serial-number" = <5c92d268d6cd789e475ffafc0d363fc950000000000000000000000000000000> | ||||
| 	"model-number" = <5a31345930303136430000000000000000000000000000000000000000000000> | ||||
| 	"IONWInterrupts" = "IONWInterrupts" | ||||
| 	"model-config" = <"ICT;MoPED=0x03D053A605C84ED11C455A18D6C643140B41A239"> | ||||
| 	"device_type" = <"bootrom"> | ||||
| 	"#size-cells" = <02000000> | ||||
| 	"IOPlatformUUID" = "81895B8D-9EF9-4EBB-B5DE-B00069CF53F0" | ||||
| } | ||||
| ` | ||||
| 	execCommandValid := func(string, ...string) (string, error) { | ||||
| 		return validOutput, nil | ||||
| 	} | ||||
|  | ||||
| 	execCommandInvalid := func(string, ...string) (string, error) { | ||||
| 		return "wasn't expecting this", nil | ||||
| 	} | ||||
|  | ||||
| 	tt := []struct { | ||||
| 		name            string | ||||
| 		fileReader      fileReader | ||||
| 		commandExecutor commandExecutor | ||||
| 		expectedHostID  string | ||||
| 		expectError     bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:            "hostIDReaderDarwin valid output", | ||||
| 			commandExecutor: execCommandValid, | ||||
| 			expectedHostID:  "81895B8D-9EF9-4EBB-B5DE-B00069CF53F0", | ||||
| 			expectError:     false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "hostIDReaderDarwin invalid output", | ||||
| 			commandExecutor: execCommandInvalid, | ||||
| 			expectedHostID:  "", | ||||
| 			expectError:     true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "hostIDReaderDarwin error", | ||||
| 			commandExecutor: execCommandError, | ||||
| 			expectedHostID:  "", | ||||
| 			expectError:     true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range tt { | ||||
| 		tc := tc | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			reader := hostIDReaderDarwin{ | ||||
| 				execCommand: tc.commandExecutor, | ||||
| 			} | ||||
| 			hostID, err := reader.read() | ||||
| 			require.Equal(t, tc.expectError, err != nil) | ||||
| 			require.Equal(t, tc.expectedHostID, hostID) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										36
									
								
								sdk/resource/host_id_unsupported.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								sdk/resource/host_id_unsupported.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // +build !darwin | ||||
| // +build !dragonfly | ||||
| // +build !freebsd | ||||
| // +build !linux | ||||
| // +build !netbsd | ||||
| // +build !openbsd | ||||
| // +build !solaris | ||||
| // +build !windows | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| // hostIDReaderUnsupported is a placeholder implementation for operating systems | ||||
| // for which this project currently doesn't support host.id | ||||
| // attribute detection. See build tags declaration early on this file | ||||
| // for a list of unsupported OSes. | ||||
| type hostIDReaderUnsupported struct{} | ||||
|  | ||||
| func (*hostIDReaderUnsupported) read() (string, error) { | ||||
| 	return "<unknown>", nil | ||||
| } | ||||
|  | ||||
| var platformHostIDReader hostIDReader = &hostIDReaderUnsupported{} | ||||
							
								
								
									
										48
									
								
								sdk/resource/host_id_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								sdk/resource/host_id_windows.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| //go:build windows | ||||
| // +build windows | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| import ( | ||||
| 	"golang.org/x/sys/windows/registry" | ||||
| ) | ||||
|  | ||||
| // implements hostIDReader | ||||
| type hostIDReaderWindows struct{} | ||||
|  | ||||
| // read reads MachineGuid from the windows registry key: | ||||
| // SOFTWARE\Microsoft\Cryptography | ||||
| func (*hostIDReaderWindows) read() (string, error) { | ||||
| 	k, err := registry.OpenKey( | ||||
| 		registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Cryptography`, | ||||
| 		registry.QUERY_VALUE|registry.WOW64_64KEY, | ||||
| 	) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer k.Close() | ||||
|  | ||||
| 	guid, _, err := k.GetStringValue("MachineGuid") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return guid, nil | ||||
| } | ||||
|  | ||||
| var platformHostIDReader hostIDReader = &hostIDReaderWindows{} | ||||
							
								
								
									
										32
									
								
								sdk/resource/host_id_windows_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								sdk/resource/host_id_windows_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // Copyright The OpenTelemetry Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| //go:build windows | ||||
| // +build windows | ||||
|  | ||||
| package resource // import "go.opentelemetry.io/otel/sdk/resource" | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| func TestReader(t *testing.T) { | ||||
| 	reader := &hostIDReaderWindows{} | ||||
| 	result, err := reader.read() | ||||
|  | ||||
| 	require.NoError(t, err) | ||||
| 	require.NotEmpty(t, result) | ||||
| } | ||||
| @@ -471,6 +471,36 @@ func TestNewWrapedError(t *testing.T) { | ||||
| 	assert.NotErrorIs(t, err, errors.New("false positive error")) | ||||
| } | ||||
|  | ||||
| func TestWithHostID(t *testing.T) { | ||||
| 	mockHostIDProvider() | ||||
| 	t.Cleanup(restoreHostIDProvider) | ||||
|  | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	res, err := resource.New(ctx, | ||||
| 		resource.WithHostID(), | ||||
| 	) | ||||
|  | ||||
| 	require.NoError(t, err) | ||||
| 	require.EqualValues(t, map[string]string{ | ||||
| 		"host.id": "f2c668b579780554f70f72a063dc0864", | ||||
| 	}, toMap(res)) | ||||
| } | ||||
|  | ||||
| func TestWithHostIDError(t *testing.T) { | ||||
| 	mockHostIDProviderWithError() | ||||
| 	t.Cleanup(restoreHostIDProvider) | ||||
|  | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	res, err := resource.New(ctx, | ||||
| 		resource.WithHostID(), | ||||
| 	) | ||||
|  | ||||
| 	assert.ErrorIs(t, err, assert.AnError) | ||||
| 	require.EqualValues(t, map[string]string{}, toMap(res)) | ||||
| } | ||||
|  | ||||
| func TestWithOSType(t *testing.T) { | ||||
| 	mockRuntimeProviders() | ||||
| 	t.Cleanup(restoreAttributesProviders) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user