Skip to content

Commit ab1f24a

Browse files
authored
Merge pull request #79 from kalnitsk/support-setting-timestamp
Support setting timestamp
2 parents d45167c + 6db27d7 commit ab1f24a

File tree

5 files changed

+85
-9
lines changed

5 files changed

+85
-9
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ Examples:
158158
setNamespace("MyApplication")
159159
```
160160

161+
- MetricsLogger **setTimestamp**(Instant timestamp)
162+
163+
Sets the timestamp of the metrics. If not set, current time of the client will be used.
164+
165+
Examples:
166+
167+
```java
168+
setTimestamp(Instant.now())
169+
```
170+
161171
- **flush**()
162172

163173
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.

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package software.amazon.cloudwatchlogs.emf.logger;
1818

19+
import java.time.Instant;
1920
import java.util.concurrent.CompletableFuture;
2021
import lombok.extern.slf4j.Slf4j;
2122
import software.amazon.cloudwatchlogs.emf.environment.Environment;
@@ -165,6 +166,17 @@ public MetricsLogger setNamespace(String namespace) {
165166
return this;
166167
}
167168

169+
/**
170+
* Set the timestamp to be used for metrics.
171+
*
172+
* @param timestamp value of timestamp to be set
173+
* @return the current logger
174+
*/
175+
public MetricsLogger setTimestamp(Instant timestamp) {
176+
this.context.setTimestamp(timestamp);
177+
return this;
178+
}
179+
168180
private void configureContextForEnvironment(MetricsContext context, Environment environment) {
169181
if (context.hasDefaultDimensions()) {
170182
return;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package software.amazon.cloudwatchlogs.emf.model;
1818

1919
import com.fasterxml.jackson.core.JsonProcessingException;
20+
import java.time.Instant;
2021
import java.util.*;
2122
import lombok.Getter;
2223
import software.amazon.cloudwatchlogs.emf.Constants;
@@ -195,6 +196,20 @@ public void putMetadata(String key, Object value) {
195196
rootNode.getAws().putCustomMetadata(key, value);
196197
}
197198

199+
/** @return timestamp field from the metadata. */
200+
public Instant getTimestamp() {
201+
return rootNode.getAws().getTimestamp();
202+
}
203+
204+
/**
205+
* Update timestamp field in the metadata
206+
*
207+
* @param timestamp value of timestamp to be set
208+
*/
209+
public void setTimestamp(Instant timestamp) {
210+
rootNode.getAws().setTimestamp(timestamp);
211+
}
212+
198213
/** @return Creates an independently flushable context. */
199214
public MetricsContext createCopyWithContext() {
200215
return new MetricsContext(metricDirective.copyWithoutMetrics());

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.junit.Assert.assertTrue;
2222
import static org.mockito.Mockito.*;
2323

24+
import java.time.Instant;
2425
import java.util.List;
2526
import java.util.concurrent.CompletableFuture;
2627
import org.junit.Assert;
@@ -118,6 +119,21 @@ public void testSetNamespace() {
118119
Assert.assertEquals(sink.getContext().getNamespace(), namespace);
119120
}
120121

122+
@Test
123+
public void testFlushWithDefaultTimestamp() {
124+
logger.flush();
125+
Assert.assertNotNull(sink.getContext().getTimestamp());
126+
}
127+
128+
@Test
129+
public void testSetTimestamp() {
130+
Instant now = Instant.now();
131+
logger.setTimestamp(now);
132+
logger.flush();
133+
134+
Assert.assertEquals(sink.getContext().getTimestamp(), now);
135+
}
136+
121137
@Test
122138
public void testFlushWithConfiguredServiceName() {
123139
String serviceName = "TestServiceName";

src/test/java/software/amazon/cloudwatchlogs/emf/model/MetricsContextTest.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.fasterxml.jackson.core.JsonProcessingException;
2424
import com.fasterxml.jackson.core.type.TypeReference;
2525
import com.fasterxml.jackson.databind.json.JsonMapper;
26+
import java.time.Instant;
2627
import java.util.ArrayList;
2728
import java.util.Arrays;
2829
import java.util.List;
@@ -140,19 +141,37 @@ public void testSerializeZeroMetric() throws JsonProcessingException {
140141
int expectedEventCount = 1;
141142
assertEquals(expectedEventCount, events.size());
142143

143-
JsonMapper objectMapper = new JsonMapper();
144-
Map<String, Object> metadata_map =
145-
objectMapper.readValue(events.get(0), new TypeReference<Map<String, Object>>() {});
144+
Map<String, Object> rootNode = parseRootNode(events.get(0));
146145
// If there's no metric added, the _aws would be filtered out from the log event
147-
assertFalse(metadata_map.containsKey("_aws"));
146+
assertFalse(rootNode.containsKey("_aws"));
147+
}
148+
149+
@Test
150+
@SuppressWarnings("unchecked")
151+
public void testSetTimestamp() throws JsonProcessingException {
152+
MetricsContext mc = new MetricsContext();
153+
mc.putMetric("Metric", 0);
154+
155+
Instant now = Instant.now();
156+
mc.setTimestamp(now);
157+
158+
List<String> events = mc.serialize();
159+
160+
int expectedEventCount = 1;
161+
assertEquals(expectedEventCount, events.size());
162+
Map<String, Object> rootNode = parseRootNode(events.get(0));
163+
164+
assertTrue(rootNode.containsKey("_aws"));
165+
Map<String, Object> metadata = (Map<String, Object>) rootNode.get("_aws");
166+
167+
assertTrue(metadata.containsKey("Timestamp"));
168+
assertEquals(metadata.get("Timestamp"), now.toEpochMilli());
148169
}
149170

150171
@SuppressWarnings("unchecked")
151172
private ArrayList<MetricDefinition> parseMetrics(String event) throws JsonProcessingException {
152-
JsonMapper objectMapper = new JsonMapper();
153-
Map<String, Object> metadata_map =
154-
objectMapper.readValue(event, new TypeReference<Map<String, Object>>() {});
155-
Map<String, Object> metadata = (Map<String, Object>) metadata_map.get("_aws");
173+
Map<String, Object> rootNode = parseRootNode(event);
174+
Map<String, Object> metadata = (Map<String, Object>) rootNode.get("_aws");
156175
ArrayList<Map<String, Object>> metricDirectives =
157176
(ArrayList<Map<String, Object>>) metadata.get("CloudWatchMetrics");
158177
ArrayList<Map<String, String>> metrics =
@@ -162,7 +181,7 @@ private ArrayList<MetricDefinition> parseMetrics(String event) throws JsonProces
162181
for (Map<String, String> metric : metrics) {
163182
String name = metric.get("Name");
164183
Unit unit = Unit.fromValue(metric.get("Unit"));
165-
Object value = metadata_map.get(name);
184+
Object value = rootNode.get(name);
166185
if (value instanceof ArrayList) {
167186
metricDefinitions.add(new MetricDefinition(name, unit, (ArrayList) value));
168187
} else {
@@ -171,4 +190,8 @@ private ArrayList<MetricDefinition> parseMetrics(String event) throws JsonProces
171190
}
172191
return metricDefinitions;
173192
}
193+
194+
private Map<String, Object> parseRootNode(String event) throws JsonProcessingException {
195+
return new JsonMapper().readValue(event, new TypeReference<Map<String, Object>>() {});
196+
}
174197
}

0 commit comments

Comments
 (0)