github.com/lulzWill/go-agent@v2.1.2+incompatible/internal_config.go (about) 1 package newrelic 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "os" 8 "strings" 9 10 "github.com/lulzWill/go-agent/internal" 11 "github.com/lulzWill/go-agent/internal/logger" 12 "github.com/lulzWill/go-agent/internal/utilization" 13 ) 14 15 func copyDestConfig(c AttributeDestinationConfig) AttributeDestinationConfig { 16 cp := c 17 if nil != c.Include { 18 cp.Include = make([]string, len(c.Include)) 19 copy(cp.Include, c.Include) 20 } 21 if nil != c.Exclude { 22 cp.Exclude = make([]string, len(c.Exclude)) 23 copy(cp.Exclude, c.Exclude) 24 } 25 return cp 26 } 27 28 func copyConfigReferenceFields(cfg Config) Config { 29 cp := cfg 30 if nil != cfg.Labels { 31 cp.Labels = make(map[string]string, len(cfg.Labels)) 32 for key, val := range cfg.Labels { 33 cp.Labels[key] = val 34 } 35 } 36 if nil != cfg.ErrorCollector.IgnoreStatusCodes { 37 ignored := make([]int, len(cfg.ErrorCollector.IgnoreStatusCodes)) 38 copy(ignored, cfg.ErrorCollector.IgnoreStatusCodes) 39 cp.ErrorCollector.IgnoreStatusCodes = ignored 40 } 41 42 cp.Attributes = copyDestConfig(cfg.Attributes) 43 cp.ErrorCollector.Attributes = copyDestConfig(cfg.ErrorCollector.Attributes) 44 cp.TransactionEvents.Attributes = copyDestConfig(cfg.TransactionEvents.Attributes) 45 cp.TransactionTracer.Attributes = copyDestConfig(cfg.TransactionTracer.Attributes) 46 47 return cp 48 } 49 50 const ( 51 agentLanguage = "go" 52 ) 53 54 func transportSetting(t http.RoundTripper) interface{} { 55 if nil == t { 56 return nil 57 } 58 return fmt.Sprintf("%T", t) 59 } 60 61 func loggerSetting(lg Logger) interface{} { 62 if nil == lg { 63 return nil 64 } 65 if _, ok := lg.(logger.ShimLogger); ok { 66 return nil 67 } 68 return fmt.Sprintf("%T", lg) 69 } 70 71 const ( 72 // https://source.datanerd.us/agents/agent-specs/blob/master/Custom-Host-Names.md 73 hostByteLimit = 255 74 ) 75 76 type settings Config 77 78 func (s settings) MarshalJSON() ([]byte, error) { 79 c := Config(s) 80 transport := c.Transport 81 c.Transport = nil 82 logger := c.Logger 83 c.Logger = nil 84 85 js, err := json.Marshal(c) 86 if nil != err { 87 return nil, err 88 } 89 fields := make(map[string]interface{}) 90 err = json.Unmarshal(js, &fields) 91 if nil != err { 92 return nil, err 93 } 94 // The License field is not simply ignored by adding the `json:"-"` tag 95 // to it since we want to allow consumers to populate Config from JSON. 96 delete(fields, `License`) 97 fields[`Transport`] = transportSetting(transport) 98 fields[`Logger`] = loggerSetting(logger) 99 return json.Marshal(fields) 100 } 101 102 func configConnectJSONInternal(c Config, pid int, util *utilization.Data, e internal.Environment, version string, securityPolicies *internal.SecurityPolicies) ([]byte, error) { 103 return json.Marshal([]interface{}{struct { 104 Pid int `json:"pid"` 105 Language string `json:"language"` 106 Version string `json:"agent_version"` 107 Host string `json:"host"` 108 HostDisplayName string `json:"display_host,omitempty"` 109 Settings interface{} `json:"settings"` 110 AppName []string `json:"app_name"` 111 HighSecurity bool `json:"high_security"` 112 Labels internal.Labels `json:"labels,omitempty"` 113 Environment internal.Environment `json:"environment"` 114 Identifier string `json:"identifier"` 115 Util *utilization.Data `json:"utilization"` 116 SecurityPolicies *internal.SecurityPolicies `json:"security_policies,omitempty"` 117 }{ 118 Pid: pid, 119 Language: agentLanguage, 120 Version: version, 121 Host: internal.StringLengthByteLimit(util.Hostname, hostByteLimit), 122 HostDisplayName: internal.StringLengthByteLimit(c.HostDisplayName, hostByteLimit), 123 Settings: (settings)(c), 124 AppName: strings.Split(c.AppName, ";"), 125 HighSecurity: c.HighSecurity, 126 Labels: internal.Labels(c.Labels), 127 Environment: e, 128 // This identifier field is provided to avoid: 129 // https://newrelic.atlassian.net/browse/DSCORE-778 130 // 131 // This identifier is used by the collector to look up the real 132 // agent. If an identifier isn't provided, the collector will 133 // create its own based on the first appname, which prevents a 134 // single daemon from connecting "a;b" and "a;c" at the same 135 // time. 136 // 137 // Providing the identifier below works around this issue and 138 // allows users more flexibility in using application rollups. 139 Identifier: c.AppName, 140 Util: util, 141 SecurityPolicies: securityPolicies, 142 }}) 143 } 144 145 // config allows CreateConnectJSON to be a method on a non-public type. 146 type config struct{ Config } 147 148 func (c config) CreateConnectJSON(securityPolicies *internal.SecurityPolicies) ([]byte, error) { 149 env := internal.NewEnvironment() 150 util := utilization.Gather(utilization.Config{ 151 DetectAWS: c.Utilization.DetectAWS, 152 DetectDocker: c.Utilization.DetectDocker, 153 LogicalProcessors: c.Utilization.LogicalProcessors, 154 TotalRAMMIB: c.Utilization.TotalRAMMIB, 155 BillingHostname: c.Utilization.BillingHostname, 156 }, c.Logger) 157 return configConnectJSONInternal(c.Config, os.Getpid(), util, env, Version, securityPolicies) 158 }