| 60 | } |
| 61 | |
| 62 | func (s *DrainSanitizer) Sanitize(lbls labels.Labels) labels.Labels { |
| 63 | // Check the override at runtime so that changes to the sanitization mode override |
| 64 | // take effect without restarting the generator. |
| 65 | mode := s.sanitizeModeF(s.tenant) |
| 66 | if mode == SpanNameSanitizationDisabled { |
| 67 | return lbls |
| 68 | } |
| 69 | |
| 70 | s.doPeriodicMaintenance() |
| 71 | |
| 72 | s.mtx.Lock() |
| 73 | defer s.mtx.Unlock() |
| 74 | |
| 75 | spanName := lbls.Get(labelSpanName) |
| 76 | cluster := s.drain.Train(spanName) |
| 77 | // drain has various limits to prevent excessive memory usage, etc. in these |
| 78 | // cases, we will just return the original labels. |
| 79 | if cluster == nil { |
| 80 | s.demand.Insert(lbls.Hash()) |
| 81 | return lbls |
| 82 | } |
| 83 | |
| 84 | // before drain has found a pattern, it will return the original span name. |
| 85 | // in this case, we can avoid the expensive label building and just return |
| 86 | // the original labels. |
| 87 | newSpanName := cluster.String() |
| 88 | if newSpanName == spanName { |
| 89 | s.demand.Insert(lbls.Hash()) |
| 90 | return lbls |
| 91 | } |
| 92 | |
| 93 | s.metricTotalSpansSanitized.Inc() |
| 94 | builder := labels.NewBuilder(lbls) |
| 95 | builder.Set(labelSpanName, newSpanName) |
| 96 | newLbls := builder.Labels() |
| 97 | newLabelHash := newLbls.Hash() |
| 98 | s.demand.Insert(newLabelHash) |
| 99 | |
| 100 | // in dry-run mode, return the labels without modifying but capture metrics |
| 101 | if mode == SpanNameSanitizationDryRun { |
| 102 | return lbls |
| 103 | } |
| 104 | |
| 105 | return newLbls |
| 106 | } |
| 107 | |
| 108 | func (s *DrainSanitizer) doPeriodicMaintenance() { |
| 109 | select { |