98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
|
package internal
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"math/rand"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// DatastoreExternalTotals contains overview of external and datastore calls
|
||
|
// made during a transaction.
|
||
|
type DatastoreExternalTotals struct {
|
||
|
externalCallCount uint64
|
||
|
externalDuration time.Duration
|
||
|
datastoreCallCount uint64
|
||
|
datastoreDuration time.Duration
|
||
|
}
|
||
|
|
||
|
// TxnEvent represents a transaction.
|
||
|
// https://source.datanerd.us/agents/agent-specs/blob/master/Transaction-Events-PORTED.md
|
||
|
// https://newrelic.atlassian.net/wiki/display/eng/Agent+Support+for+Synthetics%3A+Forced+Transaction+Traces+and+Analytic+Events
|
||
|
type TxnEvent struct {
|
||
|
Name string
|
||
|
Timestamp time.Time
|
||
|
Duration time.Duration
|
||
|
Queuing time.Duration
|
||
|
Zone ApdexZone
|
||
|
Attrs *Attributes
|
||
|
DatastoreExternalTotals
|
||
|
}
|
||
|
|
||
|
// WriteJSON prepares JSON in the format expected by the collector.
|
||
|
func (e *TxnEvent) WriteJSON(buf *bytes.Buffer) {
|
||
|
w := jsonFieldsWriter{buf: buf}
|
||
|
buf.WriteByte('[')
|
||
|
buf.WriteByte('{')
|
||
|
w.stringField("type", "Transaction")
|
||
|
w.stringField("name", e.Name)
|
||
|
w.floatField("timestamp", timeToFloatSeconds(e.Timestamp))
|
||
|
w.floatField("duration", e.Duration.Seconds())
|
||
|
if ApdexNone != e.Zone {
|
||
|
w.stringField("nr.apdexPerfZone", e.Zone.label())
|
||
|
}
|
||
|
if e.Queuing > 0 {
|
||
|
w.floatField("queueDuration", e.Queuing.Seconds())
|
||
|
}
|
||
|
if e.externalCallCount > 0 {
|
||
|
w.intField("externalCallCount", int64(e.externalCallCount))
|
||
|
w.floatField("externalDuration", e.externalDuration.Seconds())
|
||
|
}
|
||
|
if e.datastoreCallCount > 0 {
|
||
|
// Note that "database" is used for the keys here instead of
|
||
|
// "datastore" for historical reasons.
|
||
|
w.intField("databaseCallCount", int64(e.datastoreCallCount))
|
||
|
w.floatField("databaseDuration", e.datastoreDuration.Seconds())
|
||
|
}
|
||
|
buf.WriteByte('}')
|
||
|
buf.WriteByte(',')
|
||
|
userAttributesJSON(e.Attrs, buf, destTxnEvent)
|
||
|
buf.WriteByte(',')
|
||
|
agentAttributesJSON(e.Attrs, buf, destTxnEvent)
|
||
|
buf.WriteByte(']')
|
||
|
}
|
||
|
|
||
|
// MarshalJSON is used for testing.
|
||
|
func (e *TxnEvent) MarshalJSON() ([]byte, error) {
|
||
|
buf := bytes.NewBuffer(make([]byte, 0, 256))
|
||
|
|
||
|
e.WriteJSON(buf)
|
||
|
|
||
|
return buf.Bytes(), nil
|
||
|
}
|
||
|
|
||
|
type txnEvents struct {
|
||
|
events *analyticsEvents
|
||
|
}
|
||
|
|
||
|
func newTxnEvents(max int) *txnEvents {
|
||
|
return &txnEvents{
|
||
|
events: newAnalyticsEvents(max),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (events *txnEvents) AddTxnEvent(e *TxnEvent) {
|
||
|
stamp := eventStamp(rand.Float32())
|
||
|
events.events.addEvent(analyticsEvent{stamp, e})
|
||
|
}
|
||
|
|
||
|
func (events *txnEvents) MergeIntoHarvest(h *Harvest) {
|
||
|
h.TxnEvents.events.mergeFailed(events.events)
|
||
|
}
|
||
|
|
||
|
func (events *txnEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
|
||
|
return events.events.CollectorJSON(agentRunID)
|
||
|
}
|
||
|
|
||
|
func (events *txnEvents) numSeen() float64 { return events.events.NumSeen() }
|
||
|
func (events *txnEvents) numSaved() float64 { return events.events.NumSaved() }
|