Skip to content

Commit 560720e

Browse files
authored
Merge pull request #1 from Stephen-Bao/stephen-review
Code changes and unit tests for thread-safety
2 parents bbd2097 + a0f0fae commit 560720e

File tree

11 files changed

+665
-28
lines changed

11 files changed

+665
-28
lines changed

build.gradle

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ plugins {
1818
id 'com.diffplug.spotless' version '5.8.2'
1919
id 'maven-publish'
2020
id 'signing'
21+
id "me.champeau.jmh" version "0.6.6"
2122
}
2223

2324
group "software.amazon.cloudwatchlogs"
@@ -78,6 +79,10 @@ dependencies {
7879
testImplementation 'software.amazon.awssdk:cloudwatch:2.13.54'
7980
testCompileOnly 'org.projectlombok:lombok:1.18.12'
8081
testAnnotationProcessor 'org.projectlombok:lombok:1.18.12'
82+
83+
implementation 'org.openjdk.jmh:jmh-core:1.29'
84+
implementation 'org.openjdk.jmh:jmh-generator-annprocess:1.29'
85+
jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.29'
8186
}
8287

8388
spotless {
@@ -124,7 +129,7 @@ tasks.withType(JavaCompile) {
124129
}
125130

126131
tasks.named('wrapper') {
127-
gradleVersion = '6.5.1'
132+
gradleVersion = '7.4.2'
128133
distributionType = Wrapper.DistributionType.ALL
129134
}
130135

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

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

+48-15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.time.Instant;
2020
import java.util.concurrent.CompletableFuture;
21+
import java.util.concurrent.locks.ReentrantReadWriteLock;
2122
import lombok.extern.slf4j.Slf4j;
2223
import software.amazon.cloudwatchlogs.emf.environment.Environment;
2324
import software.amazon.cloudwatchlogs.emf.environment.EnvironmentProvider;
@@ -35,6 +36,7 @@ public class MetricsLogger {
3536
private MetricsContext context;
3637
private CompletableFuture<Environment> environmentFuture;
3738
private EnvironmentProvider environmentProvider;
39+
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
3840

3941
public MetricsLogger() {
4042
this(new EnvironmentProvider());
@@ -67,10 +69,16 @@ public void flush() {
6769
log.info("Failed to resolve environment. Fallback to default environment: ", ex);
6870
environment = environmentProvider.getDefaultEnvironment();
6971
}
70-
ISink sink = environment.getSink();
71-
configureContextForEnvironment(context, environment);
72-
sink.accept(context);
73-
context = context.createCopyWithContext();
72+
73+
rwl.writeLock().lock();
74+
try {
75+
ISink sink = environment.getSink();
76+
configureContextForEnvironment(context, environment);
77+
sink.accept(context);
78+
context = context.createCopyWithContext();
79+
} finally {
80+
rwl.writeLock().unlock();
81+
}
7482
}
7583

7684
/**
@@ -83,8 +91,13 @@ public void flush() {
8391
* @return the current logger
8492
*/
8593
public MetricsLogger putProperty(String key, Object value) {
86-
this.context.putProperty(key, value);
87-
return this;
94+
rwl.readLock().lock();
95+
try {
96+
this.context.putProperty(key, value);
97+
return this;
98+
} finally {
99+
rwl.readLock().unlock();
100+
}
88101
}
89102

90103
/**
@@ -99,8 +112,13 @@ public MetricsLogger putProperty(String key, Object value) {
99112
* @return the current logger
100113
*/
101114
public MetricsLogger putDimensions(DimensionSet dimensions) {
102-
context.putDimension(dimensions);
103-
return this;
115+
rwl.readLock().lock();
116+
try {
117+
context.putDimension(dimensions);
118+
return this;
119+
} finally {
120+
rwl.readLock().unlock();
121+
}
104122
}
105123

106124
/**
@@ -113,8 +131,13 @@ public MetricsLogger putDimensions(DimensionSet dimensions) {
113131
* @return the current logger
114132
*/
115133
public MetricsLogger setDimensions(DimensionSet... dimensionSets) {
116-
context.setDimensions(dimensionSets);
117-
return this;
134+
rwl.readLock().lock();
135+
try {
136+
context.setDimensions(dimensionSets);
137+
return this;
138+
} finally {
139+
rwl.readLock().unlock();
140+
}
118141
}
119142

120143
/**
@@ -128,8 +151,13 @@ public MetricsLogger setDimensions(DimensionSet... dimensionSets) {
128151
* @return the current logger
129152
*/
130153
public MetricsLogger putMetric(String key, double value, Unit unit) {
131-
this.context.putMetric(key, value, unit);
132-
return this;
154+
rwl.readLock().lock();
155+
try {
156+
this.context.putMetric(key, value, unit);
157+
return this;
158+
} finally {
159+
rwl.readLock().unlock();
160+
}
133161
}
134162

135163
/**
@@ -142,7 +170,7 @@ public MetricsLogger putMetric(String key, double value, Unit unit) {
142170
* @return the current logger
143171
*/
144172
public MetricsLogger putMetric(String key, double value) {
145-
this.context.putMetric(key, value, Unit.NONE);
173+
this.putMetric(key, value, Unit.NONE);
146174
return this;
147175
}
148176

@@ -157,8 +185,13 @@ public MetricsLogger putMetric(String key, double value) {
157185
* @return the current logger
158186
*/
159187
public MetricsLogger putMetadata(String key, Object value) {
160-
this.context.putMetadata(key, value);
161-
return this;
188+
rwl.readLock().lock();
189+
try {
190+
this.context.putMetadata(key, value);
191+
return this;
192+
} finally {
193+
rwl.readLock().unlock();
194+
}
162195
}
163196

164197
/**

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
2424
import java.time.Instant;
2525
import java.util.ArrayList;
26-
import java.util.HashMap;
2726
import java.util.List;
2827
import java.util.Map;
28+
import java.util.concurrent.ConcurrentHashMap;
2929
import lombok.AllArgsConstructor;
3030
import lombok.Getter;
3131
import lombok.Setter;
@@ -56,7 +56,7 @@ class Metadata {
5656
Metadata() {
5757
cloudWatchMetrics = new ArrayList<>();
5858
timestamp = Instant.now();
59-
customFields = new HashMap<>();
59+
customFields = new ConcurrentHashMap<>();
6060
}
6161

6262
/**

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

+13-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.fasterxml.jackson.annotation.JsonIgnore;
2020
import com.fasterxml.jackson.annotation.JsonProperty;
2121
import java.util.*;
22+
import java.util.concurrent.ConcurrentHashMap;
2223
import java.util.stream.Collectors;
2324
import lombok.*;
2425

@@ -45,8 +46,8 @@ class MetricDirective {
4546

4647
MetricDirective() {
4748
namespace = "aws-embedded-metrics";
48-
metrics = new HashMap<>();
49-
dimensions = new ArrayList<>();
49+
metrics = new ConcurrentHashMap<>();
50+
dimensions = Collections.synchronizedList(new ArrayList<>());
5051
defaultDimensions = new DimensionSet();
5152
shouldUseDefaultDimension = true;
5253
}
@@ -60,11 +61,15 @@ void putMetric(String key, double value) {
6061
}
6162

6263
void putMetric(String key, double value, Unit unit) {
63-
if (metrics.containsKey(key)) {
64-
metrics.get(key).addValue(value);
65-
} else {
66-
metrics.put(key, new MetricDefinition(key, unit, value));
67-
}
64+
metrics.compute(
65+
key,
66+
(k, v) -> {
67+
if (v == null) return new MetricDefinition(key, unit, value);
68+
else {
69+
v.addValue(value);
70+
return v;
71+
}
72+
});
6873
}
6974

7075
@JsonProperty("Metrics")
@@ -86,7 +91,7 @@ List<Set<String>> getAllDimensionKeys() {
8691
*/
8792
void setDimensions(List<DimensionSet> dimensionSets) {
8893
shouldUseDefaultDimension = false;
89-
dimensions = new ArrayList<>(dimensionSets);
94+
dimensions = Collections.synchronizedList(new ArrayList<>(dimensionSets));
9095
}
9196

9297
/**

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.HashMap;
2626
import java.util.List;
2727
import java.util.Map;
28+
import java.util.concurrent.ConcurrentHashMap;
2829
import lombok.AllArgsConstructor;
2930
import lombok.Getter;
3031
import lombok.With;
@@ -45,7 +46,7 @@ class RootNode {
4546

4647
RootNode() {
4748
aws = new Metadata();
48-
properties = new HashMap<>();
49+
properties = new ConcurrentHashMap<>();
4950
objectMapper.setFilterProvider(filterProvider);
5051
}
5152

0 commit comments

Comments
 (0)