141 lines
3.3 KiB
Go
141 lines
3.3 KiB
Go
|
// Package utilization implements the Utilization spec, available at
|
||
|
// https://source.datanerd.us/agents/agent-specs/blob/master/Utilization.md
|
||
|
package utilization
|
||
|
|
||
|
import (
|
||
|
"runtime"
|
||
|
|
||
|
"github.com/newrelic/go-agent/internal/logger"
|
||
|
"github.com/newrelic/go-agent/internal/sysinfo"
|
||
|
)
|
||
|
|
||
|
const metadataVersion = 2
|
||
|
|
||
|
// Config controls the behavior of utilization information capture.
|
||
|
type Config struct {
|
||
|
DetectAWS bool
|
||
|
DetectDocker bool
|
||
|
LogicalProcessors int
|
||
|
TotalRAMMIB int
|
||
|
BillingHostname string
|
||
|
}
|
||
|
|
||
|
type override struct {
|
||
|
LogicalProcessors *int `json:"logical_processors,omitempty"`
|
||
|
TotalRAMMIB *int `json:"total_ram_mib,omitempty"`
|
||
|
BillingHostname string `json:"hostname,omitempty"`
|
||
|
}
|
||
|
|
||
|
// Data contains utilization system information.
|
||
|
type Data struct {
|
||
|
MetadataVersion int `json:"metadata_version"`
|
||
|
LogicalProcessors int `json:"logical_processors"`
|
||
|
RAMMib *uint64 `json:"total_ram_mib"`
|
||
|
Hostname string `json:"hostname"`
|
||
|
Vendors *vendors `json:"vendors,omitempty"`
|
||
|
Config *override `json:"config,omitempty"`
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
sampleRAMMib = uint64(1024)
|
||
|
// SampleData contains sample utilization data useful for testing.
|
||
|
SampleData = Data{
|
||
|
MetadataVersion: metadataVersion,
|
||
|
LogicalProcessors: 16,
|
||
|
RAMMib: &sampleRAMMib,
|
||
|
Hostname: "my-hostname",
|
||
|
}
|
||
|
)
|
||
|
|
||
|
type vendor struct {
|
||
|
ID string `json:"id,omitempty"`
|
||
|
Type string `json:"type,omitempty"`
|
||
|
Zone string `json:"zone,omitempty"`
|
||
|
}
|
||
|
|
||
|
type vendors struct {
|
||
|
AWS *vendor `json:"aws,omitempty"`
|
||
|
Docker *vendor `json:"docker,omitempty"`
|
||
|
}
|
||
|
|
||
|
func overrideFromConfig(config Config) *override {
|
||
|
ov := &override{}
|
||
|
|
||
|
if 0 != config.LogicalProcessors {
|
||
|
x := config.LogicalProcessors
|
||
|
ov.LogicalProcessors = &x
|
||
|
}
|
||
|
if 0 != config.TotalRAMMIB {
|
||
|
x := config.TotalRAMMIB
|
||
|
ov.TotalRAMMIB = &x
|
||
|
}
|
||
|
ov.BillingHostname = config.BillingHostname
|
||
|
|
||
|
if "" == ov.BillingHostname &&
|
||
|
nil == ov.LogicalProcessors &&
|
||
|
nil == ov.TotalRAMMIB {
|
||
|
ov = nil
|
||
|
}
|
||
|
return ov
|
||
|
}
|
||
|
|
||
|
// Gather gathers system utilization data.
|
||
|
func Gather(config Config, lg logger.Logger) *Data {
|
||
|
uDat := Data{
|
||
|
MetadataVersion: metadataVersion,
|
||
|
Vendors: &vendors{},
|
||
|
LogicalProcessors: runtime.NumCPU(),
|
||
|
}
|
||
|
|
||
|
if config.DetectDocker {
|
||
|
id, err := sysinfo.DockerID()
|
||
|
if err != nil &&
|
||
|
err != sysinfo.ErrDockerUnsupported &&
|
||
|
err != sysinfo.ErrDockerNotFound {
|
||
|
lg.Warn("error gathering Docker information", map[string]interface{}{
|
||
|
"error": err.Error(),
|
||
|
})
|
||
|
} else if id != "" {
|
||
|
uDat.Vendors.Docker = &vendor{ID: id}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if config.DetectAWS {
|
||
|
aws, err := getAWS()
|
||
|
if nil == err {
|
||
|
uDat.Vendors.AWS = aws
|
||
|
} else if isAWSValidationError(err) {
|
||
|
lg.Warn("AWS validation error", map[string]interface{}{
|
||
|
"error": err.Error(),
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if uDat.Vendors.AWS == nil && uDat.Vendors.Docker == nil {
|
||
|
uDat.Vendors = nil
|
||
|
}
|
||
|
|
||
|
host, err := sysinfo.Hostname()
|
||
|
if nil == err {
|
||
|
uDat.Hostname = host
|
||
|
} else {
|
||
|
lg.Warn("error getting hostname", map[string]interface{}{
|
||
|
"error": err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
bts, err := sysinfo.PhysicalMemoryBytes()
|
||
|
if nil == err {
|
||
|
mib := sysinfo.BytesToMebibytes(bts)
|
||
|
uDat.RAMMib = &mib
|
||
|
} else {
|
||
|
lg.Warn("error getting memory", map[string]interface{}{
|
||
|
"error": err.Error(),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
uDat.Config = overrideFromConfig(config)
|
||
|
|
||
|
return &uDat
|
||
|
}
|