Skip to content

Commit 9d111b3

Browse files
authored
fix(logging): Escape double-quotes when serializing strings into JSON. (#1845)
1 parent 3281f06 commit 9d111b3

File tree

2 files changed

+23
-22
lines changed

2 files changed

+23
-22
lines changed

powertools-logging/powertools-logging-logback/src/test/java/software/amazon/lambda/powertools/logging/internal/LambdaJsonEncoderTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ void shouldLogArgumentsAsJsonWhenUsingRawJson() {
127127
assertThat(contentOf(logFile))
128128
.contains("\"input\":{\"awsRegion\":\"eu-west-1\",\"body\":\"plop\",\"eventSource\":\"eb\",\"messageAttributes\":{\"keyAttribute\":{\"stringListValues\":[\"val1\",\"val2\",\"val3\"]}},\"messageId\":\"1212abcd\"}")
129129
.contains("\"message\":\"1212abcd\"")
130-
.contains("\"message\":\"Message body = plop and id = \"1212abcd\"\"");
130+
// Should auto-escape double quotes around id
131+
.contains("\"message\":\"Message body = plop and id = \\\"1212abcd\\\"\"");
131132
// Reserved keys should be ignored
132133
PowertoolsLoggedFields.stringValues().stream().forEach(reservedKey -> {
133134
assertThat(contentOf(logFile)).doesNotContain("\"" + reservedKey + "\":\"shouldBeIgnored\"");
@@ -158,7 +159,8 @@ void shouldLogArgumentsAsJsonWhenUsingKeyValue() {
158159
assertThat(contentOf(logFile))
159160
.contains("\"input\":{\"awsRegion\":\"eu-west-1\",\"body\":\"plop\",\"eventSource\":\"eb\",\"messageAttributes\":{\"keyAttribute\":{\"stringListValues\":[\"val1\",\"val2\",\"val3\"]}},\"messageId\":\"1212abcd\"}")
160161
.contains("\"message\":\"1212abcd\"")
161-
.contains("\"message\":\"Message body = plop and id = \"1212abcd\"\"");
162+
// Should auto-escape double quotes around id
163+
.contains("\"message\":\"Message body = plop and id = \\\"1212abcd\\\"\"");
162164
// Reserved keys should be ignored
163165
PowertoolsLoggedFields.stringValues().stream().forEach(reservedKey -> {
164166
assertThat(contentOf(logFile)).doesNotContain("\"" + reservedKey + "\":\"shouldBeIgnored\"");
@@ -295,7 +297,8 @@ void shouldLogEventAsStringForStreamHandler() throws IOException {
295297
File logFile = new File("target/logfile.json");
296298
assertThat(contentOf(logFile))
297299
.contains("\"message\":\"Handler Event\"")
298-
.contains("\"event\":\"{\"key\":\"value\"}\""); // logged as String for StreamHandler
300+
// logged as String for StreamHandler (should auto-escape double-quotes to avoid breaking JSON format)
301+
.contains("\"event\":\"{\\\"key\\\":\\\"value\\\"}\"");
299302
}
300303

301304
@Test

powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/JsonSerializer.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public JsonSerializer(StringBuilder builder) {
5353
}
5454
this.builder = builder;
5555
}
56-
56+
5757
public void writeStartArray() {
5858
builder.append('[');
5959
}
@@ -84,7 +84,8 @@ public void writeString(String text) {
8484
if (text == null) {
8585
writeNull();
8686
} else {
87-
builder.append("\"").append(text).append("\"");
87+
// Escape double quotes to avoid breaking JSON format
88+
builder.append("\"").append(text.replace("\"", "\\\"")).append("\"");
8889
}
8990
}
9091

@@ -314,7 +315,7 @@ public void writeMap(final Map<?, ?> map) {
314315
writeNull();
315316
} else {
316317
writeStartObject();
317-
for (Iterator<? extends Map.Entry<?, ?>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
318+
for (Iterator<? extends Map.Entry<?, ?>> entries = map.entrySet().iterator(); entries.hasNext();) {
318319
Map.Entry<?, ?> entry = entries.next();
319320
writeObjectField(String.valueOf(entry.getKey()), entry.getValue());
320321
if (entries.hasNext()) {
@@ -326,16 +327,16 @@ public void writeMap(final Map<?, ?> map) {
326327
}
327328

328329
public void writeObject(Object value) {
329-
330+
330331
// null
331332
if (value == null) {
332333
writeNull();
333-
}
334-
334+
}
335+
335336
else if (value instanceof String) {
336337
writeString((String) value);
337-
}
338-
338+
}
339+
339340
// number & boolean
340341
else if (value instanceof Number) {
341342
Number n = (Number) value;
@@ -364,24 +365,23 @@ else if (value instanceof Number) {
364365
writeBoolean((Boolean) value);
365366
} else if (value instanceof AtomicBoolean) {
366367
writeBoolean(((AtomicBoolean) value).get());
367-
}
368-
368+
}
369+
369370
// list & collection
370371
else if (value instanceof List) {
371372
final List<?> list = (List<?>) value;
372373
writeArray(list);
373374
} else if (value instanceof Collection) {
374375
final Collection<?> collection = (Collection<?>) value;
375376
writeArray(collection);
376-
}
377-
377+
}
378+
378379
// map
379380
else if (value instanceof Map) {
380381
final Map<?, ?> map = (Map<?, ?>) value;
381382
writeMap(map);
382383
}
383384

384-
385385
// arrays
386386
else if (value instanceof char[]) {
387387
final char[] charValues = (char[]) value;
@@ -411,7 +411,7 @@ else if (value instanceof char[]) {
411411
final Object[] values = (Object[]) value;
412412
writeArray(values);
413413
}
414-
414+
415415
else if (value instanceof JsonNode) {
416416
JsonNode node = (JsonNode) value;
417417

@@ -462,7 +462,7 @@ else if (value instanceof JsonNode) {
462462
case OBJECT:
463463
case POJO:
464464
writeStartObject();
465-
for (Iterator<Map.Entry<String, JsonNode>> entries = node.fields(); entries.hasNext(); ) {
465+
for (Iterator<Map.Entry<String, JsonNode>> entries = node.fields(); entries.hasNext();) {
466466
Map.Entry<String, JsonNode> entry = entries.next();
467467
writeObjectField(entry.getKey(), entry.getValue());
468468
if (entries.hasNext()) {
@@ -475,7 +475,7 @@ else if (value instanceof JsonNode) {
475475
case ARRAY:
476476
ArrayNode arrayNode = (ArrayNode) node;
477477
writeStartArray();
478-
for (Iterator<JsonNode> elements = arrayNode.elements(); elements.hasNext(); ) {
478+
for (Iterator<JsonNode> elements = arrayNode.elements(); elements.hasNext();) {
479479
writeObject(elements.next());
480480
if (elements.hasNext()) {
481481
builder.append(',');
@@ -558,7 +558,7 @@ public void writeTree(TreeNode rootNode) {
558558
writeNull();
559559
} else if (rootNode instanceof TextNode) {
560560
writeString(((TextNode) rootNode).asText());
561-
} else if (rootNode instanceof BooleanNode) {
561+
} else if (rootNode instanceof BooleanNode) {
562562
writeBoolean(((BooleanNode) rootNode).asBoolean());
563563
} else if (rootNode instanceof NumericNode) {
564564
NumericNode numericNode = (NumericNode) rootNode;
@@ -595,5 +595,3 @@ public void close() {
595595
// nothing to do
596596
}
597597
}
598-
599-

0 commit comments

Comments
 (0)