Error here?
It doesn't work out and I cannot get the reason :(
import java.util.logging.Logger;
public class LoggingTest {
public static void main(String[] args) {
String filename = "test.dat";
Logger.getGlobal().info(filename+"opened file");
}
}
I think you should add
java.util.logging.FileHandler
java.util.logging.ConsoleHandler
to
java.util.logging.Logger
or there will be no output in neither console nor log file.
Add this import - import java.util.logging.FileHandler;
Then add file handler before logging info:
FileHandler fileHandler = new FileHandler("test.dat", true);
Logger.getGlobal().addHandler(fileHandler);
Log4j writes to application log file instead of my own log file.
I tried to find a solution without editing the log4j.properties. Do I have to edit the config file? Why the lg file is not been created.
The app runs as a tomcat web app.
import org.apache.log4j.Logger;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.SimpleLayout;
public class ArchiveJanitor extends SecureResource {
private static final Logger logger = org.apache.log4j.Logger.getRootLogger();
public ArchiveJanitor(Context context, Request request, Response response) {
super(context, request, response);
try {
SimpleLayout layout = new SimpleLayout();
FileAppender fileAppender = new FileAppender( layout, "logs/Janitor.log", false );
logger.addAppender(fileAppender);
logger.setLevel((Level) Level.ALL);
}catch (IOException e){
logger.error(e.toString());
}
}
public void doSmth(){
logger.error("error ....")
}
}
Instead of private static final Logger logger = org.apache.log4j.Logger.getRootLogger(); try to use public static final Logger logger = LogManager.getLogger(ArchiveJanitor.class);
But probably its better to config it all in .properties file
I am performing JUnit Testing and receiving log4j:WARN No appenders could be found for logger (class .. ) error when I run test class(s).
Log4j properties file is present inside my folder root directory.
This code seems to work but why doesn't log4j picked up automatically.
package com.folio3.automation;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.junit.Test;
import junit.framework.Assert;
public class TestClass {
static {
BasicConfigurator.configure();
}
private static final Logger LOG = Logger.getLogger(TestClass.class);
#Test
public void test1(){
LOG.info("test 1 called ");
Assert.assertEquals(true, false);
}
}
Do I have to call BasicConfigurator.configure(); in every class or Base class ?
Is there any way to achieve?
Try adding your application root directory to your VM start command and your problem will disappear.
It it possible to modify a log event after matching a filter?
I've got an web container (Jersey) that logs uncaught exceptions at the ERROR level. But, for certain exceptions (EofException) throw by the server (Jetty), I'd like to log them at a lower level (INFO).
I can drop those messages entirely using a Logback filter that matches on the exception type (EofException). But I haven't found a supported method to modify the log event, e.g., change the log level.
You can simulate this behaviour using a TurboFilter by logging your own modified message with the provided logger, and denying the original.
I'm not convinced this sort of hack is a good idea, though.
package com.example.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
public class LogbackTest
{
private static class ModifyingFilter
extends TurboFilter
{
#Override
public FilterReply decide(
Marker marker,
ch.qos.logback.classic.Logger logger,
Level level,
String format,
Object[] params,
Throwable t)
{
if (level == Level.ERROR &&
logger.getName().equals("com.example.logback.LogbackTest") &&
format.equals("Connection successful: {}"))
{
logger.debug(marker, format, params);
return FilterReply.DENY;
}
return FilterReply.NEUTRAL;
}
}
public static void main(String[] args)
{
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
lc.addTurboFilter(new ModifyingFilter());
Logger logger = LoggerFactory.getLogger(LogbackTest.class);
logger.error("Connection successful: {}", "no problem", new RuntimeException("Hi"));
}
}
How can I configure slf4j to redirect all logged information to a Java string?
This is sometimes useful in unit tests, e.g. to test no warnings are printed when loading a servlet, or to make sure a forbidden SQL table is never used.
A bit late, but still...
As logging configurations should be easy to replace when unit testing, you could just configure to log over stdout and then capture that prior to executing the logging subject.
Then set the logger to be silent for all but the subject under test.
#Test
public void test()
{
String log = captureStdOut(() -> {
// ... invoke method that shouldn't log
});
assertThat(log, is(emptyString()));
}
public static String captureStdOut(Runnable r)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream out = System.out;
try {
System.setOut(new PrintStream(baos, true, StandardCharsets.UTF_8.name()));
r.run();
return new String(baos.toByteArray(), StandardCharsets.UTF_8);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("End of the world, Java doesn't recognise UTF-8");
} finally {
System.setOut(out);
}
}
And if using slf4j over log4j in tests, a simple log4j.properties:
log4j.rootLogger=OFF, out
log4j.category.com.acme.YourServlet=INFO, out
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.ConversionPattern=%-5p %c{1}:%L - %m%n
Or if you loath configuration as an external dependencies in unit tests, then programmatically configure log4j:
//...
static final String CONSOLE_APPENDER_NAME = "console.appender";
private String pattern = "%d [%p|%c|%C{1}] %m%n";
private Level threshold = Level.ALL;
private Level defaultLevel = Level.OFF;
//...
public void configure()
{
configureRootLogger();
configureConsoleAppender();
configureCustomLevels();
}
private void configureConsoleAppender()
{
ConsoleAppender console = new ConsoleAppender();
console.setName(CONSOLE_APPENDER_NAME);
console.setLayout(new PatternLayout(pattern));
console.setThreshold(threshold);
console.activateOptions();
Logger.getRootLogger().addAppender(console);
}
private void configureRootLogger()
{
Logger.getRootLogger().getLoggerRepository().resetConfiguration();
Logger.getRootLogger().setLevel(defaultLevel);
}
As I see it you have two options.
First you could implement a custom Appender (depending on which slf4j implementation you're using) which simply appends each logged statement to a StringBuffer. In this case you probably have to hold a static reference to your StringBuffer so your test classes can access it.
Second you could write your own implementation of ILoggerFactory and Logger. Again your Logger would just append all the messages to internal StringBuffers, although in this case you'd probably have multiple buffers, one for each log level. If you did it this way you'd have an easy way of retrieving the Logger instances since you'd own the factory that was distributing them.
Shouldn't make sense to redirect all the logs to watch to a separate log file? That way you have the control you want (you can delete the log file before running the test and checking if the file has been create at any moment) without losing the benefits of logging (redirecting your output to a String can cause memory leaks and is less performant)
This is a simple way to log to the console:
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.LoggerContext;
private void LogToConsole() {
BasicConfigurator bc = new BasicConfigurator();
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.reset();
bc.configure(lc);
}
Not quite exactly what you're doing, but I've written a LogInterceptingTestHarness which enables assertion of specific log statements. You could similarly use it (or something like it) to assert nothing has been logged at a certain level.
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.List;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import lombok.Getter;
/**
* Use this class to intercept logs for the purposes of unit testing log output.
* <p>
* On {#link Before} of the unit test, call {#link #initHarness(Class, Level)} or {#link #initHarness(Class, Level, String)} to get a new harness and hold onto reference to it in a class-level
* variable of your unit test
* <p>
* On {#link After} of the unit test, you MUST call {#link #teardown()} in order to remove the mocked {#link #appender}
*
* #author jeff.nelson
*
*/
#Getter
public class LogInterceptingTestHarness {
private final Appender appender;
private final ArgumentCaptor<LogEvent> logEventCaptor;
private final Logger itsLogger;
private LogInterceptingTestHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) {
logEventCaptor = ArgumentCaptor.forClass(LogEvent.class);
appender = mock(Appender.class);
doReturn("testAppender").when(appender).getName();
doReturn(true).when(appender).isStarted();
itsLogger = (Logger) LogManager.getLogger(classInterceptLogsFor);
itsLogger.addAppender(appender);
itsLogger.setLevel(logLevel);
}
public void teardown() {
itsLogger.removeAppender(appender);
}
public List<LogEvent> verifyNumLogEvents(int numEvents) {
verify(appender, times(numEvents)).append(logEventCaptor.capture());
return logEventCaptor.getAllValues();
}
public LogEvent verifyOneLogEvent() {
return verifyNumLogEvents(1).get(0);
}
public void assertLoggedMessage(String message) {
assertLogMessage(message, logEventCaptor.getValue());
}
public void assertLoggedMessage(String message, int messageIndex) {
assertLogMessage(message, logEventCaptor.getAllValues().get(messageIndex));
}
public static void assertLogMessage(String message, LogEvent event) {
assertEquals(message, event.getMessage().getFormattedMessage());
}
public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel) {
return initHarness(classInterceptLogsFor, logLevel, "testAppender");
}
public static LogInterceptingTestHarness initHarness(Class<?> classInterceptLogsFor, Level logLevel, String appenderName) {
return new LogInterceptingTestHarness(classInterceptLogsFor, logLevel, appenderName);
}
}