Skip to content

Commit 2e97086

Browse files
committed
Skip error.stack_trace if empty
1 parent 584bd10 commit 2e97086

File tree

2 files changed

+71
-25
lines changed

2 files changed

+71
-25
lines changed

ecs-logging-core/src/main/java/co/elastic/logging/EcsJsonSerializer.java

+32-25
Original file line numberDiff line numberDiff line change
@@ -208,22 +208,21 @@ public static void serializeException(StringBuilder builder, Throwable thrown, b
208208
if (thrown != null) {
209209
builder.append("\"error.type\":\"");
210210
JsonUtils.quoteAsString(thrown.getClass().getName(), builder);
211-
builder.append("\",");
211+
builder.append('\"');
212212

213213
String message = thrown.getMessage();
214214
if (message != null) {
215-
builder.append("\"error.message\":\"");
215+
builder.append(",\"error.message\":\"");
216216
JsonUtils.quoteAsString(message, builder);
217-
builder.append("\",");
217+
builder.append('\"');
218218
}
219-
if (stackTraceAsArray) {
220-
builder.append("\"error.stack_trace\":[").append(NEW_LINE);
221-
formatThrowableAsArray(builder, thrown);
222-
builder.append("]");
219+
220+
int prevLength = builder.length();
221+
builder.append(",\"error.stack_trace\":").append(stackTraceAsArray ? '[' : "\"");
222+
if (formatThrowable(builder, thrown, stackTraceAsArray)) {
223+
builder.append(stackTraceAsArray ? ']' : '\"');
223224
} else {
224-
builder.append("\"error.stack_trace\":\"");
225-
JsonUtils.quoteAsString(formatThrowable(thrown), builder);
226-
builder.append("\"");
225+
builder.setLength(prevLength); // reset if no stacktrace was written
227226
}
228227
}
229228
}
@@ -249,30 +248,38 @@ public static void serializeException(StringBuilder builder, String exceptionCla
249248
}
250249
}
251250

252-
private static CharSequence formatThrowable(final Throwable throwable) {
253-
StringBuilder buffer = getMessageStringBuilder();
254-
final PrintWriter pw = new PrintWriter(new StringBuilderWriter(buffer));
255-
throwable.printStackTrace(pw);
256-
pw.flush();
257-
return buffer;
258-
}
259-
260-
private static void formatThrowableAsArray(final StringBuilder jsonBuilder, final Throwable throwable) {
251+
private static boolean formatThrowable(final StringBuilder jsonBuilder, final Throwable throwable, final boolean stackTraceAsArray) {
261252
final StringBuilder buffer = getMessageStringBuilder();
253+
final int initialLength = jsonBuilder.length();
262254
final PrintWriter pw = new PrintWriter(new StringBuilderWriter(buffer), true) {
255+
private int lines = 0;
256+
263257
@Override
264258
public void println() {
265259
flush();
266-
jsonBuilder.append("\t\"");
267-
JsonUtils.quoteAsString(buffer, jsonBuilder);
268-
jsonBuilder.append("\",");
269-
jsonBuilder.append(NEW_LINE);
260+
if (stackTraceAsArray) {
261+
if (lines > 0) jsonBuilder.append(',');
262+
jsonBuilder.append(NEW_LINE).append("\t\"");
263+
JsonUtils.quoteAsString(buffer, jsonBuilder);
264+
jsonBuilder.append('\"');
265+
} else {
266+
JsonUtils.quoteAsString(buffer, jsonBuilder);
267+
JsonUtils.quoteAsString(NEW_LINE, jsonBuilder);
268+
}
270269
buffer.setLength(0);
270+
lines++;
271+
}
272+
273+
@Override
274+
public void close() {
275+
if (lines <= 1) {
276+
jsonBuilder.setLength(initialLength); // skip the first line (message) if no stacktrace follows
277+
}
271278
}
272279
};
273280
throwable.printStackTrace(pw);
274-
removeIfEndsWith(jsonBuilder, NEW_LINE);
275-
removeIfEndsWith(jsonBuilder, ",");
281+
pw.close();
282+
return jsonBuilder.length() > initialLength;
276283
}
277284

278285
private static void formatStackTraceAsArray(StringBuilder builder, CharSequence stackTrace) {

ecs-logging-core/src/test/java/co/elastic/logging/EcsJsonSerializerTest.java

+39
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@ void serializeExceptionAsString() throws IOException {
6161
assertThat(jsonNode.get(ERROR_STACK_TRACE).textValue()).isEqualTo(stringWriter.toString());
6262
}
6363

64+
@Test
65+
void serializeExceptionWithoutStacktraceAsString() throws IOException {
66+
Exception exception = new Exception("no stacktrace"){
67+
@Override
68+
public synchronized Throwable fillInStackTrace() {
69+
return this;
70+
}
71+
};
72+
StringBuilder jsonBuilder = new StringBuilder();
73+
jsonBuilder.append('{');
74+
EcsJsonSerializer.serializeException(jsonBuilder, exception, false);
75+
jsonBuilder.append('}');
76+
JsonNode jsonNode = objectMapper.readTree(jsonBuilder.toString());
77+
78+
assertThat(jsonNode.get(ERROR_TYPE).textValue()).isEqualTo(exception.getClass().getName());
79+
assertThat(jsonNode.get(ERROR_MESSAGE).textValue()).isEqualTo("no stacktrace");
80+
assertThat(jsonNode.get(ERROR_STACK_TRACE)).isNull();
81+
}
82+
6483
@Test
6584
void testEscaping() throws IOException {
6685
String loggerName = "logger\"";
@@ -125,6 +144,26 @@ void serializeExceptionAsArray() throws IOException {
125144
.isEqualTo(stringWriter.toString());
126145
}
127146

147+
@Test
148+
void serializeExceptionWithoutStacktraceAsArray() throws IOException {
149+
Exception exception = new Exception("no stacktrace"){
150+
@Override
151+
public synchronized Throwable fillInStackTrace() {
152+
return this;
153+
}
154+
};
155+
StringBuilder jsonBuilder = new StringBuilder();
156+
jsonBuilder.append('{');
157+
EcsJsonSerializer.serializeException(jsonBuilder, exception, true);
158+
jsonBuilder.append('}');
159+
System.out.println(jsonBuilder);
160+
JsonNode jsonNode = objectMapper.readTree(jsonBuilder.toString());
161+
162+
assertThat(jsonNode.get(ERROR_TYPE).textValue()).isEqualTo(exception.getClass().getName());
163+
assertThat(jsonNode.get(ERROR_MESSAGE).textValue()).isEqualTo("no stacktrace");
164+
assertThat(jsonNode.get(ERROR_STACK_TRACE)).isNull();
165+
}
166+
128167
@Test
129168
void testRemoveIfEndsWith() {
130169
assertRemoveIfEndsWith("", "foo", "");

0 commit comments

Comments
 (0)