Skip to content

Commit

Permalink
Merge branch 'master' into bugfix/histark-bad-request
Browse files Browse the repository at this point in the history
  • Loading branch information
stigus committed Oct 28, 2024
2 parents 7853535 + a685ce8 commit 9405f48
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,113 @@
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,113 @@
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 9405f48

Please sign in to comment.