Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ MDC data will be added to log events with a `context.` prefix to distinguish it
collisions with New Relic specific context keys.

### Exception Stack Trace Size
**Note:** The log extensions now have the ability to capture the entire stack trace - specifically any `caused by` sections.
Prior versions of the extension only reported the trace for the thrown exception and ignored any nested `caused by` `Throwables`.

You can configure the logging extension to control the max stack trace size for exceptions added to log events.

Default max stack trace size is `300`. It is recommended that you do not exceed this value or data could be dropped or truncated as well as
lead to higher log event ingest costs. Max stack trace size can be configured by environment variable (`NEW_RELIC_LOG_EXTENSION_MAX_STACK_SIZE=integer`)
or system property (`-Dnewrelic.log_extension.max_stack_size=integer`).

Explicitly setting this property to `0` will not impose a maximum size constraint on the stack trace size.

## Support

Should you need assistance with New Relic products, you are in good hands with several diagnostic tools and support channels.
Expand Down
1 change: 1 addition & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ configure<JavaPluginConvention> {
}

dependencies {
implementation("org.apache.commons:commons-lang3:3.13.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
// Allows for easy testing of values based on Environment Variables and System Properties
testImplementation("com.github.stefanbirkner:system-lambda:1.2.1")
Expand Down
36 changes: 23 additions & 13 deletions core/src/main/java/com/newrelic/logging/core/ExceptionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,42 @@

package com.newrelic.logging.core;

import org.apache.commons.lang3.exception.ExceptionUtils;

import java.util.Arrays;

import static com.newrelic.logging.core.LogExtensionConfig.getMaxStackSize;

public class ExceptionUtil {
public static final int MAX_STACK_SIZE_DEFAULT = 300;
public static String getErrorStack(Throwable throwable) {

public static String getFullStackTrace(Throwable throwable) {
if (throwable == null) {
return null;
}

StackTraceElement[] stack = throwable.getStackTrace();
return getErrorStack(stack);
}

public static String getErrorStack(StackTraceElement[] stack) {
return getErrorStack(stack, getMaxStackSize());
return getStackTraceStringFromFramesArray(ExceptionUtils.getStackFrames(throwable));
}

public static String getErrorStack(StackTraceElement[] stack, Integer maxStackSize) {
if (stack == null || stack.length == 0) {
public static String transformLogbackStackTraceString(String trace) {
if (trace == null || trace.length() == 0) {
return null;
}

StringBuilder stackBuilder = new StringBuilder();
for(int i = 0; i < Math.min(maxStackSize, stack.length); i++) {
stackBuilder.append(" at ").append(stack[i].toString()).append("\n");
return getStackTraceStringFromFramesArray(trace.split("\n"));
}

private static String getStackTraceStringFromFramesArray(String[] frames) {
int maxStackSize = getMaxStackSize();

//We need to truncate the stacktrace based on the desired max stacktrace size, as well as remove the first line
//of the returned trace (the "message"), since this is already captured in the error.message attribute.
if (frames.length > maxStackSize) {
frames = Arrays.copyOfRange(frames, 1, maxStackSize + 1);
} else {
frames = Arrays.copyOfRange(frames, 1, frames.length);
}
return stackBuilder.toString();

return String.join("\n", frames).replace("\tat", " at") + "\n";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public class LogExtensionConfig {
public static final boolean ADD_MDC_DEFAULT = false;

/**
* Get an int representing the max stack size for errors that should be added to logs
* Get an int representing the max stack size for errors that should be added to logs. Explicitly setting the
* value to 0 will not impose a maximum size constraint on the stack trace size.
* <p>
* Precedence: Env var > Sys prop > Default
*
Expand All @@ -25,14 +26,17 @@ public class LogExtensionConfig {
public static int getMaxStackSize() {
String envVar = System.getenv(MAX_STACK_SIZE_ENV_VAR);
String sysProp = System.getProperty(MAX_STACK_SIZE_SYS_PROP);
int parsedValue;

if (isInteger(envVar)) {
return Integer.parseInt(envVar);
parsedValue = Integer.parseInt(envVar);
} else if (isInteger(sysProp)) {
return Integer.parseInt(sysProp);
parsedValue = Integer.parseInt(sysProp);
} else {
return ExceptionUtil.MAX_STACK_SIZE_DEFAULT;
parsedValue = ExceptionUtil.MAX_STACK_SIZE_DEFAULT;
}

return (parsedValue == 0 ? Integer.MAX_VALUE : parsedValue);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@

class LogExtensionConfigTest {

@Test
void getMaxStackSize_withValueOfZeroAndSetAsSysProp_returnsMaxInt() {
System.setProperty(MAX_STACK_SIZE_SYS_PROP, String.valueOf(0));
assertEquals(Integer.MAX_VALUE, LogExtensionConfig.getMaxStackSize());
System.clearProperty(MAX_STACK_SIZE_SYS_PROP);
}

@Test
void getMaxStackSize_withValueOfZeroAndSetAsEnvVar_returnsMaxInt() throws Exception {
assertEquals(Integer.MAX_VALUE, withEnvironmentVariable(MAX_STACK_SIZE_ENV_VAR, String.valueOf(0)).execute(LogExtensionConfig::getMaxStackSize));
}

@Test
void testGetMaxStackSizeDefault() {
int actualSize = LogExtensionConfig.getMaxStackSize();
Expand Down
Loading