
Hello, I need to count number of error messages coming thru SLF4J into my app and integrate this number with System.exit() call at the end of the program. I have found that best solution would be to write an appender and dynamicaly add it in the code of my application. I am configuring logging by calling LoggerConfigurer (loading XML file) but I do not want to have my appender in this configuration - I do want to configure it dynamically not allowing user to modify XML and disable this error counter appender. But this does not work - the new appender method append() is never called. I think there is a problem with context or something. Here is the code: public class Test { final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Test.class); public void main(String[] args) { String fileName = "myfile.xml"; LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); try { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(lc); // the context was probably already configured by default configuration // rules lc.shutdownAndReset(); configurator.doConfigure(fileName); ErrorCounterAppender errAppender = new ErrorCounterAppender(); Logger root = LoggerFactory.getLogger(LoggerContext.ROOT_NAME); errAppender.setContext(lc); errAppender.start(); ((ch.qos.logback.classic.Logger) root).addAppender(errAppender); logger.error("TEST"); logger.info("Number of errors: {}", errAppender.getErrorNumber()); // prints 0 System.exit(errAppender.getErrorNumber()); // returns 0 (instead of 1) } catch (Throwable t) { logger.warn("Cannot configure logger from location " + fileName, t); } StatusPrinter.print(lc); } } I think there must be some problem in the context or something. Or is there any better solution of my problem? Here is my appender: /** * Thread-safe implementation of error counter appender for LogBack. */ public class ErrorCounterAppender extends AppenderBase<LoggingEvent> { AtomicInteger errorCounter = new AtomicInteger(0); private Layout<LoggingEvent> layout; public ErrorCounterAppender() { } @Override public void setLayout(Layout<LoggingEvent> layout) { this.layout = layout; } public void resetErrorNumber() { errorCounter.set(0); } public int getErrorNumber() { return errorCounter.get(); } @Override public void start() { if (this.layout == null) { addError("No layout set for the appender named [" + name + "]."); return; } super.start(); } @Override public void append(LoggingEvent event) { if (event == null) return; if (Level.ERROR == event.getLevel()) { errorCounter.incrementAndGet(); } } } ----- -- Lukas Zapletal http://lukas.zapletalovi.com -- View this message in context: http://www.nabble.com/Error-counter-appender-tp22205463p22205463.html Sent from the Logback User mailing list archive at Nabble.com.

Hello Lukas, I just added one line to your code, after errAppender.start(); errAppender.start(); StatusPrinter.print(lc); <--- this is the new line of code This resulted in the following output (edited for brevity): INFO in c.q.l.c.LoggerContext - Could NOT find resource logback-test.xml] INFO in c.q.l.c.LoggerContext - Could NOT find resource [logback.xml] INFO in c.q.l.c.LoggerContext - Setting up default configuration. ERROR in ErrorCounterAppender - No layout set for the appender named [null]. The error message explains the reasons for the behavior you are seeing. HTH, Lukas Zapletal wrote:
Hello,
I need to count number of error messages coming thru SLF4J into my app and integrate this number with System.exit() call at the end of the program.
I have found that best solution would be to write an appender and dynamicaly add it in the code of my application. I am configuring logging by calling LoggerConfigurer (loading XML file) but I do not want to have my appender in this configuration - I do want to configure it dynamically not allowing user to modify XML and disable this error counter appender. But this does not work - the new appender method append() is never called. I think there is a problem with context or something. Here is the code:
public class Test { final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Test.class);
public void main(String[] args) { String fileName = "myfile.xml"; LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
try { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(lc); // the context was probably already configured by default configuration // rules lc.shutdownAndReset(); configurator.doConfigure(fileName);
ErrorCounterAppender errAppender = new ErrorCounterAppender(); Logger root = LoggerFactory.getLogger(LoggerContext.ROOT_NAME); errAppender.setContext(lc); errAppender.start(); ((ch.qos.logback.classic.Logger) root).addAppender(errAppender); logger.error("TEST"); logger.info("Number of errors: {}", errAppender.getErrorNumber()); // prints 0 System.exit(errAppender.getErrorNumber()); // returns 0 (instead of 1)
} catch (Throwable t) { logger.warn("Cannot configure logger from location " + fileName, t); } StatusPrinter.print(lc); }
}
I think there must be some problem in the context or something. Or is there any better solution of my problem? Here is my appender:
/**
* Thread-safe implementation of error counter appender for LogBack.
*/
public class ErrorCounterAppender extends AppenderBase<LoggingEvent> {
AtomicInteger errorCounter = new AtomicInteger(0);
private Layout<LoggingEvent> layout;
public ErrorCounterAppender() {
}
@Override
public void setLayout(Layout<LoggingEvent> layout) {
this.layout = layout;
}
public void resetErrorNumber() {
errorCounter.set(0);
}
public int getErrorNumber() {
return errorCounter.get();
}
@Override
public void start() {
if (this.layout == null) {
addError("No layout set for the appender named [" + name + "].");
return;
}
super.start();
}
@Override
public void append(LoggingEvent event) {
if (event == null)
return;
if (Level.ERROR == event.getLevel()) {
errorCounter.incrementAndGet();
}
}
}
----- -- Lukas Zapletal http://lukas.zapletalovi.com
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch

Great, thank you. Is there somethink like "null" layout in the head distribution? I do not need that. Well I will create one... Thank you I hope it will help. ps - is this context LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); the very same as the context I use when I log like this Logger logger = LoggerFactory.getLogger(MyClass.class); logger.debug("Hello world."); if both statements are in the same source file? LZ Ceki Gulcu wrote:
Hello Lukas,
I just added one line to your code, after errAppender.start();
errAppender.start(); StatusPrinter.print(lc); <--- this is the new line of code
This resulted in the following output (edited for brevity):
INFO in c.q.l.c.LoggerContext - Could NOT find resource logback-test.xml] INFO in c.q.l.c.LoggerContext - Could NOT find resource [logback.xml] INFO in c.q.l.c.LoggerContext - Setting up default configuration. ERROR in ErrorCounterAppender - No layout set for the appender named [null].
The error message explains the reasons for the behavior you are seeing.
HTH,
Lukas Zapletal wrote:
Hello,
I need to count number of error messages coming thru SLF4J into my app and integrate this number with System.exit() call at the end of the program.
I have found that best solution would be to write an appender and dynamicaly add it in the code of my application. I am configuring logging by calling LoggerConfigurer (loading XML file) but I do not want to have my appender in this configuration - I do want to configure it dynamically not allowing user to modify XML and disable this error counter appender. But this does not work - the new appender method append() is never called. I think there is a problem with context or something. Here is the code:
public class Test { final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Test.class);
public void main(String[] args) { String fileName = "myfile.xml"; LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
try { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(lc); // the context was probably already configured by default configuration // rules lc.shutdownAndReset(); configurator.doConfigure(fileName);
ErrorCounterAppender errAppender = new ErrorCounterAppender(); Logger root = LoggerFactory.getLogger(LoggerContext.ROOT_NAME); errAppender.setContext(lc); errAppender.start(); ((ch.qos.logback.classic.Logger) root).addAppender(errAppender); logger.error("TEST"); logger.info("Number of errors: {}", errAppender.getErrorNumber()); // prints 0 System.exit(errAppender.getErrorNumber()); // returns 0 (instead of 1)
} catch (Throwable t) { logger.warn("Cannot configure logger from location " + fileName, t); } StatusPrinter.print(lc); }
}
I think there must be some problem in the context or something. Or is there any better solution of my problem? Here is my appender:
/**
* Thread-safe implementation of error counter appender for LogBack.
*/
public class ErrorCounterAppender extends AppenderBase<LoggingEvent> {
AtomicInteger errorCounter = new AtomicInteger(0);
private Layout<LoggingEvent> layout;
public ErrorCounterAppender() {
}
@Override
public void setLayout(Layout<LoggingEvent> layout) {
this.layout = layout;
}
public void resetErrorNumber() {
errorCounter.set(0);
}
public int getErrorNumber() {
return errorCounter.get();
}
@Override
public void start() {
if (this.layout == null) {
addError("No layout set for the appender named [" + name + "].");
return;
}
super.start();
}
@Override
public void append(LoggingEvent event) {
if (event == null)
return;
if (Level.ERROR == event.getLevel()) {
errorCounter.incrementAndGet();
}
}
}
----- -- Lukas Zapletal http://lukas.zapletalovi.com
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch _______________________________________________ Logback-user mailing list Logback-user@qos.ch http://qos.ch/mailman/listinfo/logback-user
----- -- Lukas Zapletal http://lukas.zapletalovi.com -- View this message in context: http://www.nabble.com/Error-counter-appender-tp22205463p22207166.html Sent from the Logback User mailing list archive at Nabble.com.

Creating my "EmptyLayout" helped. Thank you a lot. LZ Lukas Zapletal (gmail) wrote:
Great, thank you.
Is there somethink like "null" layout in the head distribution? I do not need that. Well I will create one...
Thank you I hope it will help.
----- -- Lukas Zapletal http://lukas.zapletalovi.com -- View this message in context: http://www.nabble.com/Error-counter-appender-tp22205463p22223563.html Sent from the Logback User mailing list archive at Nabble.com.

Lukas, I forgot to mention this, but layouts are optional. If your appener does not need it, you don't actually need to set a layout. You can just leave the layout to be null. In ErrorCounterAppender modify the start() to become: @Override public void start() { super.start(); } If you do that, you will no longer need a layout. Lukas Zapletal wrote:
Creating my "EmptyLayout" helped.
Thank you a lot.
LZ
Lukas Zapletal (gmail) wrote:
Great, thank you.
Is there somethink like "null" layout in the head distribution? I do not need that. Well I will create one...
Thank you I hope it will help.
-- Ceki Gülcü Logback: The reliable, generic, fast and flexible logging framework for Java. http://logback.qos.ch
participants (2)
-
Ceki Gulcu
-
Lukas Zapletal