Skip to content

Commit a51155b

Browse files
committed
Implements Log capture feature
1 parent 878d8d6 commit a51155b

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.github.rexrk.exception.insights.capture;
2+
3+
import ch.qos.logback.classic.Logger;
4+
import ch.qos.logback.classic.LoggerContext;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.beans.factory.InitializingBean;
7+
import org.springframework.beans.factory.DisposableBean;
8+
9+
public class LogAppenderRegistrar implements InitializingBean, DisposableBean {
10+
11+
private final RingBufferLogAppender appender;
12+
13+
public LogAppenderRegistrar(RingBufferLogAppender appender) {
14+
this.appender = appender;
15+
}
16+
17+
@Override
18+
public void afterPropertiesSet() {
19+
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
20+
appender.setContext(context);
21+
appender.start();
22+
context.getLogger(Logger.ROOT_LOGGER_NAME).addAppender(appender);
23+
}
24+
25+
@Override
26+
public void destroy() {
27+
appender.stop(); // clean detach on app shutdown
28+
}
29+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.github.rexrk.exception.insights.capture;
2+
3+
import ch.qos.logback.classic.Level;
4+
import ch.qos.logback.classic.spi.ILoggingEvent;
5+
import ch.qos.logback.classic.spi.IThrowableProxy;
6+
import ch.qos.logback.core.AppenderBase;
7+
import io.github.rexrk.exception.insights.model.LogLine;
8+
9+
import java.time.Instant;
10+
import java.util.ArrayDeque;
11+
import java.util.ArrayList;
12+
import java.util.Deque;
13+
import java.util.List;
14+
15+
public class RingBufferLogAppender extends AppenderBase<ILoggingEvent> {
16+
17+
private final int bufferSize;
18+
private final Deque<LogLine> buffer;
19+
20+
public RingBufferLogAppender(int bufferSize) {
21+
this.bufferSize = bufferSize;
22+
this.buffer = new ArrayDeque<>(bufferSize);
23+
}
24+
25+
@Override
26+
protected synchronized void append(ILoggingEvent event) {
27+
if (!event.getLevel().isGreaterOrEqual(Level.WARN)) return;
28+
29+
if (buffer.size() == bufferSize) {
30+
buffer.pollFirst();
31+
}
32+
33+
buffer.addLast(new LogLine(
34+
event.getLevel().toString(),
35+
event.getFormattedMessage(),
36+
event.getLoggerName(),
37+
event.getThreadName(),
38+
throwableClass(event.getThrowableProxy()),
39+
throwableMessage(event.getThrowableProxy()),
40+
Instant.ofEpochMilli(event.getTimeStamp())
41+
));
42+
}
43+
44+
public synchronized List<LogLine> drainRecent(int limit) {
45+
List<LogLine> all = new ArrayList<>(buffer);
46+
int from = Math.max(0, all.size() - limit);
47+
return all.subList(from, all.size());
48+
}
49+
50+
private String throwableClass(IThrowableProxy proxy) {
51+
return proxy != null ? proxy.getClassName() : null;
52+
}
53+
54+
private String throwableMessage(IThrowableProxy proxy) {
55+
return proxy != null ? proxy.getMessage() : null;
56+
}
57+
}

0 commit comments

Comments
 (0)