154 lines
4.6 KiB
Go
154 lines
4.6 KiB
Go
package newrelic
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/newrelic/go-agent/internal"
|
|
"github.com/newrelic/go-agent/internal/logger"
|
|
"github.com/newrelic/go-agent/internal/utilization"
|
|
)
|
|
|
|
func copyDestConfig(c AttributeDestinationConfig) AttributeDestinationConfig {
|
|
cp := c
|
|
if nil != c.Include {
|
|
cp.Include = make([]string, len(c.Include))
|
|
copy(cp.Include, c.Include)
|
|
}
|
|
if nil != c.Exclude {
|
|
cp.Exclude = make([]string, len(c.Exclude))
|
|
copy(cp.Exclude, c.Exclude)
|
|
}
|
|
return cp
|
|
}
|
|
|
|
func copyConfigReferenceFields(cfg Config) Config {
|
|
cp := cfg
|
|
if nil != cfg.Labels {
|
|
cp.Labels = make(map[string]string, len(cfg.Labels))
|
|
for key, val := range cfg.Labels {
|
|
cp.Labels[key] = val
|
|
}
|
|
}
|
|
if nil != cfg.ErrorCollector.IgnoreStatusCodes {
|
|
ignored := make([]int, len(cfg.ErrorCollector.IgnoreStatusCodes))
|
|
copy(ignored, cfg.ErrorCollector.IgnoreStatusCodes)
|
|
cp.ErrorCollector.IgnoreStatusCodes = ignored
|
|
}
|
|
|
|
cp.Attributes = copyDestConfig(cfg.Attributes)
|
|
cp.ErrorCollector.Attributes = copyDestConfig(cfg.ErrorCollector.Attributes)
|
|
cp.TransactionEvents.Attributes = copyDestConfig(cfg.TransactionEvents.Attributes)
|
|
cp.TransactionTracer.Attributes = copyDestConfig(cfg.TransactionTracer.Attributes)
|
|
|
|
return cp
|
|
}
|
|
|
|
const (
|
|
agentLanguage = "go"
|
|
)
|
|
|
|
func transportSetting(t http.RoundTripper) interface{} {
|
|
if nil == t {
|
|
return nil
|
|
}
|
|
return fmt.Sprintf("%T", t)
|
|
}
|
|
|
|
func loggerSetting(lg Logger) interface{} {
|
|
if nil == lg {
|
|
return nil
|
|
}
|
|
if _, ok := lg.(logger.ShimLogger); ok {
|
|
return nil
|
|
}
|
|
return fmt.Sprintf("%T", lg)
|
|
}
|
|
|
|
const (
|
|
// https://source.datanerd.us/agents/agent-specs/blob/master/Custom-Host-Names.md
|
|
hostByteLimit = 255
|
|
)
|
|
|
|
type settings Config
|
|
|
|
func (s settings) MarshalJSON() ([]byte, error) {
|
|
c := Config(s)
|
|
transport := c.Transport
|
|
c.Transport = nil
|
|
logger := c.Logger
|
|
c.Logger = nil
|
|
|
|
js, err := json.Marshal(c)
|
|
if nil != err {
|
|
return nil, err
|
|
}
|
|
fields := make(map[string]interface{})
|
|
err = json.Unmarshal(js, &fields)
|
|
if nil != err {
|
|
return nil, err
|
|
}
|
|
// The License field is not simply ignored by adding the `json:"-"` tag
|
|
// to it since we want to allow consumers to populate Config from JSON.
|
|
delete(fields, `License`)
|
|
fields[`Transport`] = transportSetting(transport)
|
|
fields[`Logger`] = loggerSetting(logger)
|
|
return json.Marshal(fields)
|
|
}
|
|
|
|
func configConnectJSONInternal(c Config, pid int, util *utilization.Data, e internal.Environment, version string) ([]byte, error) {
|
|
return json.Marshal([]interface{}{struct {
|
|
Pid int `json:"pid"`
|
|
Language string `json:"language"`
|
|
Version string `json:"agent_version"`
|
|
Host string `json:"host"`
|
|
HostDisplayName string `json:"display_host,omitempty"`
|
|
Settings interface{} `json:"settings"`
|
|
AppName []string `json:"app_name"`
|
|
HighSecurity bool `json:"high_security"`
|
|
Labels internal.Labels `json:"labels,omitempty"`
|
|
Environment internal.Environment `json:"environment"`
|
|
Identifier string `json:"identifier"`
|
|
Util *utilization.Data `json:"utilization"`
|
|
}{
|
|
Pid: pid,
|
|
Language: agentLanguage,
|
|
Version: version,
|
|
Host: internal.StringLengthByteLimit(util.Hostname, hostByteLimit),
|
|
HostDisplayName: internal.StringLengthByteLimit(c.HostDisplayName, hostByteLimit),
|
|
Settings: (settings)(c),
|
|
AppName: strings.Split(c.AppName, ";"),
|
|
HighSecurity: c.HighSecurity,
|
|
Labels: internal.Labels(c.Labels),
|
|
Environment: e,
|
|
// This identifier field is provided to avoid:
|
|
// https://newrelic.atlassian.net/browse/DSCORE-778
|
|
//
|
|
// This identifier is used by the collector to look up the real
|
|
// agent. If an identifier isn't provided, the collector will
|
|
// create its own based on the first appname, which prevents a
|
|
// single daemon from connecting "a;b" and "a;c" at the same
|
|
// time.
|
|
//
|
|
// Providing the identifier below works around this issue and
|
|
// allows users more flexibility in using application rollups.
|
|
Identifier: c.AppName,
|
|
Util: util,
|
|
}})
|
|
}
|
|
|
|
func configConnectJSON(c Config) ([]byte, error) {
|
|
env := internal.NewEnvironment()
|
|
util := utilization.Gather(utilization.Config{
|
|
DetectAWS: c.Utilization.DetectAWS,
|
|
DetectDocker: c.Utilization.DetectDocker,
|
|
LogicalProcessors: c.Utilization.LogicalProcessors,
|
|
TotalRAMMIB: c.Utilization.TotalRAMMIB,
|
|
BillingHostname: c.Utilization.BillingHostname,
|
|
}, c.Logger)
|
|
return configConnectJSONInternal(c, os.Getpid(), util, env, Version)
|
|
}
|