Skip to content

Commit

Permalink
allow inline stacktrace generation (#807)
Browse files Browse the repository at this point in the history
merge of #807
  • Loading branch information
brenuart committed May 19, 2022
1 parent f248f22 commit faadf21
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 7 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,11 @@ is included in the logstash-logback-encoder library to format stacktraces by:
* Using evaluators to determine if the stacktrace should be logged.
* Outputting in either 'normal' order (root-cause-last), or root-cause-first.
* Computing and inlining hexadecimal hashes for each exception stack using the `inlineHash` or `stackHash` provider ([more info](stack-hash.md)).
* Using custom line separator for stack traces. The line separator can be specified as:
* `SYSTEM` (uses the system default)
* `UNIX` (uses `\n`)
* `WINDOWS` (uses `\r\n`), or
* any other string.

For example:

Expand All @@ -1766,6 +1771,7 @@ For example:
<evaluator class="myorg.MyCustomEvaluator"/>
<rootCauseFirst>true</rootCauseFirst>
<inlineHash>true</inlineHash>
<lineSeparator>\\n</lineSeparator>
</throwableConverter>
</encoder>
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import net.logstash.logback.CachingAbbreviator;
import net.logstash.logback.NullAbbreviator;
import net.logstash.logback.encoder.SeparatorParser;

import ch.qos.logback.access.PatternLayout;
import ch.qos.logback.classic.pattern.Abbreviator;
Expand Down Expand Up @@ -112,10 +113,15 @@ public class ShortenedThrowableConverter extends ThrowableHandlingConverter {
private static final String OPTION_VALUE_ROOT_FIRST = "rootFirst";
private static final String OPTION_VALUE_INLINE_HASH = "inlineHash";

private static final String OPTION_VALUE_INLINE_STACK = "inline";

private static final int OPTION_INDEX_MAX_DEPTH = 0;
private static final int OPTION_INDEX_SHORTENED_CLASS_NAME = 1;
private static final int OPTION_INDEX_MAX_LENGTH = 2;

/** String sequence to use to delimit lines instead of {@link CoreConstants#LINE_SEPARATOR} when inline is active */
public static final String DEFAULT_INLINE_SEPARATOR = "\\n";

private AtomicInteger errorCount = new AtomicInteger();

/**
Expand Down Expand Up @@ -160,6 +166,9 @@ public class ShortenedThrowableConverter extends ThrowableHandlingConverter {
*/
private boolean inlineHash;

/** line delimiter */
private String lineSeparator = CoreConstants.LINE_SEPARATOR;

private StackElementFilter stackElementFilter;

private StackHasher stackHasher;
Expand Down Expand Up @@ -217,13 +226,16 @@ private void parseOptions() {
* Remaining options are either
* - "rootFirst" - indicating that stacks should be printed root-cause first
* - "inlineHash" - indicating that hexadecimal error hashes should be computed and inlined
* - "inline" - indicating that the whole stack trace should be inlined, using "\\n" as separator
* - evaluator name - name of evaluators that will determine if the stacktrace is ignored
* - exclusion pattern - pattern for stack trace elements to exclude
*/
if (OPTION_VALUE_ROOT_FIRST.equals(option)) {
setRootCauseFirst(true);
} else if (OPTION_VALUE_INLINE_HASH.equals(option)) {
setInlineHash(true);
} else if (OPTION_VALUE_INLINE_STACK.equals(option)) {
setLineSeparator(DEFAULT_INLINE_SEPARATOR);
} else {
@SuppressWarnings("rawtypes")
Map evaluatorMap = (Map) getContext().getObject(CoreConstants.EVALUATOR_MAP);
Expand Down Expand Up @@ -282,12 +294,36 @@ public String convert(ILoggingEvent event) {
appendRootCauseLast(builder, null, ThrowableProxyUtil.REGULAR_EXCEPTION_INDENT, throwableProxy, stackHashes);
}
if (builder.length() > maxLength) {
builder.setLength(maxLength - ELLIPSIS.length() - CoreConstants.LINE_SEPARATOR.length());
builder.append(ELLIPSIS).append(CoreConstants.LINE_SEPARATOR);
builder.setLength(maxLength - ELLIPSIS.length() - getLineSeparator().length());
builder.append(ELLIPSIS).append(getLineSeparator());
}
return builder.toString();
}

public String getLineSeparator() {
return lineSeparator;
}

/**
* Sets which lineSeparator to use between events.
* <p>
*
* The following values have special meaning:
* <ul>
* <li>{@code null} or empty string = no new line.</li>
* <li>"{@code SYSTEM}" = operating system new line (default).</li>
* <li>"{@code UNIX}" = unix line ending ({@code \n}).</li>
* <li>"{@code WINDOWS}" = windows line ending {@code \r\n}).</li>
* </ul>
* <p>
* Any other value will be used as given as the lineSeparator.
*
* @param lineSeparator the line separator
*/
public void setLineSeparator(String lineSeparator) {
this.lineSeparator = SeparatorParser.parseSeparator(lineSeparator);
}

/**
* Return true if any evaluator returns true, indicating that
* the stack trace should not be logged.
Expand Down Expand Up @@ -467,7 +503,7 @@ private void appendPlaceHolder(StringBuilder builder, int indent, int consecutiv
.append(consecutiveExcluded)
.append(" ")
.append(message)
.append(CoreConstants.LINE_SEPARATOR);
.append(getLineSeparator());
}

/**
Expand Down Expand Up @@ -506,7 +542,7 @@ private void appendStackTraceElement(StringBuilder builder, int indent, StackTra
if (shouldAppendPackagingData(step, previousStep)) {
appendPackagingData(builder, step);
}
builder.append(CoreConstants.LINE_SEPARATOR);
builder.append(getLineSeparator());
}

/**
Expand Down Expand Up @@ -547,7 +583,7 @@ private void appendFirstLine(StringBuilder builder, String prefix, int indent, I
builder.append(abbreviator.abbreviate(throwableProxy.getClassName()))
.append(": ")
.append(throwableProxy.getMessage())
.append(CoreConstants.LINE_SEPARATOR);
.append(getLineSeparator());
}

private void indent(StringBuilder builder, int indent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,17 +315,19 @@ public void testOptions() throws EvaluationException {
assertThat(converter.getShortenedClassNameLength()).isEqualTo(ShortenedThrowableConverter.FULL_CLASS_NAME_LENGTH);
assertThat(converter.getMaxLength()).isEqualTo(ShortenedThrowableConverter.FULL_MAX_LENGTH);
assertThat(converter.isRootCauseFirst()).isTrue();
assertThat(converter.getLineSeparator()).isEqualTo(CoreConstants.LINE_SEPARATOR);
assertThat(converter.getEvaluators().get(0)).isEqualTo(evaluator);
assertThat(converter.getExcludes().get(0)).isEqualTo("regex");

// test short values
converter.setOptionList(Arrays.asList("short", "short", "short", "rootFirst", "inlineHash", "evaluator", "regex"));
converter.setOptionList(Arrays.asList("short", "short", "short", "rootFirst", "inlineHash", "inline", "evaluator", "regex"));
converter.start();

assertThat(converter.getMaxDepthPerThrowable()).isEqualTo(ShortenedThrowableConverter.SHORT_MAX_DEPTH_PER_THROWABLE);
assertThat(converter.getShortenedClassNameLength()).isEqualTo(ShortenedThrowableConverter.SHORT_CLASS_NAME_LENGTH);
assertThat(converter.getMaxLength()).isEqualTo(ShortenedThrowableConverter.SHORT_MAX_LENGTH);

assertThat(converter.getLineSeparator()).isEqualTo(ShortenedThrowableConverter.DEFAULT_INLINE_SEPARATOR);

// test numeric values
converter.setOptionList(Arrays.asList("1", "2", "3"));
converter.start();
Expand Down Expand Up @@ -424,6 +426,30 @@ public void test_inline_hash_root_cause_first() {
}
}

@Test
public void test_inline_stack() {
try {
StackTraceElementGenerator.generateCausedBy();
fail("Exception must have been thrown");
} catch (RuntimeException e) {
// GIVEN
StackHasher mockedHasher = Mockito.mock(StackHasher.class);
ShortenedThrowableConverter converter = new ShortenedThrowableConverter();
converter.setLineSeparator(ShortenedThrowableConverter.DEFAULT_INLINE_SEPARATOR);
converter.setRootCauseFirst(true);
converter.start();
converter.setStackHasher(mockedHasher);

// WHEN
String formatted = converter.convert(createEvent(e));

// THEN
// verify we have the expected stack trace line separator inlined
assertThat(formatted).doesNotContain(CoreConstants.LINE_SEPARATOR);
assertThat(formatted).contains(ShortenedThrowableConverter.DEFAULT_INLINE_SEPARATOR);
}
}

@Test
public void test_inline_hash_with_suppressed() {
try {
Expand Down

0 comments on commit faadf21

Please sign in to comment.