github.com/m3db/m3@v1.5.0/src/cmd/services/m3coordinator/downsample/samples_appender.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package downsample 22 23 import ( 24 "github.com/uber-go/tally" 25 26 "github.com/m3db/m3/src/aggregator/aggregator" 27 "github.com/m3db/m3/src/aggregator/client" 28 "github.com/m3db/m3/src/metrics/metadata" 29 "github.com/m3db/m3/src/metrics/metric" 30 "github.com/m3db/m3/src/metrics/metric/aggregated" 31 "github.com/m3db/m3/src/metrics/metric/unaggregated" 32 xerrors "github.com/m3db/m3/src/x/errors" 33 xtime "github.com/m3db/m3/src/x/time" 34 ) 35 36 // samplesAppender must have one of agg or client set 37 type samplesAppender struct { 38 agg aggregator.Aggregator 39 clientRemote client.Client 40 processedCountNonRollup tally.Counter 41 processedCountRollup tally.Counter 42 operationsCount tally.Counter 43 44 unownedID []byte 45 stagedMetadatas metadata.StagedMetadatas 46 } 47 48 // Ensure samplesAppender implements SamplesAppender. 49 var _ SamplesAppender = (*samplesAppender)(nil) 50 51 // nolint:dupl 52 func (a samplesAppender) AppendUntimedCounterSample(t xtime.UnixNano, value int64, annotation []byte) error { 53 a.emitMetrics() 54 if a.clientRemote != nil { 55 // Remote client write instead of local aggregation. 56 sample := unaggregated.Counter{ 57 ID: a.unownedID, 58 Value: value, 59 Annotation: annotation, 60 ClientTimeNanos: t, 61 } 62 return a.clientRemote.WriteUntimedCounter(sample, a.stagedMetadatas) 63 } 64 65 sample := unaggregated.MetricUnion{ 66 Type: metric.CounterType, 67 ID: a.unownedID, 68 CounterVal: value, 69 Annotation: annotation, 70 } 71 return a.agg.AddUntimed(sample, a.stagedMetadatas) 72 } 73 74 // nolint:dupl 75 func (a samplesAppender) AppendUntimedGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error { 76 a.emitMetrics() 77 if a.clientRemote != nil { 78 // Remote client write instead of local aggregation. 79 sample := unaggregated.Gauge{ 80 ID: a.unownedID, 81 Value: value, 82 Annotation: annotation, 83 ClientTimeNanos: t, 84 } 85 return a.clientRemote.WriteUntimedGauge(sample, a.stagedMetadatas) 86 } 87 88 sample := unaggregated.MetricUnion{ 89 Type: metric.GaugeType, 90 ID: a.unownedID, 91 GaugeVal: value, 92 Annotation: annotation, 93 } 94 return a.agg.AddUntimed(sample, a.stagedMetadatas) 95 } 96 97 func (a samplesAppender) AppendUntimedTimerSample(t xtime.UnixNano, value float64, annotation []byte) error { 98 a.emitMetrics() 99 if a.clientRemote != nil { 100 // Remote client write instead of local aggregation. 101 sample := unaggregated.BatchTimer{ 102 ID: a.unownedID, 103 Values: []float64{value}, 104 Annotation: annotation, 105 ClientTimeNanos: t, 106 } 107 return a.clientRemote.WriteUntimedBatchTimer(sample, a.stagedMetadatas) 108 } 109 110 sample := unaggregated.MetricUnion{ 111 Type: metric.TimerType, 112 ID: a.unownedID, 113 BatchTimerVal: []float64{value}, 114 Annotation: annotation, 115 } 116 return a.agg.AddUntimed(sample, a.stagedMetadatas) 117 } 118 119 func (a *samplesAppender) AppendCounterSample(t xtime.UnixNano, value int64, annotation []byte) error { 120 return a.appendTimedSample(aggregated.Metric{ 121 Type: metric.CounterType, 122 ID: a.unownedID, 123 TimeNanos: int64(t), 124 Value: float64(value), 125 Annotation: annotation, 126 }) 127 } 128 129 func (a *samplesAppender) AppendGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error { 130 return a.appendTimedSample(aggregated.Metric{ 131 Type: metric.GaugeType, 132 ID: a.unownedID, 133 TimeNanos: int64(t), 134 Value: value, 135 Annotation: annotation, 136 }) 137 } 138 139 func (a *samplesAppender) AppendTimerSample( 140 t xtime.UnixNano, value float64, annotation []byte, 141 ) error { 142 return a.appendTimedSample(aggregated.Metric{ 143 Type: metric.TimerType, 144 ID: a.unownedID, 145 TimeNanos: int64(t), 146 Value: value, 147 Annotation: annotation, 148 }) 149 } 150 151 func (a *samplesAppender) appendTimedSample(sample aggregated.Metric) error { 152 a.emitMetrics() 153 if a.clientRemote != nil { 154 return a.clientRemote.WriteTimedWithStagedMetadatas(sample, a.stagedMetadatas) 155 } 156 157 return a.agg.AddTimedWithStagedMetadatas(sample, a.stagedMetadatas) 158 } 159 160 func (a *samplesAppender) emitMetrics() { 161 for _, metadata := range a.stagedMetadatas { 162 // Separate out the rollup and non-rollup processed counts. For rollups 163 // additionally emit a metric that indicates the number of non-rollup 164 // operations in the rules. 165 var ( 166 numOperations = 0 167 isRollup bool 168 ) 169 for _, pipeline := range metadata.Pipelines { 170 if pipeline.IsAnyRollupRules() { 171 isRollup = true 172 } 173 numOperations += len(pipeline.Pipeline.Operations) 174 } 175 if isRollup { 176 a.processedCountRollup.Inc(1) 177 } else { 178 a.processedCountNonRollup.Inc(1) 179 } 180 // This includes operations other than the actual rollup. 181 if numOperations > 1 { 182 a.operationsCount.Inc(int64(numOperations - 1)) 183 } 184 } 185 } 186 187 // Ensure multiSamplesAppender implements SamplesAppender. 188 var _ SamplesAppender = (*multiSamplesAppender)(nil) 189 190 type multiSamplesAppender struct { 191 appenders []samplesAppender 192 } 193 194 func newMultiSamplesAppender() *multiSamplesAppender { 195 return &multiSamplesAppender{} 196 } 197 198 func (a *multiSamplesAppender) reset() { 199 for i := range a.appenders { 200 a.appenders[i] = samplesAppender{} 201 } 202 a.appenders = a.appenders[:0] 203 } 204 205 func (a *multiSamplesAppender) addSamplesAppender(v samplesAppender) { 206 a.appenders = append(a.appenders, v) 207 } 208 209 func (a *multiSamplesAppender) AppendUntimedCounterSample(t xtime.UnixNano, value int64, annotation []byte) error { 210 var multiErr xerrors.MultiError 211 for _, appender := range a.appenders { 212 multiErr = multiErr.Add(appender.AppendUntimedCounterSample(t, value, annotation)) 213 } 214 return multiErr.LastError() 215 } 216 217 func (a *multiSamplesAppender) AppendUntimedGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error { 218 var multiErr xerrors.MultiError 219 for _, appender := range a.appenders { 220 multiErr = multiErr.Add(appender.AppendUntimedGaugeSample(t, value, annotation)) 221 } 222 return multiErr.LastError() 223 } 224 225 func (a *multiSamplesAppender) AppendUntimedTimerSample(t xtime.UnixNano, value float64, annotation []byte) error { 226 var multiErr xerrors.MultiError 227 for _, appender := range a.appenders { 228 multiErr = multiErr.Add(appender.AppendUntimedTimerSample(t, value, annotation)) 229 } 230 return multiErr.LastError() 231 } 232 233 func (a *multiSamplesAppender) AppendCounterSample( 234 t xtime.UnixNano, value int64, annotation []byte, 235 ) error { 236 var multiErr xerrors.MultiError 237 for _, appender := range a.appenders { 238 multiErr = multiErr.Add(appender.AppendCounterSample(t, value, annotation)) 239 } 240 return multiErr.LastError() 241 } 242 243 func (a *multiSamplesAppender) AppendGaugeSample( 244 t xtime.UnixNano, value float64, annotation []byte, 245 ) error { 246 var multiErr xerrors.MultiError 247 for _, appender := range a.appenders { 248 multiErr = multiErr.Add(appender.AppendGaugeSample(t, value, annotation)) 249 } 250 return multiErr.LastError() 251 } 252 253 func (a *multiSamplesAppender) AppendTimerSample( 254 t xtime.UnixNano, value float64, annotation []byte, 255 ) error { 256 var multiErr xerrors.MultiError 257 for _, appender := range a.appenders { 258 multiErr = multiErr.Add(appender.AppendTimerSample(t, value, annotation)) 259 } 260 return multiErr.LastError() 261 }