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
21 changes: 13 additions & 8 deletions src/main/java/com/logtail/logback/LogtailAppender.java
Original file line number Diff line number Diff line change
Expand Up @@ -309,17 +309,22 @@ protected Map<String, Object> generateLogRuntime(ILoggingEvent event) {
Map<String, Object> logRuntime = new HashMap<>();
logRuntime.put("thread", event.getThreadName());

if (event.hasCallerData()) {
StackTraceElement[] callerData = event.getCallerData();
try {
if (event.hasCallerData()) {
StackTraceElement[] callerData = event.getCallerData();

if (callerData.length > 0) {
StackTraceElement callerContext = callerData[0];
if (callerData.length > 0) {
StackTraceElement callerContext = callerData[0];

logRuntime.put("class", callerContext.getClassName());
logRuntime.put("method", callerContext.getMethodName());
logRuntime.put("file", callerContext.getFileName());
logRuntime.put("line", callerContext.getLineNumber());
logRuntime.put("class", callerContext.getClassName());
logRuntime.put("method", callerContext.getMethodName());
logRuntime.put("file", callerContext.getFileName());
logRuntime.put("line", callerContext.getLineNumber());
}
}
} catch (RuntimeException e) {
// Caller data is optional and some ILoggingEvent implementations fail to compute it, e.g. the Quarkus
// logback bridge on a log record without a source class - the line is still worth sending without it
}

return logRuntime;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.logtail.logback;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.junit.Assert.assertEquals;

/**
* Caller data is optional in the payload, so an event that cannot provide it must not take the whole batch down.
*/
public class LogtailAppenderCallerDataTest {

@Test
public void testBatchStillSerializesWhenAnEventThrowsFromHasCallerData() throws Exception {
Logger logger = new LoggerContext().getLogger(Logger.ROOT_LOGGER_NAME);
LogtailAppender appender = new LogtailAppender();
appender.batch.add(new LoggingEvent(Logger.FQCN, logger, Level.INFO, "Regular event", null, new Object[]{}));
appender.batch.add(new LoggingEvent(Logger.FQCN, logger, Level.INFO, "Event whose caller data throws", null, new Object[]{}) {
// The Quarkus logback bridge (io.quarkiverse.logback.runtime.LoggingEventWrapper) rebuilds caller data
// from the JBoss log record inside hasCallerData() and throws when the record carries no source class
@Override
public boolean hasCallerData() {
throw new NullPointerException("Declaring class is null");
}
});

List<Map<String, Object>> lines = new ObjectMapper().readValue(appender.batchToJson(2), new TypeReference<List<Map<String, Object>>>() {});

assertEquals(Arrays.asList("Regular event", "Event whose caller data throws"),
lines.stream().map(line -> line.get("message")).collect(Collectors.toList()));
assertEquals(Collections.singletonMap("thread", "main"), lines.get(1).get("runtime"));
}
}
Loading