diff --git a/modelwriter.go b/modelwriter.go index 2d7d2825b..c5df75b31 100644 --- a/modelwriter.go +++ b/modelwriter.go @@ -276,9 +276,11 @@ func normalizeOutcome(outcome string) string { } } -func buildDroppedSpansStats(dss droppedSpanTimingsMap) []model.DroppedSpansStats { - out := make([]model.DroppedSpansStats, 0, len(dss)) - for k, timing := range dss { +func buildDroppedSpansStats(dss *droppedSpanTimingsMap) []model.DroppedSpansStats { + dss.mu.RLock() + defer dss.mu.RUnlock() + out := make([]model.DroppedSpansStats, 0, len(dss.m)) + for k, timing := range dss.m { out = append(out, model.DroppedSpansStats{ DestinationServiceResource: k.destination, ServiceTargetType: k.serviceTargetType, diff --git a/transaction.go b/transaction.go index 69478a143..ddc202b3a 100644 --- a/transaction.go +++ b/transaction.go @@ -49,8 +49,10 @@ func (t *Tracer) StartTransactionOptions(name, transactionType string, opts Tran Context: Context{ captureBodyMask: CaptureBodyTransactions, }, - spanTimings: make(spanTimingsMap), - droppedSpansStats: make(droppedSpanTimingsMap, maxDroppedSpanStats), + spanTimings: make(spanTimingsMap), + droppedSpansStats: &droppedSpanTimingsMap{ + m: make(map[droppedSpanTimingsKey]spanTiming, maxDroppedSpanStats), + }, } var seed int64 if err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed); err != nil { @@ -409,7 +411,7 @@ type TransactionData struct { spansDropped int childrenTimer childrenTimer spanTimings spanTimingsMap - droppedSpansStats droppedSpanTimingsMap + droppedSpansStats *droppedSpanTimingsMap rand *rand.Rand // for ID generation compressedSpan compressedSpan @@ -439,28 +441,35 @@ type droppedSpanTimingsKey struct { } // droppedSpanTimingsMap records span timings for groups of dropped spans. -type droppedSpanTimingsMap map[droppedSpanTimingsKey]spanTiming +type droppedSpanTimingsMap struct { + m map[droppedSpanTimingsKey]spanTiming + mu sync.RWMutex +} // add accumulates the timing for a {destination, outcome} pair, silently drops // any pairs that would cause the map to exceed the maxDroppedSpanStats. -func (m droppedSpanTimingsMap) add(targetType, targetName, dst, outcome string, count int, d time.Duration) { +func (m *droppedSpanTimingsMap) add(targetType, targetName, dst, outcome string, count int, d time.Duration) { k := droppedSpanTimingsKey{ serviceTargetType: targetType, serviceTargetName: targetName, destination: dst, outcome: outcome, } - timing, ok := m[k] - if ok || maxDroppedSpanStats > len(m) { + m.mu.Lock() + defer m.mu.Unlock() + timing, ok := m.m[k] + if ok || maxDroppedSpanStats > len(m.m) { timing.count += uint64(count) timing.duration += int64(d) - m[k] = timing + m.m[k] = timing } } // reset resets m back to its initial zero state. -func (m droppedSpanTimingsMap) reset() { - for k := range m { - delete(m, k) +func (m *droppedSpanTimingsMap) reset() { + m.mu.Lock() + defer m.mu.Unlock() + for k := range m.m { + delete(m.m, k) } }