123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- package system // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/metadataproviders/system"
- import (
- "context"
- "fmt"
- "net"
- "os"
- "runtime"
- "strings"
- "github.com/Showmax/go-fqdn"
- conventions "go.opentelemetry.io/collector/semconv/v1.6.1"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/sdk/resource"
- "github.com/open-telemetry/opentelemetry-collector-contrib/internal/metadataproviders/internal"
- )
- // nameInfoProvider abstracts domain name resolution so it can be swapped for
- // testing
- type nameInfoProvider struct {
- osHostname func() (string, error)
- lookupCNAME func(string) (string, error)
- lookupHost func(string) ([]string, error)
- lookupAddr func(string) ([]string, error)
- }
- // newNameInfoProvider creates a name info provider for production use, using
- // DNS to resolve domain names
- func newNameInfoProvider() nameInfoProvider {
- return nameInfoProvider{
- osHostname: os.Hostname,
- lookupCNAME: net.LookupCNAME,
- lookupHost: net.LookupHost,
- lookupAddr: net.LookupAddr,
- }
- }
- type Provider interface {
- // Hostname returns the OS hostname
- Hostname() (string, error)
- // FQDN returns the fully qualified domain name
- FQDN() (string, error)
- // OSDescription returns a human readable description of the OS.
- OSDescription(ctx context.Context) (string, error)
- // OSType returns the host operating system
- OSType() (string, error)
- // LookupCNAME returns the canonical name for the current host
- LookupCNAME() (string, error)
- // ReverseLookupHost does a reverse DNS query on the current host's IP address
- ReverseLookupHost() (string, error)
- // HostID returns Host Unique Identifier
- HostID(ctx context.Context) (string, error)
- // HostArch returns the host architecture
- HostArch() (string, error)
- }
- type systemMetadataProvider struct {
- nameInfoProvider
- newResource func(context.Context, ...resource.Option) (*resource.Resource, error)
- }
- func NewProvider() Provider {
- return systemMetadataProvider{nameInfoProvider: newNameInfoProvider(), newResource: resource.New}
- }
- func (systemMetadataProvider) OSType() (string, error) {
- return internal.GOOSToOSType(runtime.GOOS), nil
- }
- func (systemMetadataProvider) FQDN() (string, error) {
- return fqdn.FqdnHostname()
- }
- func (p systemMetadataProvider) Hostname() (string, error) {
- return p.nameInfoProvider.osHostname()
- }
- func (p systemMetadataProvider) LookupCNAME() (string, error) {
- hostname, err := p.Hostname()
- if err != nil {
- return "", fmt.Errorf("LookupCNAME failed to get hostname: %w", err)
- }
- cname, err := p.nameInfoProvider.lookupCNAME(hostname)
- if err != nil {
- return "", fmt.Errorf("LookupCNAME failed to get CNAME: %w", err)
- }
- return strings.TrimRight(cname, "."), nil
- }
- func (p systemMetadataProvider) ReverseLookupHost() (string, error) {
- hostname, err := p.Hostname()
- if err != nil {
- return "", fmt.Errorf("ReverseLookupHost failed to get hostname: %w", err)
- }
- return p.hostnameToDomainName(hostname)
- }
- func (p systemMetadataProvider) hostnameToDomainName(hostname string) (string, error) {
- ipAddresses, err := p.nameInfoProvider.lookupHost(hostname)
- if err != nil {
- return "", fmt.Errorf("hostnameToDomainName failed to convert hostname to IP addresses: %w", err)
- }
- return p.reverseLookup(ipAddresses)
- }
- func (p systemMetadataProvider) reverseLookup(ipAddresses []string) (string, error) {
- var err error
- for _, ip := range ipAddresses {
- var names []string
- names, err = p.nameInfoProvider.lookupAddr(ip)
- if err != nil {
- continue
- }
- return strings.TrimRight(names[0], "."), nil
- }
- return "", fmt.Errorf("reverseLookup failed to convert IP addresses to name: %w", err)
- }
- func (p systemMetadataProvider) fromOption(ctx context.Context, opt resource.Option, semconv string) (string, error) {
- res, err := p.newResource(ctx, opt)
- if err != nil {
- return "", fmt.Errorf("failed to obtain %q: %w", semconv, err)
- }
- iter := res.Iter()
- for iter.Next() {
- if iter.Attribute().Key == attribute.Key(semconv) {
- v := iter.Attribute().Value.Emit()
- if v == "" {
- return "", fmt.Errorf("empty %q", semconv)
- }
- return v, nil
- }
- }
- return "", fmt.Errorf("failed to obtain %q", semconv)
- }
- func (p systemMetadataProvider) HostID(ctx context.Context) (string, error) {
- return p.fromOption(ctx, resource.WithHostID(), conventions.AttributeHostID)
- }
- func (p systemMetadataProvider) OSDescription(ctx context.Context) (string, error) {
- return p.fromOption(ctx, resource.WithOSDescription(), conventions.AttributeOSDescription)
- }
- func (systemMetadataProvider) HostArch() (string, error) {
- return internal.GOARCHtoHostArch(runtime.GOARCH), nil
- }
|