| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- package internal
- import (
- "bytes"
- "time"
- )
- // https://source.datanerd.us/agents/agent-specs/blob/master/Span-Events.md
- type spanCategory string
- const (
- spanCategoryHTTP spanCategory = "http"
- spanCategoryDatastore = "datastore"
- spanCategoryGeneric = "generic"
- )
- // SpanEvent represents a span event, necessary to support Distributed Tracing.
- type SpanEvent struct {
- TraceID string
- GUID string
- ParentID string
- TransactionID string
- Sampled bool
- Priority Priority
- Timestamp time.Time
- Duration time.Duration
- Name string
- Category spanCategory
- IsEntrypoint bool
- DatastoreExtras *spanDatastoreExtras
- ExternalExtras *spanExternalExtras
- }
- type spanDatastoreExtras struct {
- Component string
- Statement string
- Instance string
- Address string
- Hostname string
- }
- type spanExternalExtras struct {
- URL string
- Method string
- Component string
- }
- // WriteJSON prepares JSON in the format expected by the collector.
- func (e *SpanEvent) WriteJSON(buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('[')
- buf.WriteByte('{')
- w.stringField("type", "Span")
- w.stringField("traceId", e.TraceID)
- w.stringField("guid", e.GUID)
- if "" != e.ParentID {
- w.stringField("parentId", e.ParentID)
- }
- w.stringField("transactionId", e.TransactionID)
- w.boolField("sampled", e.Sampled)
- w.writerField("priority", e.Priority)
- w.intField("timestamp", e.Timestamp.UnixNano()/(1000*1000)) // in milliseconds
- w.floatField("duration", e.Duration.Seconds())
- w.stringField("name", e.Name)
- w.stringField("category", string(e.Category))
- if e.IsEntrypoint {
- w.boolField("nr.entryPoint", true)
- }
- if ex := e.DatastoreExtras; nil != ex {
- if "" != ex.Component {
- w.stringField("component", ex.Component)
- }
- if "" != ex.Statement {
- w.stringField("db.statement", ex.Statement)
- }
- if "" != ex.Instance {
- w.stringField("db.instance", ex.Instance)
- }
- if "" != ex.Address {
- w.stringField("peer.address", ex.Address)
- }
- if "" != ex.Hostname {
- w.stringField("peer.hostname", ex.Hostname)
- }
- w.stringField("span.kind", "client")
- }
- if ex := e.ExternalExtras; nil != ex {
- if "" != ex.URL {
- w.stringField("http.url", ex.URL)
- }
- if "" != ex.Method {
- w.stringField("http.method", ex.Method)
- }
- w.stringField("span.kind", "client")
- w.stringField("component", "http")
- }
- buf.WriteByte('}')
- buf.WriteByte(',')
- buf.WriteByte('{')
- buf.WriteByte('}')
- buf.WriteByte(',')
- buf.WriteByte('{')
- buf.WriteByte('}')
- buf.WriteByte(']')
- }
- // MarshalJSON is used for testing.
- func (e *SpanEvent) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 256))
- e.WriteJSON(buf)
- return buf.Bytes(), nil
- }
- type spanEvents struct {
- events *analyticsEvents
- }
- func newSpanEvents(max int) *spanEvents {
- return &spanEvents{
- events: newAnalyticsEvents(max),
- }
- }
- func (events *spanEvents) addEvent(e *SpanEvent, cat *BetterCAT) {
- e.TraceID = cat.TraceID()
- e.TransactionID = cat.ID
- e.Sampled = cat.Sampled
- e.Priority = cat.Priority
- events.events.addEvent(analyticsEvent{priority: cat.Priority, jsonWriter: e})
- }
- // MergeFromTransaction merges the span events from a transaction into the
- // harvest's span events. This should only be called if the transaction was
- // sampled and span events are enabled.
- func (events *spanEvents) MergeFromTransaction(txndata *TxnData) {
- root := &SpanEvent{
- GUID: txndata.getRootSpanID(),
- Timestamp: txndata.Start,
- Duration: txndata.Duration,
- Name: txndata.FinalName,
- Category: spanCategoryGeneric,
- IsEntrypoint: true,
- }
- if nil != txndata.BetterCAT.Inbound {
- root.ParentID = txndata.BetterCAT.Inbound.ID
- }
- events.addEvent(root, &txndata.BetterCAT)
- for _, evt := range txndata.spanEvents {
- events.addEvent(evt, &txndata.BetterCAT)
- }
- }
- func (events *spanEvents) MergeIntoHarvest(h *Harvest) {
- h.SpanEvents.events.mergeFailed(events.events)
- }
- func (events *spanEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return events.events.CollectorJSON(agentRunID)
- }
- func (events *spanEvents) numSeen() float64 { return events.events.NumSeen() }
- func (events *spanEvents) numSaved() float64 { return events.events.NumSaved() }
- func (events *spanEvents) EndpointMethod() string {
- return cmdSpanEvents
- }
|