我想动态地创建一个appender并将其添加到记录器中。然而,这似乎不可能使用slf4j。我可以将我的appender添加到log4j记录器中,但是我无法使用slf4j LoggerFactle检索记录器。
我想做的是:创建一个测试类(而不是jUnit测试),并在构造函数中传递一个记录器,供测试类使用。测试类的每个实例都需要自己的记录器和appender来保存日志,以便以后在HTML报告中使用。
我尝试了什么(为了简单起见,我创建了一个jUnit测试):
import static org.junit.Assert.assertEquals;
import java.util.LinkedList;
import java.util.List;
import org.apache.logging.log4j.core.LogEvent;
import org.junit.Test;
import org.slf4j.helpers.Log4jLoggerFactory;
import ch.fides.fusion.logging.ListAppender;
public class ListAppenderTest {
@Test
public void test() {
String testName = "test1";
// the log messages are to be inserted in this list
List<LogEvent> testLog = new LinkedList<>();
// create log4j logger
org.apache.logging.log4j.core.Logger log4jlogger = (org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager
.getLogger("Test:" + testName);
// create appender and add it to the logger
ListAppender listAppender = new ListAppender("Test:" + testName + ":MemoryAppender", testLog);
log4jlogger.addAppender(listAppender);
// get the slf4j logger
org.slf4j.helpers.Log4jLoggerFactory loggerFactory = new Log4jLoggerFactory();
org.slf4j.Logger testLogger = loggerFactory.getLogger("Test:" + testName);
// test it
final String TEST_MESSAGE = "test message";
testLogger.info(TEST_MESSAGE);
assertEquals(1, testLog.size());
LogEvent logEvent = testLog.get(0);
assertEquals(TEST_MESSAGE, logEvent.getMessage().getFormattedMessage() );
}
}
这是我最基本的附录:
package ch.fides.fusion.logging;
import java.util.List;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
public class ListAppender extends AbstractAppender {
private final List<LogEvent> log;
public ListAppender(String name, List<LogEvent> testLog) {
super(name, null, null);
this.log = testLog;
}
@Override
public void append(LogEvent logEvent) {
log.add(new TestLogEvent(logEvent));
}
}
我能做些什么来使它工作?也许我从错误的角度来处理这个问题,但是我想避免创建我自己的日志记录类。非常感谢任何帮助。
如果其他人对此感到困惑,那么slf4j版本1.7.26需要一个构建器模式,该模式与公认的答案相关。以下实现适用于java 8和scala 2.13(与lqbweb的答案略有不同):
爪哇:
java prettyprint-override">import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.LoggerContext
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false)
Configuration configuration = loggerContext.getConfiguration()
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("")
PatternLayout.Builder layoutBuilder = PatternLayout.newBuilder()
layoutBuilder.withPattern("%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n")
RandomAccessFileAppender.Builder<?> appenderBuilder =
(RandomAccessFileAppender.Builder<?>) RandomAccessFileAppender
.newBuilder()
appenderBuilder.setLayout(layoutBuilder.build())
appenderBuilder.withBufferedIo(true)
appenderBuilder.setFileName(logFile.getAbsolutePath)
appenderBuilder.setName("OutputDirFileLogger")
RandomAccessFileAppender appender = appenderBuilder.build()
appender.start() // important to make the appender usable instantly
rootLoggerConfig.addAppender(appender, Level.DEBUG, null)
scala:
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.LoggerContext
val loggerContext = LogManager.getContext(false).asInstanceOf[LoggerContext]
val configuration: Configuration = loggerContext.getConfiguration
val rootLoggerConfig: LoggerConfig = configuration.getLoggerConfig("")
val layoutBuilder: PatternLayout.Builder = PatternLayout.newBuilder()
layoutBuilder.withPattern("%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n")
val appenderBuilder: RandomAccessFileAppender.Builder[_] = RandomAccessFileAppender
.newBuilder()
.asInstanceOf[RandomAccessFileAppender.Builder[_]]
appenderBuilder.setLayout(layoutBuilder.build())
appenderBuilder.withBufferedIo(true)
appenderBuilder.setFileName(logFile.getAbsolutePath)
appenderBuilder.setName("OutputDirFileLogger")
val appender: RandomAccessFileAppender = appenderBuilder.build()
appender.start()
rootLoggerConfig.addAppender(appender, Level.DEBUG, null)
通过代码/在运行时通过slf4j访问和操作log4j2:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log4j2OverSlf4jConfigurator {
final private static Logger LOGGER = LoggerFactory.getLogger(Log4j2OverSlf4jConfigurator.class);
public static void main(final String[] args) {
LOGGER.info("Starting");
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
Configuration configuration = loggerContext.getConfiguration();
LOGGER.info("Filepath: {}", configuration.getConfigurationSource().getLocation());
// Log4j root logger has no name attribute -> name == ""
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");
rootLoggerConfig.getAppenders().forEach((name, appender) -> {
LOGGER.info("Appender {}: {}", name, appender.getLayout().toString());
// rootLoggerConfig.removeAppender(a.getName());
});
rootLoggerConfig.getAppenderRefs().forEach(ar -> {
System.out.println("AppenderReference: " + ar.getRef());
});
// adding appenders
configuration.addAppender(null);
}
}
参考:https://logging.apache.org/log4j/2.x/manual/customconfig.html
我认为您的情况与我们的类似。生产中的日志更复杂,但在JUnit测试期间更简单,这样我们就可以断言没有错误。
如果您使用的是log4j2,那么就有使用构建器的更清洁的解决方案
@Test
public void testClass() {
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
Configuration configuration = loggerContext.getConfiguration();
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");
ListAppender listAppender = new ListAppender("testAppender");
rootLoggerConfig.addAppender(listAppender, Level.ALL, null);
new TestClass(); //this is doing writing an error like org.slf4j.LoggerFactory.getLogger(TestClass.class).error("testing this");
assertEquals(1, listAppender.getEvents().size());
}
需要注意的是,调用getContext时需要传递“false”,否则它似乎无法获得与slf4j相同的上下文。
我目前正在尝试用log4j/slf4j和java 11构建一个应用程序,但在运行时我面临这个问题: 此问题的根源代码是我的记录器的初始化: 我依赖于: org.apache.logging.log4j: log4j-api: 2.11.1 org.apache.logging.log4j: log4j-core: 2.11.1 org.apache.logging.log4j: log4j-slf
SLF4J强制应用程序记录字符串。Log4J2 API支持记录任何CharSequence(如果您想记录文本),但也支持按原样记录任何对象。 Log4j 2 API支持日志记录消息对象、Java 8 lambda表达式和无垃圾日志记录(它在日志记录CharSequence对象时避免创建vararg数组和字符串)。
我想使用slf4j而不是Log4J。我在我的pom.xml中添加了以下依赖项(我对slf4j使用了1.7.25,对log4j2使用了2.10.0): 一切都构建得很好,没有编译错误或缺乏依赖,但我未能在类中指定负责日志程序初始化的配置(log4j2.xml)文件。在这种情况下,它总是打印相同的警告 我搜索了一种提供配置文件的适当方法,结果是: 问题是,在我的例子中,LogManager.getCo
问题内容: 因此,我尝试按照其网站上的此(非Maven实现)和要求将slf4j添加到log4j。并尝试使用此代码 并将以下内容添加到我的库中 log4j-api-2.3.jar log4j-core-2.3.jar log4j-sl4j-impl-2.3.jar log4j-to-sl4j-2.3.jar slf4j-api-1.7.12.jar 当我尝试运行它时,出现以下错误 知道我要去哪里错了
问题内容: 我在我的项目中使用log4j2和slf4j并使用maven进行构建。我正在使用以下pom文件(仅显示了相关依赖项),但是我在此pom文件的下面复制了错误- 我需要添加/删除所有内容才能使其正常工作。我已经访问了错误中的url以及log4j2依赖项页面,因此请不要仅仅指向响应中的URL。 信息: pom文件 更新: 我在pom文件中添加了以下依赖项,并且在mavenrepository中
问题内容: 我使用指令创建联系表格。最初我创建用于显示客户表单的customerForm指令。在这种形式下,我有一个按钮,当我们单击添加按钮时,称为getData函数,该函数内部使用newDirective显示ul列表。为此,我使用$ compile api编译html代码。很好,当我们单击“删除”按钮时,它也显示列表值和“删除”按钮,它称为scope.remove()函数。但是它只能删除一个。之