github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/txn_events.go (about) 1 package internal 2 3 import ( 4 "bytes" 5 "math/rand" 6 "sort" 7 "strings" 8 "time" 9 ) 10 11 // DatastoreExternalTotals contains overview of external and datastore calls 12 // made during a transaction. 13 type DatastoreExternalTotals struct { 14 externalCallCount uint64 15 externalDuration time.Duration 16 datastoreCallCount uint64 17 datastoreDuration time.Duration 18 } 19 20 // WriteJSON prepares JSON in the format expected by the collector. 21 func (e *TxnEvent) WriteJSON(buf *bytes.Buffer) { 22 w := jsonFieldsWriter{buf: buf} 23 buf.WriteByte('[') 24 buf.WriteByte('{') 25 w.stringField("type", "Transaction") 26 w.stringField("name", e.FinalName) 27 w.floatField("timestamp", timeToFloatSeconds(e.Start)) 28 w.floatField("duration", e.Duration.Seconds()) 29 if ApdexNone != e.Zone { 30 w.stringField("nr.apdexPerfZone", e.Zone.label()) 31 } 32 if e.Queuing > 0 { 33 w.floatField("queueDuration", e.Queuing.Seconds()) 34 } 35 if e.externalCallCount > 0 { 36 w.intField("externalCallCount", int64(e.externalCallCount)) 37 w.floatField("externalDuration", e.externalDuration.Seconds()) 38 } 39 if e.datastoreCallCount > 0 { 40 // Note that "database" is used for the keys here instead of 41 // "datastore" for historical reasons. 42 w.intField("databaseCallCount", int64(e.datastoreCallCount)) 43 w.floatField("databaseDuration", e.datastoreDuration.Seconds()) 44 } 45 if e.CrossProcess.Used() { 46 if e.CrossProcess.ClientID != "" { 47 w.stringField("client_cross_process_id", e.CrossProcess.ClientID) 48 } 49 if e.CrossProcess.TripID != "" { 50 w.stringField("nr.tripId", e.CrossProcess.TripID) 51 } 52 if e.CrossProcess.PathHash != "" { 53 w.stringField("nr.pathHash", e.CrossProcess.PathHash) 54 } 55 if e.CrossProcess.ReferringPathHash != "" { 56 w.stringField("nr.referringPathHash", e.CrossProcess.ReferringPathHash) 57 } 58 if e.CrossProcess.GUID != "" { 59 w.stringField("nr.guid", e.CrossProcess.GUID) 60 } 61 if e.CrossProcess.ReferringTxnGUID != "" { 62 w.stringField("nr.referringTransactionGuid", e.CrossProcess.ReferringTxnGUID) 63 } 64 if len(e.CrossProcess.AlternatePathHashes) > 0 { 65 hashes := make([]string, 0, len(e.CrossProcess.AlternatePathHashes)) 66 for hash := range e.CrossProcess.AlternatePathHashes { 67 hashes = append(hashes, hash) 68 } 69 sort.Strings(hashes) 70 w.stringField("nr.alternatePathHashes", strings.Join(hashes, ",")) 71 } 72 if e.CrossProcess.IsSynthetics() { 73 w.stringField("nr.syntheticsResourceId", e.CrossProcess.Synthetics.ResourceID) 74 w.stringField("nr.syntheticsJobId", e.CrossProcess.Synthetics.JobID) 75 w.stringField("nr.syntheticsMonitorId", e.CrossProcess.Synthetics.MonitorID) 76 } 77 } 78 buf.WriteByte('}') 79 buf.WriteByte(',') 80 userAttributesJSON(e.Attrs, buf, destTxnEvent, nil) 81 buf.WriteByte(',') 82 agentAttributesJSON(e.Attrs, buf, destTxnEvent) 83 buf.WriteByte(']') 84 } 85 86 // MarshalJSON is used for testing. 87 func (e *TxnEvent) MarshalJSON() ([]byte, error) { 88 buf := bytes.NewBuffer(make([]byte, 0, 256)) 89 90 e.WriteJSON(buf) 91 92 return buf.Bytes(), nil 93 } 94 95 type txnEvents struct { 96 events *analyticsEvents 97 } 98 99 func newTxnEvents(max int) *txnEvents { 100 return &txnEvents{ 101 events: newAnalyticsEvents(max), 102 } 103 } 104 105 func (events *txnEvents) AddTxnEvent(e *TxnEvent) { 106 stamp := eventStamp(rand.Float32()) 107 108 // Synthetics events always get priority: normal event stamps are in the 109 // range [0.0,1.0), so adding 1 means that a Synthetics event will always 110 // win. 111 if e.CrossProcess.IsSynthetics() { 112 stamp += 1.0 113 } 114 115 events.events.addEvent(analyticsEvent{stamp, e}) 116 } 117 118 func (events *txnEvents) MergeIntoHarvest(h *Harvest) { 119 h.TxnEvents.events.mergeFailed(events.events) 120 } 121 122 func (events *txnEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) { 123 return events.events.CollectorJSON(agentRunID) 124 } 125 126 func (events *txnEvents) numSeen() float64 { return events.events.NumSeen() } 127 func (events *txnEvents) numSaved() float64 { return events.events.NumSaved() }