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  }