Skip to content

[processor/resourcedetection] Add os.version resource attribute #38087

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 20, 2025
12 changes: 12 additions & 0 deletions internal/metadataproviders/system/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package system // import "github.com/open-telemetry/opentelemetry-collector-cont
import (
"context"
"fmt"
"github.com/shirou/gopsutil/v4/host"
"net"
"os"
"runtime"
Expand Down Expand Up @@ -53,6 +54,9 @@ type Provider interface {
// OSType returns the host operating system
OSType() (string, error)

// OSVersion returns the version of the operating system
OSVersion() (string, error)

// LookupCNAME returns the canonical name for the current host
LookupCNAME() (string, error)

Expand Down Expand Up @@ -88,6 +92,14 @@ func (systemMetadataProvider) OSType() (string, error) {
return internal.GOOSToOSType(runtime.GOOS), nil
}

func (systemMetadataProvider) OSVersion() (string, error) {
info, err := host.Info()
if err != nil {
return "", fmt.Errorf("OSVersion failed to get os version: %w", err)
}
return info.PlatformVersion, nil
}

func (systemMetadataProvider) FQDN() (string, error) {
return fqdn.FqdnHostname()
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
| host.name | The host.name | Any Str | true |
| os.description | Human readable OS version information. | Any Str | false |
| os.type | The os.type | Any Str | true |
| os.version | The os.version | Any Str | true |

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ all_set:
enabled: true
os.type:
enabled: true
os.version:
enabled: true
none_set:
resource_attributes:
host.arch:
Expand Down Expand Up @@ -55,3 +57,5 @@ none_set:
enabled: false
os.type:
enabled: false
os.version:
enabled: false
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ resource_attributes:
description: The os.type
type: string
enabled: true
os.version:
description: The os.version
type: string
enabled: true
host.arch:
description: The host.arch
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ func (d *Detector) Detect(ctx context.Context) (resource pcommon.Resource, schem
return pcommon.NewResource(), "", fmt.Errorf("failed getting OS type: %w", err)
}

osVersion, err := d.provider.OSVersion()
if err != nil {
return pcommon.NewResource(), "", fmt.Errorf("failed getting OS version: %w", err)
}

hostArch, err := d.provider.HostArch()
if err != nil {
return pcommon.NewResource(), "", fmt.Errorf("failed getting host architecture: %w", err)
Expand Down Expand Up @@ -136,6 +141,7 @@ func (d *Detector) Detect(ctx context.Context) (resource pcommon.Resource, schem
if err == nil {
d.rb.SetHostName(hostname)
d.rb.SetOsType(osType)
d.rb.SetOsVersion(osVersion)
if d.cfg.ResourceAttributes.HostID.Enabled {
if hostID, hostIDErr := d.provider.HostID(ctx); hostIDErr == nil {
d.rb.SetHostID(hostID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func (m *mockMetadata) OSType() (string, error) {
return args.String(0), args.Error(1)
}

func (m *mockMetadata) OSVersion() (string, error) {
args := m.MethodCalled("OSVersion")
return args.String(0), args.Error(1)
}

func (m *mockMetadata) HostID(_ context.Context) (string, error) {
args := m.MethodCalled("HostID")
return args.String(0), args.Error(1)
Expand Down Expand Up @@ -155,6 +160,7 @@ func TestDetectFQDNAvailable(t *testing.T) {
md.On("FQDN").Return("fqdn", nil)
md.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
md.On("OSType").Return("darwin", nil)
md.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
md.On("HostID").Return("2", nil)
md.On("HostArch").Return("amd64", nil)
md.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -171,6 +177,7 @@ func TestDetectFQDNAvailable(t *testing.T) {
conventions.AttributeHostName: "fqdn",
conventions.AttributeOSDescription: "Ubuntu 22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeOSType: "darwin",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeHostID: "2",
conventions.AttributeHostArch: conventions.AttributeHostArchAMD64,
"host.ip": testIPsAttribute,
Expand All @@ -186,6 +193,7 @@ func TestFallbackHostname(t *testing.T) {
mdHostname.On("FQDN").Return("", errors.New("err"))
mdHostname.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("OSType").Return("darwin", nil)
mdHostname.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("HostArch").Return("amd64", nil)

detector := newTestDetector(mdHostname, []string{"dns", "os"}, metadata.DefaultResourceAttributesConfig())
Expand All @@ -197,8 +205,9 @@ func TestFallbackHostname(t *testing.T) {
mdHostname.AssertNotCalled(t, "HostIPs")

expected := map[string]any{
conventions.AttributeHostName: "hostname",
conventions.AttributeOSType: "darwin",
conventions.AttributeHostName: "hostname",
conventions.AttributeOSType: "darwin",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
}

assert.Equal(t, expected, res.Attributes().AsRaw())
Expand All @@ -210,6 +219,7 @@ func TestEnableHostID(t *testing.T) {
mdHostname.On("FQDN").Return("", errors.New("err"))
mdHostname.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("OSType").Return("darwin", nil)
mdHostname.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("HostID").Return("3", nil)
mdHostname.On("HostArch").Return("amd64", nil)
mdHostname.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -225,6 +235,7 @@ func TestEnableHostID(t *testing.T) {
conventions.AttributeHostName: "hostname",
conventions.AttributeOSDescription: "Ubuntu 22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeOSType: "darwin",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeHostID: "3",
conventions.AttributeHostArch: conventions.AttributeHostArchAMD64,
"host.ip": testIPsAttribute,
Expand All @@ -239,6 +250,7 @@ func TestUseHostname(t *testing.T) {
mdHostname.On("Hostname").Return("hostname", nil)
mdHostname.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("OSType").Return("darwin", nil)
mdHostname.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("HostID").Return("1", nil)
mdHostname.On("HostArch").Return("amd64", nil)
mdHostname.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -254,6 +266,7 @@ func TestUseHostname(t *testing.T) {
conventions.AttributeHostName: "hostname",
conventions.AttributeOSDescription: "Ubuntu 22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeOSType: "darwin",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeHostID: "1",
conventions.AttributeHostArch: conventions.AttributeHostArchAMD64,
"host.ip": testIPsAttribute,
Expand All @@ -268,6 +281,7 @@ func TestDetectError(t *testing.T) {
mdFQDN := &mockMetadata{}
mdFQDN.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdFQDN.On("OSType").Return("windows", nil)
mdFQDN.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdFQDN.On("FQDN").Return("", errors.New("err"))
mdFQDN.On("Hostname").Return("", errors.New("err"))
mdFQDN.On("HostID").Return("", errors.New("err"))
Expand All @@ -285,6 +299,7 @@ func TestDetectError(t *testing.T) {
mdHostname := &mockMetadata{}
mdHostname.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("OSType").Return("windows", nil)
mdHostname.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostname.On("Hostname").Return("", errors.New("err"))
mdHostname.On("HostID").Return("", errors.New("err"))
mdHostname.On("HostArch").Return("amd64", nil)
Expand All @@ -302,6 +317,7 @@ func TestDetectError(t *testing.T) {
mdOSType.On("FQDN").Return("fqdn", nil)
mdOSType.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdOSType.On("OSType").Return("", errors.New("err"))
mdOSType.On("OSVersion").Return("", "22.04.2 LTS (Jammy Jellyfish)")
mdOSType.On("HostID").Return("1", nil)
mdOSType.On("HostArch").Return("amd64", nil)
mdOSType.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -312,11 +328,28 @@ func TestDetectError(t *testing.T) {
assert.Equal(t, "", schemaURL)
assert.True(t, internal.IsEmptyResource(res))

// OS version fails
mdOSVersion := &mockMetadata{}
mdOSVersion.On("FQDN").Return("fqdn", nil)
mdOSVersion.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdOSVersion.On("OSType").Return("windows", nil)
mdOSVersion.On("OSVersion").Return("", errors.New("err"))
mdOSVersion.On("HostID").Return("1", nil)
mdOSVersion.On("HostArch").Return("amd64", nil)
mdOSVersion.On("HostIPs").Return(testIPsAddresses, nil)

detector = newTestDetector(mdOSVersion, []string{"os"}, allEnabledConfig())
res, schemaURL, err = detector.Detect(context.Background())
assert.Error(t, err)
assert.Equal(t, "", schemaURL)
assert.True(t, internal.IsEmptyResource(res))

// Host ID fails. All other attributes should be set.
mdHostID := &mockMetadata{}
mdHostID.On("Hostname").Return("hostname", nil)
mdHostID.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostID.On("OSType").Return("linux", nil)
mdHostID.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
mdHostID.On("HostID").Return("", errors.New("err"))
mdHostID.On("HostArch").Return("arm64", nil)
mdHostID.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -330,6 +363,7 @@ func TestDetectError(t *testing.T) {
conventions.AttributeHostName: "hostname",
conventions.AttributeOSDescription: "Ubuntu 22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeOSType: "linux",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeHostArch: conventions.AttributeHostArchARM64,
"host.ip": testIPsAttribute,
"host.mac": testMACsAttribute,
Expand All @@ -341,6 +375,7 @@ func TestDetectCPUInfo(t *testing.T) {
md.On("FQDN").Return("fqdn", nil)
md.On("OSDescription").Return("Ubuntu 22.04.2 LTS (Jammy Jellyfish)", nil)
md.On("OSType").Return("darwin", nil)
md.On("OSVersion").Return("22.04.2 LTS (Jammy Jellyfish)", nil)
md.On("HostID").Return("2", nil)
md.On("HostArch").Return("amd64", nil)
md.On("HostIPs").Return(testIPsAddresses, nil)
Expand All @@ -359,6 +394,7 @@ func TestDetectCPUInfo(t *testing.T) {
conventions.AttributeHostName: "fqdn",
conventions.AttributeOSDescription: "Ubuntu 22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeOSType: "darwin",
conventions.AttributeOSVersion: "22.04.2 LTS (Jammy Jellyfish)",
conventions.AttributeHostID: "2",
conventions.AttributeHostArch: conventions.AttributeHostArchAMD64,
"host.ip": testIPsAttribute,
Expand Down
Loading