@@ -78,7 +78,7 @@ public void stop() {
78
78
public Object toLogValue () {
79
79
return LogValueMapFactory .builder (this )
80
80
.put ("source" , _source )
81
- .put ("findAndReplace " , _findAndReplace )
81
+ .put ("tranformations " , _transformations )
82
82
.build ();
83
83
}
84
84
@@ -90,24 +90,13 @@ public String toString() {
90
90
private TransformingSource (final Builder builder ) {
91
91
super (builder );
92
92
_source = builder ._source ;
93
+ _transformations = builder ._transformations ;
93
94
94
- final ImmutableMap .Builder <Pattern , ImmutableList <String >> findReplaceBuilder =
95
- ImmutableMap .builderWithExpectedSize (builder ._findAndReplace .size ());
96
- for (final ImmutableMap .Entry <String , ? extends ImmutableList <String >> entry : builder ._findAndReplace .entrySet ()) {
97
- findReplaceBuilder .put (Pattern .compile (entry .getKey ()), ImmutableList .copyOf (entry .getValue ()));
98
- }
99
- _findAndReplace = findReplaceBuilder .build ();
100
-
101
- _inject = builder ._inject ;
102
- _remove = builder ._remove ;
103
-
104
- _source .attach (new TransformingObserver (this , _findAndReplace , _inject , _remove ));
95
+ _source .attach (new TransformingObserver (this , _transformations ));
105
96
}
106
97
107
98
private final Source _source ;
108
- private final ImmutableMap <Pattern , ImmutableList <String >> _findAndReplace ;
109
- private final ImmutableMap <String , DimensionInjection > _inject ;
110
- private final ImmutableList <String > _remove ;
99
+ private final ImmutableList <TransformationSet > _transformations ;
111
100
112
101
private static final Logger LOGGER = LoggerFactory .getLogger (TransformingSource .class );
113
102
private static final Splitter .MapSplitter TAG_SPLITTER = Splitter .on (';' ).omitEmptyStrings ().trimResults ().withKeyValueSeparator ('=' );
@@ -117,13 +106,9 @@ private TransformingSource(final Builder builder) {
117
106
118
107
/* package private */ TransformingObserver (
119
108
final TransformingSource source ,
120
- final ImmutableMap <Pattern , ImmutableList <String >> findAndReplace ,
121
- final ImmutableMap <String , DimensionInjection > inject ,
122
- final ImmutableList <String > remove ) {
109
+ final ImmutableList <TransformationSet > transformations ) {
123
110
_source = source ;
124
- _findAndReplace = findAndReplace ;
125
- _inject = inject ;
126
- _remove = remove ;
111
+ _transformations = transformations ;
127
112
}
128
113
129
114
@ Override
@@ -139,79 +124,86 @@ public void notify(final Observable observable, final Object event) {
139
124
// Merge the metrics in the record together
140
125
final Record record = (Record ) event ;
141
126
final Map <Key , Map <String , MergingMetric >> mergedMetrics = Maps .newHashMap ();
142
- for (final Map .Entry <String , ? extends Metric > metric : record .getMetrics ().entrySet ()) {
143
- boolean found = false ;
144
- final String metricName = metric .getKey ();
145
- for (final Map .Entry <Pattern , ImmutableList <String >> findAndReplace : _findAndReplace .entrySet ()) {
146
- final Pattern metricPattern = findAndReplace .getKey ();
147
- final Matcher matcher = metricPattern .matcher (metricName );
148
- if (matcher .find ()) {
149
- for (final String replacement : findAndReplace .getValue ()) {
150
- final RegexAndMapReplacer .Replacement rep =
151
- RegexAndMapReplacer .replaceAll (metricPattern , metricName , replacement , record .getDimensions ());
152
- final String replacedString = rep .getReplacement ();
153
- final ImmutableList <String > consumedDimensions = rep .getVariablesMatched ();
154
-
155
- final int tagsStart = replacedString .indexOf (';' );
156
- if (tagsStart == -1 ) {
157
- // We just have a metric name. Optimize for this common case
158
- merge (
159
- metric .getValue (),
160
- replacedString ,
161
- mergedMetrics ,
162
- getModifiedDimensions (record .getDimensions (), Collections .emptyMap (), consumedDimensions ));
163
- } else {
164
- final String newMetricName = replacedString .substring (0 , tagsStart );
165
- final Map <String , String > parsedTags = TAG_SPLITTER .split (replacedString .substring (tagsStart + 1 ));
166
- merge (
167
- metric .getValue (),
168
- newMetricName ,
169
- mergedMetrics ,
170
- getModifiedDimensions (record .getDimensions (), parsedTags , consumedDimensions ));
127
+ for (TransformationSet transformation : _transformations ) {
128
+ for (final Map .Entry <String , ? extends Metric > metric : record .getMetrics ().entrySet ()) {
129
+ boolean found = false ;
130
+ final String metricName = metric .getKey ();
131
+ for (final Map .Entry <Pattern , ImmutableList <String >> findAndReplace : transformation .getFindAndReplace ().entrySet ()) {
132
+ final Pattern metricPattern = findAndReplace .getKey ();
133
+ final Matcher matcher = metricPattern .matcher (metricName );
134
+ if (matcher .find ()) {
135
+ for (final String replacement : findAndReplace .getValue ()) {
136
+ final RegexAndMapReplacer .Replacement rep =
137
+ RegexAndMapReplacer .replaceAll (metricPattern , metricName , replacement , record .getDimensions ());
138
+ final String replacedString = rep .getReplacement ();
139
+ final ImmutableList <String > consumedDimensions = rep .getVariablesMatched ();
140
+
141
+ final int tagsStart = replacedString .indexOf (';' );
142
+ if (tagsStart == -1 ) {
143
+ // We just have a metric name. Optimize for this common case
144
+ merge (
145
+ metric .getValue (),
146
+ replacedString ,
147
+ mergedMetrics ,
148
+ getModifiedDimensions (
149
+ record .getDimensions (),
150
+ Collections .emptyMap (),
151
+ consumedDimensions ,
152
+ transformation ));
153
+ } else {
154
+ final String newMetricName = replacedString .substring (0 , tagsStart );
155
+ final Map <String , String > parsedTags = TAG_SPLITTER .split (replacedString .substring (tagsStart + 1 ));
156
+ merge (
157
+ metric .getValue (),
158
+ newMetricName ,
159
+ mergedMetrics ,
160
+ getModifiedDimensions (record .getDimensions (), parsedTags , consumedDimensions , transformation ));
161
+ }
171
162
}
163
+ //Having "found" set here means that mapping a metric to an empty list suppresses that metric
164
+ found = true ;
172
165
}
173
- //Having "found" set here means that mapping a metric to an empty list suppresses that metric
174
- found = true ;
166
+ }
167
+ if (!found ) {
168
+ merge (
169
+ metric .getValue (),
170
+ metricName ,
171
+ mergedMetrics ,
172
+ getModifiedDimensions (record .getDimensions (), Collections .emptyMap (), ImmutableList .of (), transformation ));
175
173
}
176
174
}
177
- if (!found ) {
178
- merge (
179
- metric .getValue (),
180
- metricName ,
181
- mergedMetrics ,
182
- getModifiedDimensions (record .getDimensions (), Collections .emptyMap (), ImmutableList .of ()));
183
- }
184
- }
185
175
186
- // Raise the merged record event with this source's observers
187
- // NOTE: Do not leak instances of MergingMetric since it is mutable
188
- for (final Map .Entry <Key , Map <String , MergingMetric >> entry : mergedMetrics .entrySet ()) {
189
- _source .notify (
190
- ThreadLocalBuilder .build (
191
- DefaultRecord .Builder .class ,
192
- b1 -> b1 .setMetrics (
193
- entry .getValue ().entrySet ().stream ().collect (
194
- ImmutableMap .toImmutableMap (
195
- Map .Entry ::getKey ,
196
- e -> ThreadLocalBuilder .clone (
197
- e .getValue (),
198
- DefaultMetric .Builder .class ))))
199
- .setId (record .getId ())
200
- .setTime (record .getTime ())
201
- .setAnnotations (record .getAnnotations ())
202
- .setDimensions (entry .getKey ().getParameters ())));
176
+ // Raise the merged record event with this source's observers
177
+ // NOTE: Do not leak instances of MergingMetric since it is mutable
178
+ for (final Map .Entry <Key , Map <String , MergingMetric >> entry : mergedMetrics .entrySet ()) {
179
+ _source .notify (
180
+ ThreadLocalBuilder .build (
181
+ DefaultRecord .Builder .class ,
182
+ b1 -> b1 .setMetrics (
183
+ entry .getValue ().entrySet ().stream ().collect (
184
+ ImmutableMap .toImmutableMap (
185
+ Map .Entry ::getKey ,
186
+ e -> ThreadLocalBuilder .clone (
187
+ e .getValue (),
188
+ DefaultMetric .Builder .class ))))
189
+ .setId (record .getId ())
190
+ .setTime (record .getTime ())
191
+ .setAnnotations (record .getAnnotations ())
192
+ .setDimensions (entry .getKey ().getParameters ())));
193
+ }
203
194
}
204
195
}
205
196
206
197
private Key getModifiedDimensions (
207
198
final ImmutableMap <String , String > inputDimensions ,
208
199
final Map <String , String > add ,
209
- final ImmutableList <String > remove ) {
200
+ final ImmutableList <String > remove ,
201
+ final TransformationSet transformation ) {
210
202
final Map <String , String > finalTags = Maps .newHashMap (inputDimensions );
211
203
// Remove the dimensions that we consumed in the replacement
212
204
remove .forEach (finalTags ::remove );
213
- _remove .forEach (finalTags ::remove );
214
- _inject .forEach (
205
+ transformation . getRemove () .forEach (finalTags ::remove );
206
+ transformation . getInject () .forEach (
215
207
(key , inject ) ->
216
208
finalTags .compute (key , (k , oldValue ) ->
217
209
inject .isReplaceExisting () || oldValue == null ? inject .getValue () : oldValue ));
@@ -247,9 +239,7 @@ private void merge(
247
239
}
248
240
249
241
private final TransformingSource _source ;
250
- private final ImmutableMap <Pattern , ImmutableList <String >> _findAndReplace ;
251
- private final ImmutableMap <String , DimensionInjection > _inject ;
252
- private final ImmutableList <String > _remove ;
242
+ private final ImmutableList <TransformationSet > _transformations ;
253
243
}
254
244
255
245
// NOTE: Package private for testing
@@ -357,6 +347,87 @@ public Builder setReplaceExisting(final Boolean value) {
357
347
}
358
348
}
359
349
350
+ public static final class TransformationSet {
351
+ public ImmutableMap <Pattern , ImmutableList <String >> getFindAndReplace () {
352
+ return _findAndReplace ;
353
+ }
354
+
355
+ public ImmutableMap <String , DimensionInjection > getInject () {
356
+ return _inject ;
357
+ }
358
+
359
+ public ImmutableList <String > getRemove () {
360
+ return _remove ;
361
+ }
362
+
363
+ private TransformationSet (final Builder builder ) {
364
+ final ImmutableMap .Builder <Pattern , ImmutableList <String >> findReplaceBuilder =
365
+ ImmutableMap .builderWithExpectedSize (builder ._findAndReplace .size ());
366
+ for (final ImmutableMap .Entry <String , ? extends ImmutableList <String >> entry : builder ._findAndReplace .entrySet ()) {
367
+ findReplaceBuilder .put (Pattern .compile (entry .getKey ()), ImmutableList .copyOf (entry .getValue ()));
368
+ }
369
+ _findAndReplace = findReplaceBuilder .build ();
370
+ _inject = builder ._inject ;
371
+ _remove = builder ._remove ;
372
+ }
373
+
374
+ private final ImmutableMap <String , DimensionInjection > _inject ;
375
+ private final ImmutableList <String > _remove ;
376
+ private final ImmutableMap <Pattern , ImmutableList <String >> _findAndReplace ;
377
+
378
+ /**
379
+ * Implementation of the builder pattern for a {@link TransformationSet}.
380
+ */
381
+ public static final class Builder extends OvalBuilder <TransformationSet > {
382
+ /**
383
+ * Public constructor.
384
+ */
385
+ public Builder () {
386
+ super (TransformationSet ::new );
387
+ }
388
+
389
+ /**
390
+ * Sets find and replace expression map. Optional. Cannot be null. Defaults to empty.
391
+ *
392
+ * @param value The find and replace expression map.
393
+ * @return This instance of <code>Builder</code>.
394
+ */
395
+ public Builder setFindAndReplace (final ImmutableMap <String , ? extends ImmutableList <String >> value ) {
396
+ _findAndReplace = value ;
397
+ return this ;
398
+ }
399
+
400
+ /**
401
+ * Sets dimensions to inject. Optional. Cannot be null. Defaults to empty.
402
+ *
403
+ * @param value List of dimensions to inject.
404
+ * @return This instance of <code>Builder</code>.
405
+ */
406
+ public Builder setInject (final ImmutableMap <String , DimensionInjection > value ) {
407
+ _inject = value ;
408
+ return this ;
409
+ }
410
+
411
+ /**
412
+ * Sets dimensions to remove. Optional. Cannot be null. Defaults to empty.
413
+ *
414
+ * @param value List of dimensions to inject.
415
+ * @return This instance of <code>Builder</code>.
416
+ */
417
+ public Builder setRemove (final ImmutableList <String > value ) {
418
+ _remove = value ;
419
+ return this ;
420
+ }
421
+
422
+ @ NotNull
423
+ private ImmutableMap <String , ? extends ImmutableList <String >> _findAndReplace = ImmutableMap .of ();
424
+ @ NotNull
425
+ private ImmutableMap <String , DimensionInjection > _inject = ImmutableMap .of ();
426
+ @ NotNull
427
+ private ImmutableList <String > _remove = ImmutableList .of ();
428
+ }
429
+ }
430
+
360
431
/**
361
432
* Implementation of builder pattern for {@link TransformingSource}.
362
433
*
@@ -375,43 +446,21 @@ public Builder() {
375
446
* Sets the underlying source. Cannot be null.
376
447
*
377
448
* @param value The underlying source.
378
- * @return This instance of <code> Builder</code> .
449
+ * @return This instance of {@link Builder} .
379
450
*/
380
451
public Builder setSource (final Source value ) {
381
452
_source = value ;
382
453
return this ;
383
454
}
384
455
385
456
/**
386
- * Sets find and replace expression map. Optional. Cannot be null. Defaults to empty.
387
- *
388
- * @param value The find and replace expression map.
389
- * @return This instance of <code>Builder</code>.
390
- */
391
- public Builder setFindAndReplace (final ImmutableMap <String , ? extends ImmutableList <String >> value ) {
392
- _findAndReplace = value ;
393
- return this ;
394
- }
395
-
396
- /**
397
- * Sets dimensions to inject. Optional. Cannot be null. Defaults to empty.
457
+ * Sets the transformations. Required. Cannot be null. Cannot be empty.
398
458
*
399
- * @param value List of dimensions to inject .
400
- * @return This instance of <code> Builder</code> .
459
+ * @param value The list of transformations to apply .
460
+ * @return This instance of {@link Builder} .
401
461
*/
402
- public Builder setInject (final ImmutableMap <String , DimensionInjection > value ) {
403
- _inject = value ;
404
- return this ;
405
- }
406
-
407
- /**
408
- * Sets dimensions to remove. Optional. Cannot be null. Defaults to empty.
409
- *
410
- * @param value List of dimensions to inject.
411
- * @return This instance of <code>Builder</code>.
412
- */
413
- public Builder setRemove (final ImmutableList <String > value ) {
414
- _remove = value ;
462
+ public Builder setTransformations (final ImmutableList <TransformationSet > value ) {
463
+ _transformations = value ;
415
464
return this ;
416
465
}
417
466
@@ -423,10 +472,7 @@ protected Builder self() {
423
472
@ NotNull
424
473
private Source _source ;
425
474
@ NotNull
426
- private ImmutableMap <String , ? extends ImmutableList <String >> _findAndReplace = ImmutableMap .of ();
427
- @ NotNull
428
- private ImmutableMap <String , DimensionInjection > _inject = ImmutableMap .of ();
429
- @ NotNull
430
- private ImmutableList <String > _remove = ImmutableList .of ();
475
+ @ NotEmpty
476
+ private ImmutableList <TransformationSet > _transformations ;
431
477
}
432
478
}
0 commit comments