github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/harvest.go (about)

     1  package internal
     2  
     3  import (
     4  	"strings"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  // Harvestable is something that can be merged into a Harvest.
    10  type Harvestable interface {
    11  	MergeIntoHarvest(h *Harvest)
    12  }
    13  
    14  // Harvest contains collected data.
    15  type Harvest struct {
    16  	Metrics      *metricTable
    17  	CustomEvents *customEvents
    18  	TxnEvents    *txnEvents
    19  	ErrorEvents  *errorEvents
    20  	ErrorTraces  harvestErrors
    21  	TxnTraces    *harvestTraces
    22  	SlowSQLs     *slowQueries
    23  }
    24  
    25  // Payloads returns a map from expected collector method name to data type.
    26  func (h *Harvest) Payloads() map[string]PayloadCreator {
    27  	return map[string]PayloadCreator{
    28  		cmdMetrics:      h.Metrics,
    29  		cmdCustomEvents: h.CustomEvents,
    30  		cmdTxnEvents:    h.TxnEvents,
    31  		cmdErrorEvents:  h.ErrorEvents,
    32  		cmdErrorData:    h.ErrorTraces,
    33  		cmdTxnTraces:    h.TxnTraces,
    34  		cmdSlowSQLs:     h.SlowSQLs,
    35  	}
    36  }
    37  
    38  // NewHarvest returns a new Harvest.
    39  func NewHarvest(now time.Time) *Harvest {
    40  	return &Harvest{
    41  		Metrics:      newMetricTable(maxMetrics, now),
    42  		CustomEvents: newCustomEvents(maxCustomEvents),
    43  		TxnEvents:    newTxnEvents(maxTxnEvents),
    44  		ErrorEvents:  newErrorEvents(maxErrorEvents),
    45  		ErrorTraces:  newHarvestErrors(maxHarvestErrors),
    46  		TxnTraces:    newHarvestTraces(),
    47  		SlowSQLs:     newSlowQueries(maxHarvestSlowSQLs),
    48  	}
    49  }
    50  
    51  var (
    52  	trackMutex   sync.Mutex
    53  	trackMetrics []string
    54  )
    55  
    56  // TrackUsage helps track which integration packages are used.
    57  func TrackUsage(s ...string) {
    58  	trackMutex.Lock()
    59  	defer trackMutex.Unlock()
    60  
    61  	m := "Supportability/" + strings.Join(s, "/")
    62  	trackMetrics = append(trackMetrics, m)
    63  }
    64  
    65  func createTrackUsageMetrics(metrics *metricTable) {
    66  	trackMutex.Lock()
    67  	defer trackMutex.Unlock()
    68  
    69  	for _, m := range trackMetrics {
    70  		metrics.addSingleCount(m, forced)
    71  	}
    72  }
    73  
    74  // CreateFinalMetrics creates extra metrics at harvest time.
    75  func (h *Harvest) CreateFinalMetrics() {
    76  	h.Metrics.addSingleCount(instanceReporting, forced)
    77  
    78  	h.Metrics.addCount(customEventsSeen, h.CustomEvents.numSeen(), forced)
    79  	h.Metrics.addCount(customEventsSent, h.CustomEvents.numSaved(), forced)
    80  
    81  	h.Metrics.addCount(txnEventsSeen, h.TxnEvents.numSeen(), forced)
    82  	h.Metrics.addCount(txnEventsSent, h.TxnEvents.numSaved(), forced)
    83  
    84  	h.Metrics.addCount(errorEventsSeen, h.ErrorEvents.numSeen(), forced)
    85  	h.Metrics.addCount(errorEventsSent, h.ErrorEvents.numSaved(), forced)
    86  
    87  	if h.Metrics.numDropped > 0 {
    88  		h.Metrics.addCount(supportabilityDropped, float64(h.Metrics.numDropped), forced)
    89  	}
    90  
    91  	createTrackUsageMetrics(h.Metrics)
    92  }
    93  
    94  // PayloadCreator is a data type in the harvest.
    95  type PayloadCreator interface {
    96  	// In the event of a rpm request failure (hopefully simply an
    97  	// intermittent collector issue) the payload may be merged into the next
    98  	// time period's harvest.
    99  	Harvestable
   100  	// Data prepares JSON in the format expected by the collector endpoint.
   101  	// This method should return (nil, nil) if the payload is empty and no
   102  	// rpm request is necessary.
   103  	Data(agentRunID string, harvestStart time.Time) ([]byte, error)
   104  }
   105  
   106  // CreateTxnMetrics creates metrics for a transaction.
   107  func CreateTxnMetrics(args *TxnData, metrics *metricTable) {
   108  	// Duration Metrics
   109  	rollup := backgroundRollup
   110  	if args.IsWeb {
   111  		rollup = webRollup
   112  		metrics.addDuration(dispatcherMetric, "", args.Duration, 0, forced)
   113  	}
   114  
   115  	metrics.addDuration(args.FinalName, "", args.Duration, args.Exclusive, forced)
   116  	metrics.addDuration(rollup, "", args.Duration, args.Exclusive, forced)
   117  
   118  	// Apdex Metrics
   119  	if args.Zone != ApdexNone {
   120  		metrics.addApdex(apdexRollup, "", args.ApdexThreshold, args.Zone, forced)
   121  
   122  		mname := apdexPrefix + removeFirstSegment(args.FinalName)
   123  		metrics.addApdex(mname, "", args.ApdexThreshold, args.Zone, unforced)
   124  	}
   125  
   126  	// Error Metrics
   127  	if args.HasErrors() {
   128  		metrics.addSingleCount(errorsRollupMetric.all, forced)
   129  		metrics.addSingleCount(errorsRollupMetric.webOrOther(args.IsWeb), forced)
   130  		metrics.addSingleCount(errorsPrefix+args.FinalName, forced)
   131  	}
   132  
   133  	// Queueing Metrics
   134  	if args.Queuing > 0 {
   135  		metrics.addDuration(queueMetric, "", args.Queuing, args.Queuing, forced)
   136  	}
   137  }