using java.util.logging across multiple classes - java

I found this example of using java.util.logging online here. I don't understand how to modify it to use the sample across multiple classes
do I just declare this in every class?
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
also in the class, they supplied there is a syntax error:
// suppress the logging output to the console
Logger rootLogger = Logger.*getLogger*("");
what is the correct way to get to the root logger?
package com.vogella.logger;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class MyLogger {
static private FileHandler fileTxt;
static private SimpleFormatter formatterTxt;
static private FileHandler fileHTML;
static private Formatter formatterHTML;
static public void setup() throws IOException {
// get the global logger to configure it
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
// suppress the logging output to the console
Logger rootLogger = Logger.*getLogger*("");
Handler[] handlers = rootLogger.getHandlers();
if (handlers[0] instanceof ConsoleHandler) {
rootLogger.removeHandler(handlers[0]);
}
logger.setLevel(Level.INFO);
fileTxt = new FileHandler("Logging.txt");
fileHTML = new FileHandler("Logging.html");
// create a TXT formatter
formatterTxt = new SimpleFormatter();
fileTxt.setFormatter(formatterTxt);
logger.addHandler(fileTxt);
// create an HTML formatter
formatterHTML = new MyHtmlFormatter();
fileHTML.setFormatter(formatterHTML);
logger.addHandler(fileHTML);
}
}

Yes. Using GLOBAL_LOGGER_NAME as stated in the linked Javadoc as well serves as logging using the global logger from each class. Though the usefulness is not much as it is a default java logger provided.
GLOBAL_LOGGER_NAME is a name for the global logger. This name is
provided as a convenience to developers who are making casual use of
the Logging package....
The preferred way to get the global logger object is via the call Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).
It's also an alternate of Logger.getGlobal() from the older jdk versions.
To configure the root logger use :-
Logger logger = Logger.getLogger("");

Related

Java logging question. It doesn't work out. Cannot find the reason

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 own log file

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

Log4j in Unit Testing Environment

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.

Logback: modify message via filter?

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"));
}
}

Redirect slf4j to string

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);
}
}

Categories

Resources