1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-01 22:09:57 +02:00

OS description attribute detector (#1840)

* Added Linux-specific detector for the os.description attribute

* Generalized OS description detector with placeholder function for unimplemented OSes

* Extended osDescription function to *nix OSes based on golang.org/x/sys/unix

* Added WithOS resource configuration function to configure all of the OS resource attributes

* Implemented osDescription funtion for Windows OS

* Improved documentation header for *nix version of the osDescription function

* Added support for reading os-release file

* Added/updated documentation headers for *nix implementation of osDescription and related functions

* Changelog update

* Added support for reading macOS version information

* Mock approach to test OS description attribute

* Extracted common function getFirstAvailableFile to read the first available file from a list of candidates

* Upgraded golang.org/x/sys

* Changelog update

* Fixed wrong function name in documentation header for WithOSDescription

* Updated documentation header for platformOSDescription function

* Renamed restoreProcessAttributesProviders test helper function

The function restoreProcessAttributesProviders was renamed to simply
restoreAttributesProviders to better reflect its broader scope, which
not only applies to process attribute's providers.

* Fixed os_linux.go overriding build tags defined inside the file

The suffix on os_linux.go was overriding the build tags already defined
in that file. The file was renamed to os_release_unix.go, reflecting
the main function defined in the file.

For consistency, os_darwin.go was renamed to os_release_darwing.go, as
its primary purpose is to also define the osRelease function.

* Removed use of discontinued function resource.WithoutBuiltin

* Added PR number to changelog entries

* Updated go.sum files after run of make lint

* Linux implementation: ignore lines with an empty key

* Linux implementation: avoid unquoting strings less than two chars

* WIP: added tests for Linux support functions

* WIP: added tests for charsToString and getFirstAvailableFile functions

* Replaced os.CreateTemp with ioutil.TempFile as the former only exists in Go 1.16

* Added unameProvider type to decouple direct reference to unix.Uname function inside Uname()

* Added tests for Uname() function

* Replaced *os.File with io.Reader in parseOSReleaseFile to ease testing

* Added tests for parseOSReleaseFile function

* Darwin implementation: added tests for buildOSRelease function

* Replaced *os.File with io.Reader in parsePlistFile to ease testing

* Darwin implementation: added tests for parsePlistFile function

* Type in documentation header for Linux osRelease function

* Extracted logic for reading specific registry values into helper functions

* Added basic tests for Windows version of platformOSDescription and helper functions

* Manually formatted uint64 to strings to have an uniform interface for test assertions

* Asserts there's no error when opening registry key for testing

Co-authored-by: Robert Pająk <pellared@hotmail.com>

* Simplified subtests by using a single test with multiple asserts

* go.sum update after running make

* Fix typo

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>

* WIP: added placeholder implementation of platformOSDescription for unsupported OSes

* Fixed typo on osRelease documentation header

Co-authored-by: Chris Bandy <bandy.chris@gmail.com>

* Fixed typo on test case name for ParsePlistFile tests

Co-authored-by: Chris Bandy <bandy.chris@gmail.com>

* Linter fix in changelog

* go.sum updates after running make

* Used strings.Replacer instead of multiple strings.ReplaceAll calls

* Optimized implementation of charsToString

* Safer temporary file deletion with t.TempDir()

* Used t.Cleanup() for safer mocking of runtime providers in OS resource tests

* Handled optionality of DisplayVersion registry key.

For example, CI machine runs on:
Windows Server 2019 Datacenter (1809) [Version 10.0.17763.1999]

So, to not add an extra white space due to missing DisplayVersion,
this value is checked to be not empty, and only in such case a
trailing space is added for that component.

* Workaround to handle the case of DisplayVersion registry key not present

* Excluded unsupported GOOSes by negation of supported ones

* go.sum update after running make

Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Chris Bandy <bandy.chris@gmail.com>
This commit is contained in:
Nelson Ghezzi 2021-07-08 20:35:27 +00:00 committed by GitHub
parent d8c9a9554a
commit 484258eb36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1395 additions and 18 deletions

View File

@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Added
- Adds HTTP support for OTLP metrics exporter. (#2022)
- Added `WithOSDescription` resource configuration option to set OS (Operating System) description resource attribute (`os.description`). (#1840)
- Added `WithOS` resource configuration option to set all OS (Operating System) resource attributes at once. (#1840)
### Changed

View File

@ -37,6 +37,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -8,6 +8,8 @@ github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -7,6 +7,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -39,6 +39,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -80,8 +80,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -7,6 +7,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -121,6 +121,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -71,6 +71,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

View File

@ -8,6 +8,8 @@ github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -82,8 +82,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -82,8 +82,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -81,8 +81,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -80,8 +80,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -80,8 +80,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -79,8 +79,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -121,6 +121,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -9,6 +9,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -7,6 +7,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -71,6 +71,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

View File

@ -7,6 +7,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -10,6 +10,7 @@ require (
go.opentelemetry.io/otel v1.0.0-RC1
go.opentelemetry.io/otel/oteltest v1.0.0-RC1
go.opentelemetry.io/otel/trace v1.0.0-RC1
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7
)
replace go.opentelemetry.io/otel/bridge/opencensus => ../bridge/opencensus

View File

@ -7,6 +7,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View File

@ -9,6 +9,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

View 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.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package resource // import "go.opentelemetry.io/otel/sdk/resource"
var (
Uname = uname
CharsToString = charsToString
GetFirstAvailableFile = getFirstAvailableFile
)
var (
SetUnameProvider = setUnameProvider
SetDefaultUnameProvider = setDefaultUnameProvider
)

View File

@ -0,0 +1,20 @@
// 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 (
ParsePlistFile = parsePlistFile
BuildOSRelease = buildOSRelease
)

View File

@ -15,12 +15,14 @@
package resource // import "go.opentelemetry.io/otel/sdk/resource"
var (
SetDefaultOSProviders = setDefaultOSProviders
SetOSProviders = setOSProviders
SetDefaultRuntimeProviders = setDefaultRuntimeProviders
SetRuntimeProviders = setRuntimeProviders
SetDefaultUserProviders = setDefaultUserProviders
SetUserProviders = setUserProviders
SetDefaultOSProviders = setDefaultOSProviders
SetOSProviders = setOSProviders
SetDefaultRuntimeProviders = setDefaultRuntimeProviders
SetRuntimeProviders = setRuntimeProviders
SetDefaultUserProviders = setDefaultUserProviders
SetUserProviders = setUserProviders
SetDefaultOSDescriptionProvider = setDefaultOSDescriptionProvider
SetOSDescriptionProvider = setOSDescriptionProvider
)
var (

View File

@ -0,0 +1,26 @@
// 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 aix dragonfly freebsd linux netbsd openbsd solaris zos
package resource // import "go.opentelemetry.io/otel/sdk/resource"
var (
ParseOSReleaseFile = parseOSReleaseFile
Skip = skip
Parse = parse
Unquote = unquote
Unescape = unescape
BuildOSRelease = buildOSRelease
)

View File

@ -0,0 +1,26 @@
// 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 (
PlatformOSDescription = platformOSDescription
ReadProductName = readProductName
ReadDisplayVersion = readDisplayVersion
ReadReleaseID = readReleaseID
ReadCurrentMajorVersionNumber = readCurrentMajorVersionNumber
ReadCurrentMinorVersionNumber = readCurrentMinorVersionNumber
ReadCurrentBuildNumber = readCurrentBuildNumber
ReadUBR = readUBR
)

View File

@ -21,7 +21,22 @@ import (
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
type osDescriptionProvider func() (string, error)
var defaultOSDescriptionProvider osDescriptionProvider = platformOSDescription
var osDescription = defaultOSDescriptionProvider
func setDefaultOSDescriptionProvider() {
setOSDescriptionProvider(defaultOSDescriptionProvider)
}
func setOSDescriptionProvider(osDescriptionProvider osDescriptionProvider) {
osDescription = osDescriptionProvider
}
type osTypeDetector struct{}
type osDescriptionDetector struct{}
// Detect returns a *Resource that describes the operating system type the
// service is running on.
@ -34,7 +49,38 @@ func (osTypeDetector) Detect(ctx context.Context) (*Resource, error) {
), nil
}
// Detect returns a *Resource that describes the operating system the
// service is running on.
func (osDescriptionDetector) Detect(ctx context.Context) (*Resource, error) {
description, err := osDescription()
if err != nil {
return nil, err
}
return NewWithAttributes(
semconv.SchemaURL,
semconv.OSDescriptionKey.String(description),
), nil
}
// WithOSType adds an attribute with the operating system type to the configured Resource.
func WithOSType() Option {
return WithDetectors(osTypeDetector{})
}
// WithOSDescription adds an attribute with the operating system description to the
// configured Resource. The formatted string is equivalent to the output of the
// `uname -snrvm` command.
func WithOSDescription() Option {
return WithDetectors(osDescriptionDetector{})
}
// WithOS adds all the OS attributes to the configured Resource.
// See individual WithOS* functions to configure specific attributes.
func WithOS() Option {
return WithDetectors(
osTypeDetector{},
osDescriptionDetector{},
)
}

View File

@ -0,0 +1,102 @@
// 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 (
"encoding/xml"
"fmt"
"io"
"os"
)
type plist struct {
XMLName xml.Name `xml:"plist"`
Dict dict `xml:"dict"`
}
type dict struct {
Key []string `xml:"key"`
String []string `xml:"string"`
}
// osRelease builds a string describing the operating system release based on the
// contents of the property list (.plist) system files. If no .plist files are found,
// or if the required properties to build the release description string are missing,
// an empty string is returned instead. The generated string resembles the output of
// the `sw_vers` commandline program, but in a single-line string. For more information
// about the `sw_vers` program, see: https://www.unix.com/man-page/osx/1/SW_VERS.
func osRelease() string {
file, err := getPlistFile()
if err != nil {
return ""
}
defer file.Close()
values, err := parsePlistFile(file)
if err != nil {
return ""
}
return buildOSRelease(values)
}
// getPlistFile returns a *os.File pointing to one of the well-known .plist files
// available on macOS. If no file can be opened, it returns an error.
func getPlistFile() (*os.File, error) {
return getFirstAvailableFile([]string{
"/System/Library/CoreServices/SystemVersion.plist",
"/System/Library/CoreServices/ServerVersion.plist",
})
}
// parsePlistFile process the file pointed by `file` as a .plist file and returns
// a map with the key-values for each pair of correlated <key> and <string> elements
// contained in it.
func parsePlistFile(file io.Reader) (map[string]string, error) {
var v plist
err := xml.NewDecoder(file).Decode(&v)
if err != nil {
return nil, err
}
if len(v.Dict.Key) != len(v.Dict.String) {
return nil, fmt.Errorf("the number of <key> and <string> elements doesn't match")
}
properties := make(map[string]string, len(v.Dict.Key))
for i, key := range v.Dict.Key {
properties[key] = v.Dict.String[i]
}
return properties, nil
}
// buildOSRelease builds a string describing the OS release based on the properties
// available on the provided map. It tries to find the `ProductName`, `ProductVersion`
// and `ProductBuildVersion` properties. If some of these properties are not found,
// it returns an empty string.
func buildOSRelease(properties map[string]string) string {
productName := properties["ProductName"]
productVersion := properties["ProductVersion"]
productBuildVersion := properties["ProductBuildVersion"]
if productName == "" || productVersion == "" || productBuildVersion == "" {
return ""
}
return fmt.Sprintf("%s %s (%s)", productName, productVersion, productBuildVersion)
}

View File

@ -0,0 +1,176 @@
// 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 (
"bytes"
"io"
"testing"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/sdk/resource"
)
func TestParsePlistFile(t *testing.T) {
standardPlist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ProductBuildVersion</key>
<string>20E232</string>
<key>ProductCopyright</key>
<string>1983-2021 Apple Inc.</string>
<key>ProductName</key>
<string>macOS</string>
<key>ProductUserVisibleVersion</key>
<string>11.3</string>
<key>ProductVersion</key>
<string>11.3</string>
<key>iOSSupportVersion</key>
<string>14.5</string>
</dict>
</plist>`)
parsedPlist := map[string]string{
"ProductBuildVersion": "20E232",
"ProductCopyright": "1983-2021 Apple Inc.",
"ProductName": "macOS",
"ProductUserVisibleVersion": "11.3",
"ProductVersion": "11.3",
"iOSSupportVersion": "14.5",
}
emptyPlist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>`)
missingDictPlist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
</plist>`)
unknownElementsPlist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<a>
<b>123</b>
</a>
<key>ProductBuildVersion</key>
<c>Value</c>
<string>20E232</string>
<d attr="1"></d>
</dict>
</plist>`)
parsedUnknownElementsPlist := map[string]string{
"ProductBuildVersion": "20E232",
}
tt := []struct {
Name string
Plist io.Reader
Parsed map[string]string
}{
{"Standard", standardPlist, parsedPlist},
{"Empty", emptyPlist, map[string]string{}},
{"Missing dict", missingDictPlist, map[string]string{}},
{"Unknown elements", unknownElementsPlist, parsedUnknownElementsPlist},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result, err := resource.ParsePlistFile(tc.Plist)
require.Equal(t, tc.Parsed, result)
require.NoError(t, err)
})
}
}
func TestParsePlistFileUnevenKeys(t *testing.T) {
plist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ProductBuildVersion</key>
<string>20E232</string>
<key>ProductCopyright</key>
</dict>
</plist>`)
result, err := resource.ParsePlistFile(plist)
require.Nil(t, result)
require.Error(t, err)
}
func TestParsePlistFileMalformed(t *testing.T) {
plist := bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Product
</dict>
</plist>`)
result, err := resource.ParsePlistFile(plist)
require.Nil(t, result)
require.Error(t, err)
}
func TestBuildOSRelease(t *testing.T) {
tt := []struct {
Name string
Properties map[string]string
OSRelease string
}{
{"Empty properties", map[string]string{}, ""},
{"Empty properties (nil)", nil, ""},
{"Missing product name", map[string]string{
"ProductVersion": "11.3",
"ProductBuildVersion": "20E232",
}, ""},
{"Missing product version", map[string]string{
"ProductName": "macOS",
"ProductBuildVersion": "20E232",
}, ""},
{"Missing product build version", map[string]string{
"ProductName": "macOS",
"ProductVersion": "11.3",
}, ""},
{"All properties available", map[string]string{
"ProductName": "macOS",
"ProductVersion": "11.3",
"ProductBuildVersion": "20E232",
}, "macOS 11.3 (20E232)"},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.BuildOSRelease(tc.Properties)
require.Equal(t, tc.OSRelease, result)
})
}
}

View File

@ -0,0 +1,153 @@
// 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 aix dragonfly freebsd linux netbsd openbsd solaris zos
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
// osRelease builds a string describing the operating system release based on the
// properties of the os-release file. If no os-release file is found, or if the
// required properties to build the release description string are missing, an empty
// string is returned instead. For more information about os-release files, see:
// https://www.freedesktop.org/software/systemd/man/os-release.html
func osRelease() string {
file, err := getOSReleaseFile()
if err != nil {
return ""
}
defer file.Close()
values := parseOSReleaseFile(file)
return buildOSRelease(values)
}
// getOSReleaseFile returns a *os.File pointing to one of the well-known os-release
// files, according to their order of preference. If no file can be opened, it
// returns an error.
func getOSReleaseFile() (*os.File, error) {
return getFirstAvailableFile([]string{"/etc/os-release", "/usr/lib/os-release"})
}
// parseOSReleaseFile process the file pointed by `file` as an os-release file and
// returns a map with the key-values contained in it. Empty lines or lines starting
// with a '#' character are ignored, as well as lines with the missing key=value
// separator. Values are unquoted and unescaped.
func parseOSReleaseFile(file io.Reader) map[string]string {
values := make(map[string]string)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if skip(line) {
continue
}
key, value, ok := parse(line)
if ok {
values[key] = value
}
}
return values
}
// skip returns true if the line is blank or starts with a '#' character, and
// therefore should be skipped from processing.
func skip(line string) bool {
line = strings.TrimSpace(line)
return len(line) == 0 || strings.HasPrefix(line, "#")
}
// parse attempts to split the provided line on the first '=' character, and then
// sanitize each side of the split before returning them as a key-value pair.
func parse(line string) (string, string, bool) {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 || len(parts[0]) == 0 {
return "", "", false
}
key := strings.TrimSpace(parts[0])
value := unescape(unquote(strings.TrimSpace(parts[1])))
return key, value, true
}
// unquote checks whether the string `s` is quoted with double or single quotes
// and, if so, returns a version of the string without them. Otherwise it returns
// the provided string unchanged.
func unquote(s string) string {
if len(s) < 2 {
return s
}
if (s[0] == '"' || s[0] == '\'') && s[0] == s[len(s)-1] {
return s[1 : len(s)-1]
}
return s
}
// unescape removes the `\` prefix from some characters that are expected
// to have it added in front of them for escaping purposes.
func unescape(s string) string {
return strings.NewReplacer(
`\$`, `$`,
`\"`, `"`,
`\'`, `'`,
`\\`, `\`,
"\\`", "`",
).Replace(s)
}
// buildOSRelease builds a string describing the OS release based on the properties
// available on the provided map. It favors a combination of the `NAME` and `VERSION`
// properties as first option (falling back to `VERSION_ID` if `VERSION` isn't
// found), and using `PRETTY_NAME` alone if some of the previous are not present. If
// none of these properties are found, it returns an empty string.
//
// The rationale behind not using `PRETTY_NAME` as first choice was that, for some
// Linux distributions, it doesn't include the same detail that can be found on the
// individual `NAME` and `VERSION` properties, and combining `PRETTY_NAME` with
// other properties can produce "pretty" redundant strings in some cases.
func buildOSRelease(values map[string]string) string {
var osRelease string
name := values["NAME"]
version := values["VERSION"]
if version == "" {
version = values["VERSION_ID"]
}
if name != "" && version != "" {
osRelease = fmt.Sprintf("%s %s", name, version)
} else {
osRelease = values["PRETTY_NAME"]
}
return osRelease
}

View File

@ -0,0 +1,306 @@
// 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 aix dragonfly freebsd linux netbsd openbsd solaris zos
package resource_test
import (
"bytes"
"io"
"testing"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/sdk/resource"
)
func TestParseOSReleaseFile(t *testing.T) {
osReleaseUbuntu := bytes.NewBufferString(`NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal`)
parsedUbuntu := map[string]string{
"NAME": "Ubuntu",
"VERSION": "20.04.2 LTS (Focal Fossa)",
"ID": "ubuntu",
"ID_LIKE": "debian",
"PRETTY_NAME": "Ubuntu 20.04.2 LTS",
"VERSION_ID": "20.04",
"HOME_URL": "https://www.ubuntu.com/",
"SUPPORT_URL": "https://help.ubuntu.com/",
"BUG_REPORT_URL": "https://bugs.launchpad.net/ubuntu/",
"PRIVACY_POLICY_URL": "https://www.ubuntu.com/legal/terms-and-policies/privacy-policy",
"VERSION_CODENAME": "focal",
"UBUNTU_CODENAME": "focal",
}
osReleaseDebian := bytes.NewBufferString(`PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"`)
parsedDebian := map[string]string{
"PRETTY_NAME": "Debian GNU/Linux 10 (buster)",
"NAME": "Debian GNU/Linux",
"VERSION_ID": "10",
"VERSION": "10 (buster)",
"VERSION_CODENAME": "buster",
"ID": "debian",
"HOME_URL": "https://www.debian.org/",
"SUPPORT_URL": "https://www.debian.org/support",
"BUG_REPORT_URL": "https://bugs.debian.org/",
}
osReleaseAlpine := bytes.NewBufferString(`NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.13.4
PRETTY_NAME="Alpine Linux v3.13"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"`)
parsedAlpine := map[string]string{
"NAME": "Alpine Linux",
"ID": "alpine",
"VERSION_ID": "3.13.4",
"PRETTY_NAME": "Alpine Linux v3.13",
"HOME_URL": "https://alpinelinux.org/",
"BUG_REPORT_URL": "https://bugs.alpinelinux.org/",
}
osReleaseMock := bytes.NewBufferString(`
# This line should be skipped
QUOTED1="Quoted value 1"
QUOTED2='Quoted value 2'
ESCAPED1="\$HOME"
ESCAPED2="\"release\""
ESCAPED3="rock\'n\'roll"
ESCAPED4="\\var"
=line with missing key should be skipped
PROP1=name=john
PROP2 = Value
PROP3='This value will be overwritten by the next one'
PROP3='Final value'`)
parsedMock := map[string]string{
"QUOTED1": "Quoted value 1",
"QUOTED2": "Quoted value 2",
"ESCAPED1": "$HOME",
"ESCAPED2": `"release"`,
"ESCAPED3": "rock'n'roll",
"ESCAPED4": `\var`,
"PROP1": "name=john",
"PROP2": "Value",
"PROP3": "Final value",
}
tt := []struct {
Name string
OSRelease io.Reader
Parsed map[string]string
}{
{"Ubuntu", osReleaseUbuntu, parsedUbuntu},
{"Debian", osReleaseDebian, parsedDebian},
{"Alpine", osReleaseAlpine, parsedAlpine},
{"Mock", osReleaseMock, parsedMock},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.ParseOSReleaseFile(tc.OSRelease)
require.EqualValues(t, tc.Parsed, result)
})
}
}
func TestSkip(t *testing.T) {
tt := []struct {
Name string
Line string
Expected bool
}{
{"Empty string", "", true},
{"Only whitespace", " ", true},
{"Hashtag prefix 1", "# Sample text", true},
{"Hashtag prefix 2", " # Sample text", true},
{"Hashtag and whitespace 1", "# ", true},
{"Hashtag and whitespace 2", " #", true},
{"Hashtag and whitespace 3", " # ", true},
{"Nonempty string", "Sample text", false},
{"Nonempty string with whitespace around", " Sample text ", false},
{"Nonempty string with middle hashtag", "Sample #text", false},
{"Nonempty string with ending hashtag", "Sample text #", false},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.Skip(tc.Line)
require.EqualValues(t, tc.Expected, result)
})
}
}
func TestParse(t *testing.T) {
tt := []struct {
Name string
Line string
ExpectedKey string
ExpectedValue string
OK bool
}{
{"Empty string", "", "", "", false},
{"No separator", "wrong", "", "", false},
{"Empty key", "=john", "", "", false},
{"Empty key value", "=", "", "", false},
{"Empty value", "name=", "name", "", true},
{"Key value 1", "name=john", "name", "john", true},
{"Key value 2", "name=john=dev", "name", "john=dev", true},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
key, value, ok := resource.Parse(tc.Line)
require.EqualValues(t, tc.ExpectedKey, key)
require.EqualValues(t, tc.ExpectedValue, value)
require.EqualValues(t, tc.OK, ok)
})
}
}
func TestUnquote(t *testing.T) {
tt := []struct {
Name string
Text string
Expected string
}{
{"Empty string", ``, ``},
{"Single double quote", `"`, `"`},
{"Single single quote", `'`, `'`},
{"Empty double quotes", `""`, ``},
{"Empty single quotes", `''`, ``},
{"Empty mixed quotes 1", `"'`, `"'`},
{"Empty mixed quotes 2", `'"`, `'"`},
{"Double quotes", `"Sample text"`, `Sample text`},
{"Single quotes", `'Sample text'`, `Sample text`},
{"Half-open starting double quote", `"Sample text`, `"Sample text`},
{"Half-open ending double quote", `Sample text"`, `Sample text"`},
{"Half-open starting single quote", `'Sample text`, `'Sample text`},
{"Half-open ending single quote", `Sample text'`, `Sample text'`},
{"Double double quotes", `""Sample text""`, `"Sample text"`},
{"Double single quotes", `''Sample text''`, `'Sample text'`},
{"Mismatch quotes 1", `"Sample text'`, `"Sample text'`},
{"Mismatch quotes 2", `'Sample text"`, `'Sample text"`},
{"No quotes", `Sample text`, `Sample text`},
{"Internal double quote", `Sample "text"`, `Sample "text"`},
{"Internal single quote", `Sample 'text'`, `Sample 'text'`},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.Unquote(tc.Text)
require.EqualValues(t, tc.Expected, result)
})
}
}
func TestUnescape(t *testing.T) {
tt := []struct {
Name string
Text string
Expected string
}{
{"Empty string", ``, ``},
{"Escaped dollar sign", `\$var`, `$var`},
{"Escaped double quote", `\"var`, `"var`},
{"Escaped single quote", `\'var`, `'var`},
{"Escaped backslash", `\\var`, `\var`},
{"Escaped backtick", "\\`var", "`var"},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.Unescape(tc.Text)
require.EqualValues(t, tc.Expected, result)
})
}
}
func TestBuildOSRelease(t *testing.T) {
tt := []struct {
Name string
Values map[string]string
Expected string
}{
{"Nil values", nil, ""},
{"Empty values", map[string]string{}, ""},
{"Name and version only", map[string]string{
"NAME": "Ubuntu",
"VERSION": "20.04.2 LTS (Focal Fossa)",
}, "Ubuntu 20.04.2 LTS (Focal Fossa)"},
{"Name and version preferred", map[string]string{
"NAME": "Ubuntu",
"VERSION": "20.04.2 LTS (Focal Fossa)",
"VERSION_ID": "20.04",
"PRETTY_NAME": "Ubuntu 20.04.2 LTS",
}, "Ubuntu 20.04.2 LTS (Focal Fossa)"},
{"Version ID fallback", map[string]string{
"NAME": "Ubuntu",
"VERSION_ID": "20.04",
}, "Ubuntu 20.04"},
{"Pretty name fallback due to missing name", map[string]string{
"VERSION": "20.04.2 LTS (Focal Fossa)",
"PRETTY_NAME": "Ubuntu 20.04.2 LTS",
}, "Ubuntu 20.04.2 LTS"},
{"Pretty name fallback due to missing version", map[string]string{
"NAME": "Ubuntu",
"PRETTY_NAME": "Ubuntu 20.04.2 LTS",
}, "Ubuntu 20.04.2 LTS"},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.BuildOSRelease(tc.Values)
require.EqualValues(t, tc.Expected, result)
})
}
}

View File

@ -30,10 +30,15 @@ func mockRuntimeProviders() {
func() string { return "LINUX" },
fakeRuntimeArchProvider,
)
resource.SetOSDescriptionProvider(
func() (string, error) { return "Test", nil },
)
}
func TestWithOSType(t *testing.T) {
mockRuntimeProviders()
t.Cleanup(restoreAttributesProviders)
ctx := context.Background()
@ -45,6 +50,37 @@ func TestWithOSType(t *testing.T) {
require.EqualValues(t, map[string]string{
"os.type": "linux",
}, toMap(res))
restoreProcessAttributesProviders()
}
func TestWithOSDescription(t *testing.T) {
mockRuntimeProviders()
t.Cleanup(restoreAttributesProviders)
ctx := context.Background()
res, err := resource.New(ctx,
resource.WithOSDescription(),
)
require.NoError(t, err)
require.EqualValues(t, map[string]string{
"os.description": "Test",
}, toMap(res))
}
func TestWithOS(t *testing.T) {
mockRuntimeProviders()
t.Cleanup(restoreAttributesProviders)
ctx := context.Background()
res, err := resource.New(ctx,
resource.WithOS(),
)
require.NoError(t, err)
require.EqualValues(t, map[string]string{
"os.type": "linux",
"os.description": "Test",
}, toMap(res))
}

99
sdk/resource/os_unix.go Normal file
View File

@ -0,0 +1,99 @@
// 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package resource // import "go.opentelemetry.io/otel/sdk/resource"
import (
"bytes"
"fmt"
"os"
"golang.org/x/sys/unix"
)
type unameProvider func(buf *unix.Utsname) (err error)
var defaultUnameProvider unameProvider = unix.Uname
var currentUnameProvider = defaultUnameProvider
func setDefaultUnameProvider() {
setUnameProvider(defaultUnameProvider)
}
func setUnameProvider(unameProvider unameProvider) {
currentUnameProvider = unameProvider
}
// platformOSDescription returns a human readable OS version information string.
// The final string combines OS release information (where available) and the
// result of the `uname` system call.
func platformOSDescription() (string, error) {
uname, err := uname()
if err != nil {
return "", err
}
osRelease := osRelease()
if osRelease != "" {
return fmt.Sprintf("%s (%s)", osRelease, uname), nil
}
return uname, nil
}
// uname issues a uname(2) system call (or equivalent on systems which doesn't
// have one) and formats the output in a single string, similar to the output
// of the `uname` commandline program. The final string resembles the one
// obtained with a call to `uname -snrvm`.
func uname() (string, error) {
var utsName unix.Utsname
err := currentUnameProvider(&utsName)
if err != nil {
return "", err
}
return fmt.Sprintf("%s %s %s %s %s",
charsToString(utsName.Sysname[:]),
charsToString(utsName.Nodename[:]),
charsToString(utsName.Release[:]),
charsToString(utsName.Version[:]),
charsToString(utsName.Machine[:]),
), nil
}
// charsToString converts a C-like null-terminated char array to a Go string.
func charsToString(charArray []byte) string {
if i := bytes.IndexByte(charArray, 0); i >= 0 {
charArray = charArray[:i]
}
return string(charArray)
}
// getFirstAvailableFile returns an *os.File of the first available
// file from a list of candidate file paths.
func getFirstAvailableFile(candidates []string) (*os.File, error) {
for _, c := range candidates {
file, err := os.Open(c)
if err == nil {
return file, nil
}
}
return nil, fmt.Errorf("no candidate file available: %v", candidates)
}

View File

@ -0,0 +1,134 @@
// 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package resource_test
import (
"fmt"
"io/ioutil"
"testing"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/sdk/resource"
"golang.org/x/sys/unix"
)
func fakeUnameProvider(buf *unix.Utsname) error {
copy(buf.Sysname[:], "Mock OS")
copy(buf.Nodename[:], "DESKTOP-PC")
copy(buf.Release[:], "5.0.0")
copy(buf.Version[:], "#1 SMP Thu May 6 12:34:56 UTC 2021")
copy(buf.Machine[:], "x86_64")
return nil
}
func fakeUnameProviderWithError(buf *unix.Utsname) error {
return fmt.Errorf("Error invoking uname(2)")
}
func TestUname(t *testing.T) {
resource.SetUnameProvider(fakeUnameProvider)
uname, err := resource.Uname()
require.Equal(t, uname, "Mock OS DESKTOP-PC 5.0.0 #1 SMP Thu May 6 12:34:56 UTC 2021 x86_64")
require.NoError(t, err)
resource.SetDefaultUnameProvider()
}
func TestUnameError(t *testing.T) {
resource.SetUnameProvider(fakeUnameProviderWithError)
uname, err := resource.Uname()
require.Empty(t, uname)
require.Error(t, err)
resource.SetDefaultUnameProvider()
}
func TestCharsToString(t *testing.T) {
tt := []struct {
Name string
Bytes []byte
Expected string
}{
{"Nil array", nil, ""},
{"Empty array", []byte{}, ""},
{"Empty string (null terminated)", []byte{0x00}, ""},
{"Nonempty string (null terminated)", []byte{0x31, 0x32, 0x33, 0x00}, "123"},
{"Nonempty string (non-null terminated)", []byte{0x31, 0x32, 0x33}, "123"},
{"Nonempty string with values after null", []byte{0x31, 0x32, 0x33, 0x00, 0x34}, "123"},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
result := resource.CharsToString(tc.Bytes)
require.EqualValues(t, tc.Expected, result)
})
}
}
func TestGetFirstAvailableFile(t *testing.T) {
tempDir := t.TempDir()
file1, _ := ioutil.TempFile(tempDir, "candidate_")
file2, _ := ioutil.TempFile(tempDir, "candidate_")
filename1, filename2 := file1.Name(), file2.Name()
tt := []struct {
Name string
Candidates []string
ExpectedFileName string
ExpectedErr string
}{
{"Gets first, skip second candidate", []string{filename1, filename2}, filename1, ""},
{"Skips first, gets second candidate", []string{"does_not_exists", filename2}, filename2, ""},
{"Skips first, gets second, ignores third candidate", []string{"does_not_exists", filename2, filename1}, filename2, ""},
{"No candidates (empty slice)", []string{}, "", "no candidate file available: []"},
{"No candidates (nil slice)", nil, "", "no candidate file available: []"},
{"Single nonexisting candidate", []string{"does_not_exists"}, "", "no candidate file available: [does_not_exists]"},
{"Multiple nonexisting candidates", []string{"does_not_exists", "this_either"}, "", "no candidate file available: [does_not_exists this_either]"},
}
for _, tc := range tt {
tc := tc
t.Run(tc.Name, func(t *testing.T) {
file, err := resource.GetFirstAvailableFile(tc.Candidates)
filename := ""
if file != nil {
filename = file.Name()
}
errString := ""
if err != nil {
errString = err.Error()
}
require.Equal(t, tc.ExpectedFileName, filename)
require.Equal(t, tc.ExpectedErr, errString)
})
}
}

View File

@ -0,0 +1,34 @@
// 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 !aix
// +build !darwin
// +build !dragonfly
// +build !freebsd
// +build !linux
// +build !netbsd
// +build !openbsd
// +build !solaris
// +build !windows
// +build !zos
package resource // import "go.opentelemetry.io/otel/sdk/resource"
// platformOSDescription is a placeholder implementation for OSes
// for which this project currently doesn't support os.description
// attribute detection. See build tags declaration early on this file
// for a list of unsupported OSes.
func platformOSDescription() (string, error) {
return "<unknown>", nil
}

101
sdk/resource/os_windows.go Normal file
View File

@ -0,0 +1,101 @@
// 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 (
"fmt"
"strconv"
"golang.org/x/sys/windows/registry"
)
// platformOSDescription returns a human readable OS version information string.
// It does so by querying registry values under the
// `SOFTWARE\Microsoft\Windows NT\CurrentVersion` key. The final string
// resembles the one displayed by the Version Reporter Applet (winver.exe).
func platformOSDescription() (string, error) {
k, err := registry.OpenKey(
registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
if err != nil {
return "", err
}
defer k.Close()
var (
productName = readProductName(k)
displayVersion = readDisplayVersion(k)
releaseID = readReleaseID(k)
currentMajorVersionNumber = readCurrentMajorVersionNumber(k)
currentMinorVersionNumber = readCurrentMinorVersionNumber(k)
currentBuildNumber = readCurrentBuildNumber(k)
ubr = readUBR(k)
)
if displayVersion != "" {
displayVersion += " "
}
return fmt.Sprintf("%s %s(%s) [Version %s.%s.%s.%s]",
productName,
displayVersion,
releaseID,
currentMajorVersionNumber,
currentMinorVersionNumber,
currentBuildNumber,
ubr,
), nil
}
func getStringValue(name string, k registry.Key) string {
value, _, _ := k.GetStringValue(name)
return value
}
func getIntegerValue(name string, k registry.Key) uint64 {
value, _, _ := k.GetIntegerValue(name)
return value
}
func readProductName(k registry.Key) string {
return getStringValue("ProductName", k)
}
func readDisplayVersion(k registry.Key) string {
return getStringValue("DisplayVersion", k)
}
func readReleaseID(k registry.Key) string {
return getStringValue("ReleaseID", k)
}
func readCurrentMajorVersionNumber(k registry.Key) string {
return strconv.FormatUint(getIntegerValue("CurrentMajorVersionNumber", k), 10)
}
func readCurrentMinorVersionNumber(k registry.Key) string {
return strconv.FormatUint(getIntegerValue("CurrentMinorVersionNumber", k), 10)
}
func readCurrentBuildNumber(k registry.Key) string {
return getStringValue("CurrentBuildNumber", k)
}
func readUBR(k registry.Key) string {
return strconv.FormatUint(getIntegerValue("UBR", k), 10)
}

View File

@ -0,0 +1,49 @@
// 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 (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows/registry"
"go.opentelemetry.io/otel/sdk/resource"
)
func TestPlatformOSDescription(t *testing.T) {
osDescription, err := resource.PlatformOSDescription()
require.NoError(t, err)
require.Regexp(t, `^(\w+\s)+\(\d+\)\s\[Version\s\d+(\.\d+){3}\]$`, osDescription)
}
func TestReadRegistryValues(t *testing.T) {
k, err := registry.OpenKey(
registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
require.NoError(t, err, "should open Windows CurrentVersion registry key")
defer k.Close()
assert.NotEmpty(t, resource.ReadProductName(k), "should read ProductName")
assert.NotEmpty(t, resource.ReadReleaseID(k), "should read ReleaseID")
assert.NotEmpty(t, resource.ReadCurrentMajorVersionNumber(k), "should read CurrentMajorVersionNumber")
assert.NotEmpty(t, resource.ReadCurrentMinorVersionNumber(k), "should read CurrentMinorVersionNumber")
assert.NotEmpty(t, resource.ReadCurrentBuildNumber(k), "should read CurrentBuildNumber")
assert.NotEmpty(t, resource.ReadUBR(k), "should read UBR")
assert.NotPanics(t, func() { resource.ReadDisplayVersion(k) }, "should not panic when reading DisplayVersion")
}

View File

@ -97,10 +97,11 @@ func mockProcessAttributesProvidersWithErrors() {
)
}
func restoreProcessAttributesProviders() {
func restoreAttributesProviders() {
resource.SetDefaultOSProviders()
resource.SetDefaultRuntimeProviders()
resource.SetDefaultUserProviders()
resource.SetDefaultOSDescriptionProvider()
}
func TestWithProcessFuncs(t *testing.T) {
@ -116,7 +117,7 @@ func TestWithProcessFuncs(t *testing.T) {
t.Run("WithRuntimeDescription", testWithProcessRuntimeDescription)
t.Run("WithProcess", testWithProcess)
restoreProcessAttributesProviders()
restoreAttributesProviders()
}
func TestWithProcessFuncsErrors(t *testing.T) {
@ -125,7 +126,7 @@ func TestWithProcessFuncsErrors(t *testing.T) {
t.Run("WithPID", testWithProcessExecutablePathError)
t.Run("WithExecutableName", testWithProcessOwnerError)
restoreProcessAttributesProviders()
restoreAttributesProviders()
}
func TestCommandArgs(t *testing.T) {