| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- 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
- SpanEvents *spanEvents
- }
- const (
- // txnEventPayloadlimit is the maximum number of events that should be
- // sent up in one post.
- txnEventPayloadlimit = 5000
- )
- // Payloads returns a map from expected collector method name to data type.
- func (h *Harvest) Payloads(splitLargeTxnEvents bool) []PayloadCreator {
- ps := []PayloadCreator{
- h.Metrics,
- h.CustomEvents,
- h.ErrorEvents,
- h.ErrorTraces,
- h.TxnTraces,
- h.SlowSQLs,
- h.SpanEvents,
- }
- if splitLargeTxnEvents {
- ps = append(ps, h.TxnEvents.payloads(txnEventPayloadlimit)...)
- } else {
- ps = append(ps, h.TxnEvents)
- }
- return ps
- }
- // 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),
- SpanEvents: newSpanEvents(maxSpanEvents),
- }
- }
- 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)
- h.Metrics.addCount(spanEventsSeen, h.SpanEvents.numSeen(), forced)
- h.Metrics.addCount(spanEventsSent, h.SpanEvents.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)
- // EndpointMethod is used for the "method" query parameter when posting
- // the data.
- EndpointMethod() string
- }
- func supportMetric(metrics *metricTable, b bool, metricName string) {
- if b {
- metrics.addSingleCount(metricName, forced)
- }
- }
- // CreateTxnMetrics creates metrics for a transaction.
- func CreateTxnMetrics(args *TxnData, metrics *metricTable) {
- // Duration Metrics
- rollup := backgroundRollup
- if args.IsWeb {
- rollup = webRollup
- metrics.addDuration(dispatcherMetric, "", args.Duration, 0, forced)
- }
- metrics.addDuration(args.FinalName, "", args.Duration, args.Exclusive, forced)
- metrics.addDuration(rollup, "", args.Duration, args.Exclusive, forced)
- // Better CAT Metrics
- if cat := args.BetterCAT; cat.Enabled {
- caller := callerUnknown
- if nil != cat.Inbound {
- caller = cat.Inbound.payloadCaller
- }
- m := durationByCallerMetric(caller)
- metrics.addDuration(m.all, "", args.Duration, args.Duration, unforced)
- metrics.addDuration(m.webOrOther(args.IsWeb), "", args.Duration, args.Duration, unforced)
- // Transport Duration Metric
- if nil != cat.Inbound {
- d := cat.Inbound.TransportDuration
- m = transportDurationMetric(caller)
- metrics.addDuration(m.all, "", d, d, unforced)
- metrics.addDuration(m.webOrOther(args.IsWeb), "", d, d, unforced)
- }
- // CAT Error Metrics
- if args.HasErrors() {
- m = errorsByCallerMetric(caller)
- metrics.addSingleCount(m.all, unforced)
- metrics.addSingleCount(m.webOrOther(args.IsWeb), unforced)
- }
- supportMetric(metrics, args.AcceptPayloadSuccess, supportTracingAcceptSuccess)
- supportMetric(metrics, args.AcceptPayloadException, supportTracingAcceptException)
- supportMetric(metrics, args.AcceptPayloadParseException, supportTracingAcceptParseException)
- supportMetric(metrics, args.AcceptPayloadCreateBeforeAccept, supportTracingCreateBeforeAccept)
- supportMetric(metrics, args.AcceptPayloadIgnoredMultiple, supportTracingIgnoredMultiple)
- supportMetric(metrics, args.AcceptPayloadIgnoredVersion, supportTracingIgnoredVersion)
- supportMetric(metrics, args.AcceptPayloadUntrustedAccount, supportTracingAcceptUntrustedAccount)
- supportMetric(metrics, args.AcceptPayloadNullPayload, supportTracingAcceptNull)
- supportMetric(metrics, args.CreatePayloadSuccess, supportTracingCreatePayloadSuccess)
- supportMetric(metrics, args.CreatePayloadException, supportTracingCreatePayloadException)
- }
- // Apdex Metrics
- if args.Zone != ApdexNone {
- metrics.addApdex(apdexRollup, "", args.ApdexThreshold, args.Zone, forced)
- mname := apdexPrefix + removeFirstSegment(args.FinalName)
- metrics.addApdex(mname, "", args.ApdexThreshold, args.Zone, unforced)
- }
- // Error Metrics
- if args.HasErrors() {
- metrics.addSingleCount(errorsRollupMetric.all, forced)
- metrics.addSingleCount(errorsRollupMetric.webOrOther(args.IsWeb), forced)
- metrics.addSingleCount(errorsPrefix+args.FinalName, forced)
- }
- // Queueing Metrics
- if args.Queuing > 0 {
- metrics.addDuration(queueMetric, "", args.Queuing, args.Queuing, forced)
- }
- }
|