terraform/vendor/github.com/newrelic/go-agent/internal/harvest.go

154 lines
4.3 KiB
Go
Raw Normal View History

package internal
import (
"strings"
"sync"
"time"
)
// Harvestable is something that can be merged into a Harvest.
type Harvestable interface {
MergeIntoHarvest(h *Harvest)
}
// Harvest contains collected data.
type Harvest struct {
Metrics *metricTable
CustomEvents *customEvents
TxnEvents *txnEvents
ErrorEvents *errorEvents
ErrorTraces *harvestErrors
TxnTraces *harvestTraces
SlowSQLs *slowQueries
}
// Payloads returns a map from expected collector method name to data type.
func (h *Harvest) Payloads() map[string]PayloadCreator {
return map[string]PayloadCreator{
cmdMetrics: h.Metrics,
cmdCustomEvents: h.CustomEvents,
cmdTxnEvents: h.TxnEvents,
cmdErrorEvents: h.ErrorEvents,
cmdErrorData: h.ErrorTraces,
cmdTxnTraces: h.TxnTraces,
cmdSlowSQLs: h.SlowSQLs,
}
}
// NewHarvest returns a new Harvest.
func NewHarvest(now time.Time) *Harvest {
return &Harvest{
Metrics: newMetricTable(maxMetrics, now),
CustomEvents: newCustomEvents(maxCustomEvents),
TxnEvents: newTxnEvents(maxTxnEvents),
ErrorEvents: newErrorEvents(maxErrorEvents),
ErrorTraces: newHarvestErrors(maxHarvestErrors),
TxnTraces: newHarvestTraces(),
SlowSQLs: newSlowQueries(maxHarvestSlowSQLs),
}
}
var (
trackMutex sync.Mutex
trackMetrics []string
)
// TrackUsage helps track which integration packages are used.
func TrackUsage(s ...string) {
trackMutex.Lock()
defer trackMutex.Unlock()
m := "Supportability/" + strings.Join(s, "/")
trackMetrics = append(trackMetrics, m)
}
func createTrackUsageMetrics(metrics *metricTable) {
trackMutex.Lock()
defer trackMutex.Unlock()
for _, m := range trackMetrics {
metrics.addSingleCount(m, forced)
}
}
// CreateFinalMetrics creates extra metrics at harvest time.
func (h *Harvest) CreateFinalMetrics() {
h.Metrics.addSingleCount(instanceReporting, forced)
h.Metrics.addCount(customEventsSeen, h.CustomEvents.numSeen(), forced)
h.Metrics.addCount(customEventsSent, h.CustomEvents.numSaved(), forced)
h.Metrics.addCount(txnEventsSeen, h.TxnEvents.numSeen(), forced)
h.Metrics.addCount(txnEventsSent, h.TxnEvents.numSaved(), forced)
h.Metrics.addCount(errorEventsSeen, h.ErrorEvents.numSeen(), forced)
h.Metrics.addCount(errorEventsSent, h.ErrorEvents.numSaved(), forced)
if h.Metrics.numDropped > 0 {
h.Metrics.addCount(supportabilityDropped, float64(h.Metrics.numDropped), forced)
}
createTrackUsageMetrics(h.Metrics)
}
// PayloadCreator is a data type in the harvest.
type PayloadCreator interface {
// In the event of a rpm request failure (hopefully simply an
// intermittent collector issue) the payload may be merged into the next
// time period's harvest.
Harvestable
// Data prepares JSON in the format expected by the collector endpoint.
// This method should return (nil, nil) if the payload is empty and no
// rpm request is necessary.
Data(agentRunID string, harvestStart time.Time) ([]byte, error)
}
// CreateTxnMetricsArgs contains the parameters to CreateTxnMetrics.
type CreateTxnMetricsArgs struct {
IsWeb bool
Duration time.Duration
Exclusive time.Duration
Name string
Zone ApdexZone
ApdexThreshold time.Duration
HasErrors bool
Queueing time.Duration
}
// CreateTxnMetrics creates metrics for a transaction.
func CreateTxnMetrics(args CreateTxnMetricsArgs, metrics *metricTable) {
// Duration Metrics
rollup := backgroundRollup
if args.IsWeb {
rollup = webRollup
metrics.addDuration(dispatcherMetric, "", args.Duration, 0, forced)
}
metrics.addDuration(args.Name, "", args.Duration, args.Exclusive, forced)
metrics.addDuration(rollup, "", args.Duration, args.Exclusive, forced)
// Apdex Metrics
if args.Zone != ApdexNone {
metrics.addApdex(apdexRollup, "", args.ApdexThreshold, args.Zone, forced)
mname := apdexPrefix + removeFirstSegment(args.Name)
metrics.addApdex(mname, "", args.ApdexThreshold, args.Zone, unforced)
}
// Error Metrics
if args.HasErrors {
metrics.addSingleCount(errorsAll, forced)
if args.IsWeb {
metrics.addSingleCount(errorsWeb, forced)
} else {
metrics.addSingleCount(errorsBackground, forced)
}
metrics.addSingleCount(errorsPrefix+args.Name, forced)
}
// Queueing Metrics
if args.Queueing > 0 {
metrics.addDuration(queueMetric, "", args.Queueing, args.Queueing, forced)
}
}