Skip to content

Commit c5a78d4

Browse files
Stephen-BaoStephen-Bao
and
Stephen-Bao
authored
Add support to clear custom dimensions and configure flush behavior on dimensions (#105)
* Added resetDimension method and a boolean field to control whether to preserve dimensions after each flush * Adjusted README to reflect correct behavior of flush and added methods * Added exmaples to README * Fixed some typos in README * Added setDimensions() with an option to preserve default dimensions * Adjusted the code format * Adjusted some documentation * Modified README to more clearly reflect the behavior of setFlushPreserveDimensions() Co-authored-by: Stephen-Bao <[email protected]>
1 parent 68ab8f5 commit c5a78d4

File tree

5 files changed

+187
-3
lines changed

5 files changed

+187
-3
lines changed

README.md

+31-1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,19 @@ setDimensions(
166166
)
167167
```
168168

169+
- MetricsLogger **setDimensions**(boolean useDefault, DimensionSet... dimensionSets)
170+
171+
Override all custom dimensions, with an option to configure whether to use default dimensions.
172+
173+
- MetricsLogger **resetDimensions**(boolean useDefault)
174+
175+
Explicitly clear all custom dimensions. The behavior of whether default dimensions should be used can be configured by the input parameter.
176+
177+
Examples:
178+
179+
```java
180+
resetDimensions(false) // this will clear all custom dimensions as well as disable default dimensions
181+
```
169182

170183
- MetricsLogger **setNamespace**(String value)
171184

@@ -194,7 +207,24 @@ setTimestamp(Instant.now())
194207

195208
- **flush**()
196209

197-
Flushes the current MetricsContext to the configured sink and resets all properties, dimensions and metric values. The namespace and default dimensions will be preserved across flushes.
210+
Flushes the current MetricsContext to the configured sink and resets all properties and metric values. The namespace and default dimensions will be preserved across flushes. Custom dimensions are preserved by default, but this behavior can be disabled by invoking `setFlushPreserveDimensions(false)`, so that no custom dimensions would be preserved after each flushing thereafter.
211+
212+
Example:
213+
214+
```java
215+
flush(); // default dimensions and custom dimensions will be preserved after each flush()
216+
```
217+
218+
```java
219+
setFlushPreserveDimensions(false);
220+
flush(); // only default dimensions will be preserved after each flush()
221+
```
222+
223+
```java
224+
setFlushPreserveDimensions(false);
225+
flush();
226+
resetDimensions(false); // default dimensions are disabled; no dimensions will be preserved after each flush()
227+
```
198228

199229
### Configuration
200230

src/main/java/software/amazon/cloudwatchlogs/emf/logger/MetricsLogger.java

+35-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.time.Instant;
2020
import java.util.concurrent.CompletableFuture;
21+
import lombok.Getter;
22+
import lombok.Setter;
2123
import lombok.extern.slf4j.Slf4j;
2224
import software.amazon.cloudwatchlogs.emf.environment.Environment;
2325
import software.amazon.cloudwatchlogs.emf.environment.EnvironmentProvider;
@@ -36,6 +38,8 @@ public class MetricsLogger {
3638
private CompletableFuture<Environment> environmentFuture;
3739
private EnvironmentProvider environmentProvider;
3840

41+
@Getter @Setter private boolean flushPreserveDimensions = true;
42+
3943
public MetricsLogger() {
4044
this(new EnvironmentProvider());
4145
}
@@ -67,10 +71,14 @@ public void flush() {
6771
log.info("Failed to resolve environment. Fallback to default environment: ", ex);
6872
environment = environmentProvider.getDefaultEnvironment();
6973
}
74+
7075
ISink sink = environment.getSink();
7176
configureContextForEnvironment(context, environment);
7277
sink.accept(context);
73-
context = context.createCopyWithContext();
78+
context =
79+
flushPreserveDimensions
80+
? context.createCopyWithContext()
81+
: context.createCopyWithContextWithoutDimensions();
7482
}
7583

7684
/**
@@ -106,7 +114,7 @@ public MetricsLogger putDimensions(DimensionSet dimensions) {
106114
/**
107115
* Overwrite all dimensions on this MetricsLogger instance.
108116
*
109-
* @param dimensionSets the dimensionSets to set.
117+
* @param dimensionSets the dimensionSets to set
110118
* @see <a
111119
* href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html#Dimension">CloudWatch
112120
* Dimensions</a>
@@ -117,6 +125,31 @@ public MetricsLogger setDimensions(DimensionSet... dimensionSets) {
117125
return this;
118126
}
119127

128+
/**
129+
* Overwrite custom dimensions on this MetricsLogger instance, with an option to preserve
130+
* default dimensions.
131+
*
132+
* @param useDefault indicates whether default dimensions should be used
133+
* @param dimensionSets the dimensionSets to set
134+
* @return the current logger
135+
*/
136+
public MetricsLogger setDimensions(boolean useDefault, DimensionSet... dimensionSets) {
137+
context.setDimensions(useDefault, dimensionSets);
138+
return this;
139+
}
140+
141+
/**
142+
* Clear all custom dimensions on this MetricsLogger instance. Whether default dimensions should
143+
* be used can be configured by the input parameter.
144+
*
145+
* @param useDefault indicates whether default dimensions should be used
146+
* @return the current logger
147+
*/
148+
public MetricsLogger resetDimensions(boolean useDefault) {
149+
context.resetDimensions(useDefault);
150+
return this;
151+
}
152+
120153
/**
121154
* Put a metric value. This value will be emitted to CloudWatch Metrics asyncronously and does
122155
* not contribute to your account TPS limits. The value will also be available in your

src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricDirective.java

+36
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,27 @@ void setDimensions(List<DimensionSet> dimensionSets) {
9898
dimensions = new ArrayList<>(dimensionSets);
9999
}
100100

101+
/**
102+
* Override existing dimensions. Default dimensions are preserved optionally.
103+
*
104+
* @param useDefault indicates whether default dimensions should be used
105+
* @param dimensionSets the dimensionSets to be set
106+
*/
107+
void setDimensions(boolean useDefault, List<DimensionSet> dimensionSets) {
108+
shouldUseDefaultDimension = useDefault;
109+
dimensions = new ArrayList<>(dimensionSets);
110+
}
111+
112+
/**
113+
* Clear existing custom dimensions.
114+
*
115+
* @param useDefault indicates whether default dimensions should be used
116+
*/
117+
void resetDimensions(boolean useDefault) {
118+
shouldUseDefaultDimension = useDefault;
119+
dimensions = new ArrayList<>();
120+
}
121+
101122
/**
102123
* Return all the dimension sets. If there's a default dimension set, the custom dimensions are
103124
* prepended with the default dimensions.
@@ -138,4 +159,19 @@ MetricDirective copyWithoutMetrics() {
138159
metricDirective.shouldUseDefaultDimension = this.shouldUseDefaultDimension;
139160
return metricDirective;
140161
}
162+
163+
/**
164+
* Create a copy of the metric directive without having the existing metrics and custom
165+
* dimensions. The original state of default dimensions are preserved.
166+
*
167+
* @return an object of metric directive
168+
*/
169+
MetricDirective copyWithoutMetricsAndDimensions() {
170+
MetricDirective metricDirective = new MetricDirective();
171+
metricDirective.setDefaultDimensions(this.defaultDimensions);
172+
metricDirective.setNamespace(this.namespace);
173+
metricDirective.shouldUseDefaultDimension = this.shouldUseDefaultDimension;
174+
175+
return metricDirective;
176+
}
141177
}

src/main/java/software/amazon/cloudwatchlogs/emf/model/MetricsContext.java

+24
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,25 @@ public void setDimensions(DimensionSet... dimensionSets) {
186186
metricDirective.setDimensions(Arrays.asList(dimensionSets));
187187
}
188188

189+
/**
190+
* Update the dimensions. Default dimensions are preserved optionally.
191+
*
192+
* @param useDefault indicates whether default dimensions should be used
193+
* @param dimensionSets the dimensionSets to set
194+
*/
195+
public void setDimensions(boolean useDefault, DimensionSet... dimensionSets) {
196+
metricDirective.setDimensions(useDefault, Arrays.asList(dimensionSets));
197+
}
198+
199+
/**
200+
* Reset the dimensions. This would clear all custom dimensions.
201+
*
202+
* @param useDefault indicates whether default dimensions should be used
203+
*/
204+
public void resetDimensions(boolean useDefault) {
205+
metricDirective.resetDimensions(useDefault);
206+
}
207+
189208
/**
190209
* Add a key-value pair to the metadata
191210
*
@@ -215,6 +234,11 @@ public MetricsContext createCopyWithContext() {
215234
return new MetricsContext(metricDirective.copyWithoutMetrics());
216235
}
217236

237+
/** @return Creates an independently flushable context without metrics and custom dimensions */
238+
public MetricsContext createCopyWithContextWithoutDimensions() {
239+
return new MetricsContext(metricDirective.copyWithoutMetricsAndDimensions());
240+
}
241+
218242
/**
219243
* Serialize the metrics in this context to strings. The EMF backend requires no more than 100
220244
* metrics in one log event. If there're more than 100 metrics, we split the metrics into

src/test/java/software/amazon/cloudwatchlogs/emf/logger/MetricsLoggerTest.java

+61
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,38 @@ public void testOverrideDefaultDimensions() {
9393
sink.getContext().getDimensions().get(0).getDimensionValue(defaultDimName), null);
9494
}
9595

96+
@Test
97+
public void testResetWithDefaultDimensions() {
98+
String dimensionName = "dim";
99+
String dimensionValue = "dimValue";
100+
logger.putDimensions(DimensionSet.of("foo", "bar"));
101+
logger.resetDimensions(true);
102+
logger.putDimensions(DimensionSet.of(dimensionName, dimensionValue));
103+
logger.flush();
104+
105+
Assert.assertEquals(sink.getContext().getDimensions().size(), 1);
106+
Assert.assertEquals(sink.getContext().getDimensions().get(0).getDimensionKeys().size(), 4);
107+
Assert.assertEquals(
108+
sink.getContext().getDimensions().get(0).getDimensionValue(dimensionName),
109+
dimensionValue);
110+
}
111+
112+
@Test
113+
public void testResetWithoutDefaultDimensions() {
114+
String dimensionName = "dim";
115+
String dimensionValue = "dimValue";
116+
logger.putDimensions(DimensionSet.of("foo", "bar"));
117+
logger.resetDimensions(false);
118+
logger.putDimensions(DimensionSet.of(dimensionName, dimensionValue));
119+
logger.flush();
120+
121+
Assert.assertEquals(sink.getContext().getDimensions().size(), 1);
122+
Assert.assertEquals(sink.getContext().getDimensions().get(0).getDimensionKeys().size(), 1);
123+
Assert.assertEquals(
124+
sink.getContext().getDimensions().get(0).getDimensionValue(dimensionName),
125+
dimensionValue);
126+
}
127+
96128
@Test
97129
public void testOverridePreviousDimensions() {
98130

@@ -109,6 +141,21 @@ public void testOverridePreviousDimensions() {
109141
dimensionValue);
110142
}
111143

144+
@Test
145+
public void testSetDimensionsAndPreserveDefault() {
146+
String dimensionName = "dim";
147+
String dimensionValue = "dimValue";
148+
logger.putDimensions(DimensionSet.of("foo", "bar"));
149+
logger.setDimensions(true, DimensionSet.of(dimensionName, dimensionValue));
150+
logger.flush();
151+
152+
Assert.assertEquals(sink.getContext().getDimensions().size(), 1);
153+
Assert.assertEquals(sink.getContext().getDimensions().get(0).getDimensionKeys().size(), 4);
154+
Assert.assertEquals(
155+
sink.getContext().getDimensions().get(0).getDimensionValue(dimensionName),
156+
dimensionValue);
157+
}
158+
112159
@Test
113160
public void testSetNamespace() {
114161

@@ -229,6 +276,20 @@ public void testFlushPreserveDimensions() {
229276
expectDimension("Name", "Test");
230277
}
231278

279+
@Test
280+
public void testFlushDoesntPreserveDimensions() {
281+
logger.putDimensions(DimensionSet.of("Name", "Test"));
282+
logger.setFlushPreserveDimensions(false);
283+
284+
logger.flush();
285+
Assert.assertEquals(sink.getContext().getDimensions().get(0).getDimensionKeys().size(), 4);
286+
expectDimension("Name", "Test");
287+
288+
logger.flush();
289+
Assert.assertEquals(sink.getContext().getDimensions().get(0).getDimensionKeys().size(), 3);
290+
expectDimension("Name", null);
291+
}
292+
232293
@Test
233294
public void testFlushDoesntPreserveMetrics() {
234295
MetricsLogger logger = new MetricsLogger(envProvider);

0 commit comments

Comments
 (0)