Files
goldenChart/backend/src/main/java/com/goldenchart/service/Ta4jRuleTraceCapture.java
T
2026-06-17 13:40:52 +09:00

83 lines
2.8 KiB
Java

package com.goldenchart.service;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.read.ListAppender;
import ch.qos.logback.core.spi.FilterReply;
import org.slf4j.LoggerFactory;
import org.ta4j.core.Rule;
import org.ta4j.core.TradingRecord;
/**
* Ta4j Rule 평가 시 TRACE 로그를 메모리에 수집 (AI 검증용).
*/
final class Ta4jRuleTraceCapture implements AutoCloseable {
private static final int MAX_LINES = 100;
private static final int MAX_LINE_LEN = 600;
private final ListAppender<ILoggingEvent> appender;
private final Logger rulesLogger;
private final Level previousLevel;
private Ta4jRuleTraceCapture(ListAppender<ILoggingEvent> appender, Logger rulesLogger, Level previousLevel) {
this.appender = appender;
this.rulesLogger = rulesLogger;
this.previousLevel = previousLevel;
}
static Ta4jRuleTraceCapture open() {
LoggerContext ctx = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger rulesLogger = ctx.getLogger("org.ta4j.core.rules");
Level prev = rulesLogger.getLevel();
ListAppender<ILoggingEvent> appender = new ListAppender<>();
appender.addFilter(new Filter<>() {
@Override
public FilterReply decide(ILoggingEvent event) {
if (event == null || event.getLoggerName() == null) return FilterReply.DENY;
return event.getLoggerName().startsWith("org.ta4j.core.rules")
? FilterReply.ACCEPT
: FilterReply.DENY;
}
});
appender.setContext(ctx);
appender.start();
rulesLogger.setLevel(Level.TRACE);
rulesLogger.setAdditive(true);
rulesLogger.addAppender(appender);
return new Ta4jRuleTraceCapture(appender, rulesLogger, prev);
}
boolean evaluateWithTrace(Rule rule, int index, TradingRecord tradingRecord) {
return rule.isSatisfiedWithTraceMode(index, tradingRecord, Rule.TraceMode.VERBOSE);
}
java.util.List<String> lines() {
return appender.list.stream()
.filter(e -> e.getLevel().isGreaterOrEqual(Level.TRACE))
.map(ILoggingEvent::getFormattedMessage)
.map(Ta4jRuleTraceCapture::truncate)
.limit(MAX_LINES)
.toList();
}
@Override
public void close() {
rulesLogger.detachAppender(appender);
appender.stop();
rulesLogger.setLevel(previousLevel);
}
private static String truncate(String s) {
if (s == null) return "";
if (s.length() <= MAX_LINE_LEN) return s;
return s.substring(0, MAX_LINE_LEN) + "…";
}
}