Skip to content

Commit

Permalink
- Kan nå konfigurere eller slå av lengde før stack trace trunkeres. D…
Browse files Browse the repository at this point in the history
…efault til 480 hvis ikke satt (som før, men legger nå på " (truncated)..." i tillegg).

- Kan nå legge til causes på stack trace. Default til false hvis ikke satt (som før).
- Kan nå filtrere på elementer i stack trace. Default til alle hvis ikke satt (som før).
  • Loading branch information
rfc3092 committed Oct 25, 2024
1 parent b13a30f commit da527bf
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,112 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import com.fasterxml.jackson.core.JsonFactory;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.logstash.logback.encoder.LogstashEncoder;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.regex.Pattern;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

import static org.springframework.util.StringUtils.truncate;

/**
* Config:
* <ul>
* <li>{@code maxStackTraceLength}: Default 480, set to <1 to disable truncation of stack trace altogether.</li>
* <li>{@code addCauses}: If enabled, adds the cause(s) to the stack trace (with stack traces for each cause) Truncated according to above, filtered according to below.</li>
* <li>{@code stackTraceIncludePrefix}: If set, only include stack trace elements that starts with the given prefix, e.g. "no.nav.testnav".</li>
* </ul>
* Copy of {@code no.nav.testnav.libs.servletcore.logging.TestnavLogbackEncoder}.
* @see StringUtils#truncate(CharSequence, int)
*/
@Slf4j
@SuppressWarnings("java:S110")
public class TestnavLogbackEncoder extends LogstashEncoder {

// matches exactly 11 digits (\\d{11}) that are not immediately preceded ((?<!\\d)) or followed ((?!\\d)) by another digit.
private final Pattern pattern = Pattern.compile("(?<!\\d)\\d{11}(?!\\d)");

@Setter
private int maxStackTraceLength = 480;

@Setter
private boolean addCauses = false;

@Setter
private String stackTraceIncludePrefix = null;

@SneakyThrows
@Override
public byte[] encode(ILoggingEvent event) {
var outputStream = new ByteArrayOutputStream();

var generator = new JsonFactory().createGenerator(outputStream);

generator.writeStartObject();
var outputStream = new ByteArrayOutputStream();
try (var generator = new JsonFactory().createGenerator(outputStream)) {

generator.writeStartObject();
generator.writeStringField("@timestamp", new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX")
.format(new java.util.Date(event.getTimeStamp())));
generator.writeStringField("message", formatMessage(event.getFormattedMessage()));
generator.writeStringField("logger_name", event.getLoggerName());
generator.writeStringField("thread_name", event.getThreadName());
generator.writeStringField("level", event.getLevel().toString());
generator.writeStringField("stack_trace", getStackTrace(event));
generator.writeEndObject();

generator.flush();
outputStream.write('\n');
}

generator.writeStringField("@timestamp", new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX")
.format(new java.util.Date(event.getTimeStamp())));
generator.writeStringField("message", formatMessage(event.getFormattedMessage()));
generator.writeStringField("logger_name", event.getLoggerName());
generator.writeStringField("thread_name", event.getThreadName());
generator.writeStringField("level", event.getLevel().toString());
return outputStream.toByteArray();
}

private String getStackTrace(ILoggingEvent event) {
if (nonNull(event.getThrowableProxy())) {
var exception = (ThrowableProxy) event.getThrowableProxy();
if (nonNull(exception.getThrowable())) {
var sw = new StringWriter();
var pw = new PrintWriter(sw);
for (StackTraceElement element : exception.getThrowable().getStackTrace()) {
pw.println("\tat " + element);
}
var stackTrace = sw.toString().substring(0, 480); //Limit the stack trace to 480 characters
generator.writeStringField("stack_trace", stackTrace);
var writer = new StringWriter();
appendStackTraceElements(exception.getThrowable().getStackTrace(), writer);
appendStackTraceCauses(exception, writer);
return maxStackTraceLength > 0 ?
truncate(writer.toString(), maxStackTraceLength) :
writer.toString();
}
}
return null;
}

generator.writeEndObject();

generator.flush();
outputStream.write('\n');
private void appendStackTraceElements(StackTraceElement[] elements, StringWriter writer) {
for (StackTraceElement element : elements) {
if (isNull(stackTraceIncludePrefix) || stackTraceIncludePrefix.isEmpty() || element.toString().startsWith(stackTraceIncludePrefix)) {
writer
.append("\tat ")
.append(element.toString())
.append("\n");
}
}
}

return outputStream.toByteArray();
private void appendStackTraceCauses(ThrowableProxy exception, StringWriter writer) {
if (addCauses) {
var cause = exception;
while (!isNull(cause.getCause())) {
cause = (ThrowableProxy) cause.getCause();
writer
.append("caused by ")
.append(cause.getClassName())
.append(": ")
.append(cause.getMessage())
.append("\n");
if (!isNull(cause.getThrowable())) {
appendStackTraceElements(cause.getThrowable().getStackTrace(), writer);
}
}
}
}

private String formatMessage(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,112 @@
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import com.fasterxml.jackson.core.JsonFactory;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.logstash.logback.encoder.LogstashEncoder;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.regex.Pattern;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

import static org.springframework.util.StringUtils.truncate;

/**
* Config:
* <ul>
* <li>{@code maxStackTraceLength}: Default 480, set to <1 to disable truncation of stack trace altogether.</li>
* <li>{@code addCauses}: If enabled, adds the cause(s) to the stack trace (with stack traces for each cause) Truncated according to above, filtered according to below.</li>
* <li>{@code stackTraceIncludePrefix}: If set, only include stack trace elements that starts with the given prefix, e.g. "no.nav.testnav".</li>
* </ul>
* Copy of {@code no.nav.testnav.libs.servletcore.logging.TestnavLogbackEncoder}.
* @see StringUtils#truncate(CharSequence, int)
*/
@Slf4j
@SuppressWarnings("java:S110")
public class TestnavLogbackEncoder extends LogstashEncoder {

// matches exactly 11 digits (\\d{11}) that are not immediately preceded ((?<!\\d)) or followed ((?!\\d)) by another digit.
private final Pattern pattern = Pattern.compile("(?<!\\d)\\d{11}(?!\\d)");

@Setter
private int maxStackTraceLength = 480;

@Setter
private boolean addCauses = false;

@Setter
private String stackTraceIncludePrefix = null;

@SneakyThrows
@Override
public byte[] encode(ILoggingEvent event) {
var outputStream = new ByteArrayOutputStream();

var generator = new JsonFactory().createGenerator(outputStream);

generator.writeStartObject();
var outputStream = new ByteArrayOutputStream();
try (var generator = new JsonFactory().createGenerator(outputStream)) {

generator.writeStartObject();
generator.writeStringField("@timestamp", new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX")
.format(new java.util.Date(event.getTimeStamp())));
generator.writeStringField("message", formatMessage(event.getFormattedMessage()));
generator.writeStringField("logger_name", event.getLoggerName());
generator.writeStringField("thread_name", event.getThreadName());
generator.writeStringField("level", event.getLevel().toString());
generator.writeStringField("stack_trace", getStackTrace(event));
generator.writeEndObject();

generator.flush();
outputStream.write('\n');
}

generator.writeStringField("@timestamp", new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX")
.format(new java.util.Date(event.getTimeStamp())));
generator.writeStringField("message", formatMessage(event.getFormattedMessage()));
generator.writeStringField("logger_name", event.getLoggerName());
generator.writeStringField("thread_name", event.getThreadName());
generator.writeStringField("level", event.getLevel().toString());
return outputStream.toByteArray();
}

private String getStackTrace(ILoggingEvent event) {
if (nonNull(event.getThrowableProxy())) {
var exception = (ThrowableProxy) event.getThrowableProxy();
if (nonNull(exception.getThrowable())) {
var sw = new StringWriter();
var pw = new PrintWriter(sw);
for (StackTraceElement element : exception.getThrowable().getStackTrace()) {
pw.println("\tat " + element);
}
var stackTrace = sw.toString().substring(0, 480); //Limit the stack trace to 480 characters
generator.writeStringField("stack_trace", stackTrace);
var writer = new StringWriter();
appendStackTraceElements(exception.getThrowable().getStackTrace(), writer);
appendStackTraceCauses(exception, writer);
return maxStackTraceLength > 0 ?
truncate(writer.toString(), maxStackTraceLength) :
writer.toString();
}
}
return null;
}

generator.writeEndObject();

generator.flush();
outputStream.write('\n');
private void appendStackTraceElements(StackTraceElement[] elements, StringWriter writer) {
for (StackTraceElement element : elements) {
if (isNull(stackTraceIncludePrefix) || stackTraceIncludePrefix.isEmpty() || element.toString().startsWith(stackTraceIncludePrefix)) {
writer
.append("\tat ")
.append(element.toString())
.append("\n");
}
}
}

return outputStream.toByteArray();
private void appendStackTraceCauses(ThrowableProxy exception, StringWriter writer) {
if (addCauses) {
var cause = exception;
while (!isNull(cause.getCause())) {
cause = (ThrowableProxy) cause.getCause();
writer
.append("caused by ")
.append(cause.getClassName())
.append(": ")
.append(cause.getMessage())
.append("\n");
if (!isNull(cause.getThrowable())) {
appendStackTraceElements(cause.getThrowable().getStackTrace(), writer);
}
}
}
}

private String formatMessage(String message) {
Expand Down

0 comments on commit da527bf

Please sign in to comment.