logback-dev
Threads by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 9940 discussions
[JIRA] Commented: (LBCORE-63) Deadlock when running on multiple core processors
by Paweł Paprota (JIRA) 16 Nov '08
by Paweł Paprota (JIRA) 16 Nov '08
16 Nov '08
[ http://jira.qos.ch/browse/LBCORE-63?page=com.atlassian.jira.plugin.system.i… ]
Paweł Paprota commented on LBCORE-63:
-------------------------------------
Thanks, I will update to 0.9.11 ASAP then.
Good luck with fixing it "the right way" :-)
> Deadlock when running on multiple core processors
> -------------------------------------------------
>
> Key: LBCORE-63
> URL: http://jira.qos.ch/browse/LBCORE-63
> Project: logback-core
> Issue Type: Sub-task
> Affects Versions: 0.9.9
> Environment: Operating System: Windows
> Platform: PC
> Reporter: Toni Heimala
> Assignee: Ceki Gulcu
> Priority: Blocker
> Attachments: patch.txt, patch2.txt, patch3.txt
>
>
> When you run logging into same file from many threads on a system that has more than one physical processor (Dual Core for example), a deadlock will occur after a while. This can not be reproduced on HyperThreading processors. Here's an example program that will demonstrate the behavior:
> -----------------------------
> Main.java
> -----------------------------
> import java.util.Date;
> import java.util.concurrent.ScheduledThreadPoolExecutor;
> import java.util.concurrent.TimeUnit;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import ch.qos.logback.classic.LoggerContext;
> import ch.qos.logback.classic.joran.JoranConfigurator;
> import ch.qos.logback.core.joran.spi.JoranException;
> public class Main extends Thread
> {
> private final static String LOGGER_CONFIGURATION_FILE = "logger.xml";
> private final Logger logger = LoggerFactory.getLogger(Main.class);
>
> private final long start;
>
> public Main()
> throws JoranException
> {
> start = new Date().getTime();
> LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
> JoranConfigurator configurator = new JoranConfigurator();
> lc.shutdownAndReset();
> configurator.setContext(lc);
> configurator.doConfigure(LOGGER_CONFIGURATION_FILE);
> }
>
> public void start()
> {
> ScheduledThreadPoolExecutor ex1 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex2 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex3 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex4 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex5 = new ScheduledThreadPoolExecutor(1);
> ex1.scheduleAtFixedRate(new Task("EX1"), 10, 10, TimeUnit.MICROSECONDS);
> ex2.scheduleAtFixedRate(new Task("EX2"), 10, 10, TimeUnit.MICROSECONDS);
> ex3.scheduleAtFixedRate(new Task("EX3"), 10, 10, TimeUnit.MICROSECONDS);
> ex4.scheduleAtFixedRate(new Task("EX4"), 10, 10, TimeUnit.MICROSECONDS);
> ex5.scheduleAtFixedRate(new Task("EX5"), 10, 10, TimeUnit.MICROSECONDS);
>
> super.start();
> }
>
> public void run()
> {
> try
> {
> while(true)
> {
> logger.debug("[MAIN] {}", new Date().getTime() - start);
> Thread.sleep(10);
> }
> }
> catch (InterruptedException e)
> {
> logger.info("[MAIN]: Interrupted: {}", e.getMessage());
> }
> }
>
> public static void main(String[] args)
> {
> try
> {
> Main main = new Main();
> main.start();
> }
> catch (JoranException e)
> {
> System.out.println("Failed to load application: " + e.getMessage());
> }
> }
> }
> -------------------------------
> Task.java
> -------------------------------
> import java.util.Date;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> public class Task implements Runnable
> {
> private final Logger logger = LoggerFactory.getLogger(Task.class);
> private final Logger logger_main = LoggerFactory.getLogger(Main.class);
> private final String name;
> private final long start;
>
> public Task(final String name)
> {
> this.name = name;
> start = new Date().getTime();
> }
> public void run()
> {
> logger.debug("[{}] {}", name, new Date().getTime() - start);
> logger_main.debug("[MAIN] - [{}] {}", name, new Date().getTime() - start);
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0
[JIRA] Commented: (LBCORE-63) Deadlock when running on multiple core processors
by Ralph Goers (JIRA) 15 Nov '08
by Ralph Goers (JIRA) 15 Nov '08
15 Nov '08
[ http://jira.qos.ch/browse/LBCORE-63?page=com.atlassian.jira.plugin.system.i… ]
Ralph Goers commented on LBCORE-63:
-----------------------------------
I should point out, this isn't a deadlock but a bottleneck. By removing the locking in Logback we allow Appenders to better handle situations like this. But to do that the Appender will have to extend UnsynchronizedAppenderBase, which the SocketAppender doesn't do. Even if it did, because the SocketAppender has a scarce resource, the socket, it would eventually have to block on that.
The SocketAppender could be modified to use a pool of sockets, but then you would just end up with a bunch of threads sitting in SocketWrite. The advantage is that if the sockets have a 5 second timeout and you have 10 threads then the average log event takes 50 seconds. With a socket pool the same size as the number of threads the average log event would be 5 seconds. Still awful but 10 times better.
What is needed is a better way to handle Appenders that are "Out of Service". I will create a Jira issue for that and create a patch at some point.
> Deadlock when running on multiple core processors
> -------------------------------------------------
>
> Key: LBCORE-63
> URL: http://jira.qos.ch/browse/LBCORE-63
> Project: logback-core
> Issue Type: Sub-task
> Affects Versions: 0.9.9
> Environment: Operating System: Windows
> Platform: PC
> Reporter: Toni Heimala
> Assignee: Ceki Gulcu
> Priority: Blocker
> Attachments: patch.txt, patch2.txt, patch3.txt
>
>
> When you run logging into same file from many threads on a system that has more than one physical processor (Dual Core for example), a deadlock will occur after a while. This can not be reproduced on HyperThreading processors. Here's an example program that will demonstrate the behavior:
> -----------------------------
> Main.java
> -----------------------------
> import java.util.Date;
> import java.util.concurrent.ScheduledThreadPoolExecutor;
> import java.util.concurrent.TimeUnit;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import ch.qos.logback.classic.LoggerContext;
> import ch.qos.logback.classic.joran.JoranConfigurator;
> import ch.qos.logback.core.joran.spi.JoranException;
> public class Main extends Thread
> {
> private final static String LOGGER_CONFIGURATION_FILE = "logger.xml";
> private final Logger logger = LoggerFactory.getLogger(Main.class);
>
> private final long start;
>
> public Main()
> throws JoranException
> {
> start = new Date().getTime();
> LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
> JoranConfigurator configurator = new JoranConfigurator();
> lc.shutdownAndReset();
> configurator.setContext(lc);
> configurator.doConfigure(LOGGER_CONFIGURATION_FILE);
> }
>
> public void start()
> {
> ScheduledThreadPoolExecutor ex1 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex2 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex3 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex4 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex5 = new ScheduledThreadPoolExecutor(1);
> ex1.scheduleAtFixedRate(new Task("EX1"), 10, 10, TimeUnit.MICROSECONDS);
> ex2.scheduleAtFixedRate(new Task("EX2"), 10, 10, TimeUnit.MICROSECONDS);
> ex3.scheduleAtFixedRate(new Task("EX3"), 10, 10, TimeUnit.MICROSECONDS);
> ex4.scheduleAtFixedRate(new Task("EX4"), 10, 10, TimeUnit.MICROSECONDS);
> ex5.scheduleAtFixedRate(new Task("EX5"), 10, 10, TimeUnit.MICROSECONDS);
>
> super.start();
> }
>
> public void run()
> {
> try
> {
> while(true)
> {
> logger.debug("[MAIN] {}", new Date().getTime() - start);
> Thread.sleep(10);
> }
> }
> catch (InterruptedException e)
> {
> logger.info("[MAIN]: Interrupted: {}", e.getMessage());
> }
> }
>
> public static void main(String[] args)
> {
> try
> {
> Main main = new Main();
> main.start();
> }
> catch (JoranException e)
> {
> System.out.println("Failed to load application: " + e.getMessage());
> }
> }
> }
> -------------------------------
> Task.java
> -------------------------------
> import java.util.Date;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> public class Task implements Runnable
> {
> private final Logger logger = LoggerFactory.getLogger(Task.class);
> private final Logger logger_main = LoggerFactory.getLogger(Main.class);
> private final String name;
> private final long start;
>
> public Task(final String name)
> {
> this.name = name;
> start = new Date().getTime();
> }
> public void run()
> {
> logger.debug("[{}] {}", name, new Date().getTime() - start);
> logger_main.debug("[MAIN] - [{}] {}", name, new Date().getTime() - start);
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0
[JIRA] Commented: (LBCORE-63) Deadlock when running on multiple core processors
by Ceki Gulcu (JIRA) 15 Nov '08
by Ceki Gulcu (JIRA) 15 Nov '08
15 Nov '08
[ http://jira.qos.ch/browse/LBCORE-63?page=com.atlassian.jira.plugin.system.i… ]
Ceki Gulcu commented on LBCORE-63:
----------------------------------
Pawel,
Ralph's made has made it into the trunk and was part of the 0.9.11 release. The bad news is that the problem that you are suffering from is in the eclipse plug-in. Ralph's patch merely displaces the deadlock elsewhere.
> Deadlock when running on multiple core processors
> -------------------------------------------------
>
> Key: LBCORE-63
> URL: http://jira.qos.ch/browse/LBCORE-63
> Project: logback-core
> Issue Type: Sub-task
> Affects Versions: 0.9.9
> Environment: Operating System: Windows
> Platform: PC
> Reporter: Toni Heimala
> Assignee: Ceki Gulcu
> Priority: Blocker
> Attachments: patch.txt, patch2.txt, patch3.txt
>
>
> When you run logging into same file from many threads on a system that has more than one physical processor (Dual Core for example), a deadlock will occur after a while. This can not be reproduced on HyperThreading processors. Here's an example program that will demonstrate the behavior:
> -----------------------------
> Main.java
> -----------------------------
> import java.util.Date;
> import java.util.concurrent.ScheduledThreadPoolExecutor;
> import java.util.concurrent.TimeUnit;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import ch.qos.logback.classic.LoggerContext;
> import ch.qos.logback.classic.joran.JoranConfigurator;
> import ch.qos.logback.core.joran.spi.JoranException;
> public class Main extends Thread
> {
> private final static String LOGGER_CONFIGURATION_FILE = "logger.xml";
> private final Logger logger = LoggerFactory.getLogger(Main.class);
>
> private final long start;
>
> public Main()
> throws JoranException
> {
> start = new Date().getTime();
> LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
> JoranConfigurator configurator = new JoranConfigurator();
> lc.shutdownAndReset();
> configurator.setContext(lc);
> configurator.doConfigure(LOGGER_CONFIGURATION_FILE);
> }
>
> public void start()
> {
> ScheduledThreadPoolExecutor ex1 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex2 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex3 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex4 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex5 = new ScheduledThreadPoolExecutor(1);
> ex1.scheduleAtFixedRate(new Task("EX1"), 10, 10, TimeUnit.MICROSECONDS);
> ex2.scheduleAtFixedRate(new Task("EX2"), 10, 10, TimeUnit.MICROSECONDS);
> ex3.scheduleAtFixedRate(new Task("EX3"), 10, 10, TimeUnit.MICROSECONDS);
> ex4.scheduleAtFixedRate(new Task("EX4"), 10, 10, TimeUnit.MICROSECONDS);
> ex5.scheduleAtFixedRate(new Task("EX5"), 10, 10, TimeUnit.MICROSECONDS);
>
> super.start();
> }
>
> public void run()
> {
> try
> {
> while(true)
> {
> logger.debug("[MAIN] {}", new Date().getTime() - start);
> Thread.sleep(10);
> }
> }
> catch (InterruptedException e)
> {
> logger.info("[MAIN]: Interrupted: {}", e.getMessage());
> }
> }
>
> public static void main(String[] args)
> {
> try
> {
> Main main = new Main();
> main.start();
> }
> catch (JoranException e)
> {
> System.out.println("Failed to load application: " + e.getMessage());
> }
> }
> }
> -------------------------------
> Task.java
> -------------------------------
> import java.util.Date;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> public class Task implements Runnable
> {
> private final Logger logger = LoggerFactory.getLogger(Task.class);
> private final Logger logger_main = LoggerFactory.getLogger(Main.class);
> private final String name;
> private final long start;
>
> public Task(final String name)
> {
> this.name = name;
> start = new Date().getTime();
> }
> public void run()
> {
> logger.debug("[{}] {}", name, new Date().getTime() - start);
> logger_main.debug("[MAIN] - [{}] {}", name, new Date().getTime() - start);
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0
[JIRA] Commented: (LBCORE-63) Deadlock when running on multiple core processors
by Paweł Paprota (JIRA) 15 Nov '08
by Paweł Paprota (JIRA) 15 Nov '08
15 Nov '08
[ http://jira.qos.ch/browse/LBCORE-63?page=com.atlassian.jira.plugin.system.i… ]
Paweł Paprota commented on LBCORE-63:
-------------------------------------
What is the current status of this issue? I think I got hit by this one, at least that's what I'm seeing right now in Eclipse when I suspend all threads in my application - one thread has callAppenders in its stack trace and it hanged (yesterday) on socketWrite. Some of the other threads seem to be waiting on a lock in callAppenders. As a result, I don't see any more logging appended to my log file and the console.
I'm using logback-core/classic 0.9.9 with slf4j 1.5.3.
Did the Ralph's patch make it to any of the newer logback releases? I was not able to find any change log or release announcement for releases newer than 0.9.9...
I would really appreciate some feedback, thank you.
Below is the stack trace of the "offending" thread (only relevant calls included):
Thread [Thread-12] (Suspended)
SocketOutputStream.socketWrite0(FileDescriptor, byte[], int, int) line: not available [native method]
SocketOutputStream.socketWrite(byte[], int, int) line: 92
SocketOutputStream.write(byte[], int, int) line: 136
ObjectOutputStream$BlockDataOutputStream.drain() line: 1685
ObjectOutputStream$BlockDataOutputStream.write(byte[], int, int, boolean) line: 1649
ObjectOutputStream.defaultWriteFields(Object, ObjectStreamClass) line: 1368
ObjectOutputStream.writeSerialData(Object, ObjectStreamClass) line: 1347
ObjectOutputStream.writeOrdinaryObject(Object, ObjectStreamClass, boolean) line: 1290
ObjectOutputStream.writeObject0(Object, boolean) line: 1079
ObjectOutputStream.writeArray(Object, ObjectStreamClass, boolean) line: 1251
ObjectOutputStream.writeObject0(Object, boolean) line: 1075
ObjectOutputStream.defaultWriteFields(Object, ObjectStreamClass) line: 1375
ObjectOutputStream.defaultWriteObject() line: 391
LoggingEvent.writeObject(ObjectOutputStream) line: 288
GeneratedMethodAccessor1118.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 585
ObjectStreamClass.invokeWriteObject(Object, ObjectOutputStream) line: 917
ObjectOutputStream.writeSerialData(Object, ObjectStreamClass) line: 1339
ObjectOutputStream.writeOrdinaryObject(Object, ObjectStreamClass, boolean) line: 1290
ObjectOutputStream.writeObject0(Object, boolean) line: 1079
ObjectOutputStream.writeObject(Object) line: 302
SocketAppender(SocketAppenderBase<E>).append(E) line: 163
SocketAppender(AppenderBase<E>).doAppend(E) line: 81
AppenderAttachableImpl<E>.appendLoopOnAppenders(E) line: 51
Logger.appendLoopOnAppenders(LoggingEvent) line: 282
Logger.callAppenders(LoggingEvent) line: 266
Logger.buildLoggingEventAndAppend(String, Marker, Level, String, Object[], Throwable) line: 487
Logger.filterAndLog(String, Marker, Level, String, Object, Object, Throwable) line: 460
Logger.debug(String, Object, Object) line: 406
And those are the ones being blocked:
Thread [Thread-4] (Suspended)
Logger.callAppenders(LoggingEvent) line: 265
Logger.buildLoggingEventAndAppend(String, Marker, Level, String, Object[], Throwable) line: 487
Logger.filterAndLog(String, Marker, Level, String, Object[], Throwable) line: 479
Logger.debug(String, Throwable) line: 414
Daemon Thread [ActiveMQ Connection Worker: tcp://localhost/127.0.0.1:61616] (Suspended)
Logger.callAppenders(LoggingEvent) line: 265
Logger.buildLoggingEventAndAppend(String, Marker, Level, String, Object[], Throwable) line: 487
Logger.filterAndLog(String, Marker, Level, String, Object[], Throwable) line: 479
Logger.log(Marker, String, int, String, Throwable) line: 818
SLF4JLocationAwareLog.info(Object, Throwable) line: 152
AdvisoryConsumer.dispose() line: 58
ActiveMQConnection.close() line: 563
CachingConnectionFactory(SingleConnectionFactory).closeConnection(Connection) line: 364
CachingConnectionFactory(SingleConnectionFactory).resetConnection() line: 302
CachingConnectionFactory.resetConnection() line: 120
CachingConnectionFactory(SingleConnectionFactory).onException(JMSException) line: 283
SingleConnectionFactory$InternalChainedExceptionListener(ChainedExceptionListener).onException(JMSException) line: 60
ActiveMQConnection$3.run() line: 1690
ThreadPoolExecutor$Worker.runTask(Runnable) line: 650
ThreadPoolExecutor$Worker.run() line: 675
Thread.run() line: 595
> Deadlock when running on multiple core processors
> -------------------------------------------------
>
> Key: LBCORE-63
> URL: http://jira.qos.ch/browse/LBCORE-63
> Project: logback-core
> Issue Type: Sub-task
> Affects Versions: 0.9.9
> Environment: Operating System: Windows
> Platform: PC
> Reporter: Toni Heimala
> Assignee: Ceki Gulcu
> Priority: Blocker
> Attachments: patch.txt, patch2.txt, patch3.txt
>
>
> When you run logging into same file from many threads on a system that has more than one physical processor (Dual Core for example), a deadlock will occur after a while. This can not be reproduced on HyperThreading processors. Here's an example program that will demonstrate the behavior:
> -----------------------------
> Main.java
> -----------------------------
> import java.util.Date;
> import java.util.concurrent.ScheduledThreadPoolExecutor;
> import java.util.concurrent.TimeUnit;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import ch.qos.logback.classic.LoggerContext;
> import ch.qos.logback.classic.joran.JoranConfigurator;
> import ch.qos.logback.core.joran.spi.JoranException;
> public class Main extends Thread
> {
> private final static String LOGGER_CONFIGURATION_FILE = "logger.xml";
> private final Logger logger = LoggerFactory.getLogger(Main.class);
>
> private final long start;
>
> public Main()
> throws JoranException
> {
> start = new Date().getTime();
> LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
> JoranConfigurator configurator = new JoranConfigurator();
> lc.shutdownAndReset();
> configurator.setContext(lc);
> configurator.doConfigure(LOGGER_CONFIGURATION_FILE);
> }
>
> public void start()
> {
> ScheduledThreadPoolExecutor ex1 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex2 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex3 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex4 = new ScheduledThreadPoolExecutor(1);
> ScheduledThreadPoolExecutor ex5 = new ScheduledThreadPoolExecutor(1);
> ex1.scheduleAtFixedRate(new Task("EX1"), 10, 10, TimeUnit.MICROSECONDS);
> ex2.scheduleAtFixedRate(new Task("EX2"), 10, 10, TimeUnit.MICROSECONDS);
> ex3.scheduleAtFixedRate(new Task("EX3"), 10, 10, TimeUnit.MICROSECONDS);
> ex4.scheduleAtFixedRate(new Task("EX4"), 10, 10, TimeUnit.MICROSECONDS);
> ex5.scheduleAtFixedRate(new Task("EX5"), 10, 10, TimeUnit.MICROSECONDS);
>
> super.start();
> }
>
> public void run()
> {
> try
> {
> while(true)
> {
> logger.debug("[MAIN] {}", new Date().getTime() - start);
> Thread.sleep(10);
> }
> }
> catch (InterruptedException e)
> {
> logger.info("[MAIN]: Interrupted: {}", e.getMessage());
> }
> }
>
> public static void main(String[] args)
> {
> try
> {
> Main main = new Main();
> main.start();
> }
> catch (JoranException e)
> {
> System.out.println("Failed to load application: " + e.getMessage());
> }
> }
> }
> -------------------------------
> Task.java
> -------------------------------
> import java.util.Date;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> public class Task implements Runnable
> {
> private final Logger logger = LoggerFactory.getLogger(Task.class);
> private final Logger logger_main = LoggerFactory.getLogger(Main.class);
> private final String name;
> private final long start;
>
> public Task(final String name)
> {
> this.name = name;
> start = new Date().getTime();
> }
> public void run()
> {
> logger.debug("[{}] {}", name, new Date().getTime() - start);
> logger_main.debug("[MAIN] - [{}] {}", name, new Date().getTime() - start);
> }
> }
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
1
0
14 Nov '08
Author: ceki
Date: Fri Nov 14 15:21:57 2008
New Revision: 1972
Added:
logback/trunk/logback-classic/src/test/generateLogsInSafeMode.sh
- copied, changed from r1971, /logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh
Removed:
logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh
Modified:
logback/trunk/logback-classic/src/test/allInOneSafeMode.sh
logback/trunk/logback-classic/src/test/checkResults.sh
Log:
ongoing work
Modified: logback/trunk/logback-classic/src/test/allInOneSafeMode.sh
==============================================================================
--- logback/trunk/logback-classic/src/test/allInOneSafeMode.sh (original)
+++ logback/trunk/logback-classic/src/test/allInOneSafeMode.sh Fri Nov 14 15:21:57 2008
@@ -1,8 +1,12 @@
+# Use this script both generate and check the results. It only works
+# if there is only one instance of this script
+
echo "File name $1"
echo "run length $2"
+
#On windows
#CLASSPATH="${CLASSPATH};./target/classes/"
#CLASSPATH="${CLASSPATH};./target/test-classes/"
@@ -15,11 +19,11 @@
#CLASSPATH="${CLASSPATH}:../logback-core/target/classes"
#CLASSPATH="${CLASSPATH}:../logback-examples/lib/slf4j-api-1.5.5.jar"
-#if [ -f $1 ]
-#then
-# echo Removing $1 before tests
-# rm $1;
-#fi
+if [ -f $1 ]
+then
+ echo Removing $1 before tests
+ rm $1;
+fi
if [ $# -lt 3 ]
then
Modified: logback/trunk/logback-classic/src/test/checkResults.sh
==============================================================================
--- logback/trunk/logback-classic/src/test/checkResults.sh (original)
+++ logback/trunk/logback-classic/src/test/checkResults.sh Fri Nov 14 15:21:57 2008
@@ -1,3 +1,7 @@
+# Use this script to check the output generated by
+# the generateLogsInSafeMode.sh script
+# Note that you can pass multiple stamps
+
echo "File name $1"
echo "run length $2"
Copied: logback/trunk/logback-classic/src/test/generateLogsInSafeMode.sh (from r1971, /logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh)
==============================================================================
--- /logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh (original)
+++ logback/trunk/logback-classic/src/test/generateLogsInSafeMode.sh Fri Nov 14 15:21:57 2008
@@ -15,15 +15,10 @@
#CLASSPATH="${CLASSPATH}:../logback-core/target/classes"
#CLASSPATH="${CLASSPATH}:../logback-examples/lib/slf4j-api-1.5.5.jar"
-#if [ -f $1 ]
-#then
-# echo Removing $1 before tests
-# rm $1;
-#fi
if [ $# -lt 3 ]
then
- echo "Usage: generateInSafeMode.sh filename runLen stamp0 ... stampN"
+ echo "Usage: generateLogsInSafeMode.sh filename runLen stamp0 ... stampN"
exit 1;
fi
1
0
14 Nov '08
Author: ceki
Date: Fri Nov 14 15:15:42 2008
New Revision: 1971
Added:
logback/trunk/logback-classic/src/test/allInOneSafeMode.sh
- copied unchanged from r1970, /logback/trunk/logback-classic/src/test/testSafeMode.sh
logback/trunk/logback-classic/src/test/checkResults.sh
logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh
Removed:
logback/trunk/logback-classic/src/test/testSafeMode.sh
Log:
- ongoing work
Added: logback/trunk/logback-classic/src/test/checkResults.sh
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/checkResults.sh Fri Nov 14 15:15:42 2008
@@ -0,0 +1,16 @@
+echo "File name $1"
+echo "run length $2"
+
+if [ $# -lt 3 ]
+then
+ echo "Usage: checkResults.sh filename runLen stamp0 ... stampN"
+ exit 1;
+fi
+
+FILENAME=$1
+LEN=$2
+
+shift 2
+
+echo Checking results...
+java ch.qos.logback.classic.multiJVM.Checker $LEN $FILENAME $*
Added: logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/gerateLogFileInSafeMode.sh Fri Nov 14 15:15:42 2008
@@ -0,0 +1,45 @@
+echo "File name $1"
+echo "run length $2"
+
+
+
+#On windows
+#CLASSPATH="${CLASSPATH};./target/classes/"
+#CLASSPATH="${CLASSPATH};./target/test-classes/"
+#CLASSPATH="${CLASSPATH};../logback-core/target/classes"
+#CLASSPATH="${CLASSPATH};../logback-examples/lib/slf4j-api-1.5.5.jar"
+
+# On Unix
+#CLASSPATH="${CLASSPATH}:./target/classes/"
+#CLASSPATH="${CLASSPATH}:./target/test-classes/"
+#CLASSPATH="${CLASSPATH}:../logback-core/target/classes"
+#CLASSPATH="${CLASSPATH}:../logback-examples/lib/slf4j-api-1.5.5.jar"
+
+#if [ -f $1 ]
+#then
+# echo Removing $1 before tests
+# rm $1;
+#fi
+
+if [ $# -lt 3 ]
+then
+ echo "Usage: generateInSafeMode.sh filename runLen stamp0 ... stampN"
+ exit 1;
+fi
+
+FILENAME=$1
+LEN=$2
+
+shift 2
+
+for stamp in $@
+do
+ echo running safe mode with $stamp
+ java ch.qos.logback.classic.multiJVM.SafeModeFileAppender $stamp $LEN $FILENAME &
+done
+
+wait
+
+echo "To test the results issue the following command"
+echo "./checkResults.sh $FILENAME $LEN $*"
+
1
0
14 Nov '08
Author: ceki
Date: Fri Nov 14 11:52:06 2008
New Revision: 1970
Modified:
logback/trunk/logback-classic/src/test/testSafeMode.sh
Log:
- we have to manually delete the log file when testing
from multiple JVM on different hosts
Modified: logback/trunk/logback-classic/src/test/testSafeMode.sh
==============================================================================
--- logback/trunk/logback-classic/src/test/testSafeMode.sh (original)
+++ logback/trunk/logback-classic/src/test/testSafeMode.sh Fri Nov 14 11:52:06 2008
@@ -15,11 +15,11 @@
#CLASSPATH="${CLASSPATH}:../logback-core/target/classes"
#CLASSPATH="${CLASSPATH}:../logback-examples/lib/slf4j-api-1.5.5.jar"
-if [ -f $1 ]
-then
- echo Removing $1 before tests
- rm $1;
-fi
+#if [ -f $1 ]
+#then
+# echo Removing $1 before tests
+# rm $1;
+#fi
if [ $# -lt 3 ]
then
1
0
svn commit: r1968 - in logback/trunk: logback-classic/src/test/java/ch/qos/logback/classic/multiJVM logback-core/src/main/java/ch/qos/logback/core logback-examples/src/main/java/chapter4
by noreply.ceki@qos.ch 13 Nov '08
by noreply.ceki@qos.ch 13 Nov '08
13 Nov '08
Author: ceki
Date: Thu Nov 13 18:54:51 2008
New Revision: 1968
Added:
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/Checker.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/LoggingThread.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/SafeModeFileAppender.java
Modified:
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java
logback/trunk/logback-examples/src/main/java/chapter4/IO.java
Log:
LBCORE-29
Experimental support for multiple JVM's writing to the same file
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/Checker.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/Checker.java Thu Nov 13 18:54:51 2008
@@ -0,0 +1,89 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.multiJVM;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Checker {
+
+ static long LEN;
+ static String FILENAME;
+
+ static void usage(String msg) {
+ System.err.println(msg);
+ System.err
+ .println("Usage: java "
+ + Checker.class.getName()
+ + " runLength filename stamp0 stamp1 ..\n"
+ + " runLength (integer) the number of logs to generate perthread\n"
+ + " filename (string) the filename where to write\n"
+ + " stamp0 JVM instance stamp0\n"
+ + " stamp1 JVM instance stamp1\n");
+ System.exit(1);
+ }
+
+ public static void main(String[] argv) throws Exception {
+ if (argv.length < 3) {
+ usage("Wrong number of arguments.");
+ }
+
+ LEN = Integer.parseInt(argv[0]);
+ FILENAME = argv[1];
+
+ for (int i = 2; i < argv.length; i++) {
+ check(argv[i], FILENAME, true);
+ }
+ }
+
+ static void check(String stamp, String filename, boolean safetyMode)
+ throws Exception {
+
+ FileReader fr = new FileReader(FILENAME);
+ BufferedReader br = new BufferedReader(fr);
+
+ String regExp = "^" + stamp + " DEBUG - " + LoggingThread.msgLong
+ + " (\\d+)$";
+ // System.out.println(regExp);
+ Pattern p = Pattern.compile(regExp);
+
+ String line;
+ int expected = 0;
+ while ((line = br.readLine()) != null) {
+ // System.out.println(line);
+ Matcher m = p.matcher(line);
+ if (m.matches()) {
+ String g = m.group(1);
+ int num = Integer.parseInt(g);
+ if (num != expected) {
+ System.err.println("ERROR: out of sequence line: ");
+ System.err.println(line);
+ return;
+ }
+ expected++;
+ }
+ }
+
+ if (expected != LEN) {
+ System.err.println("ERROR: For JVM stamp " + stamp + " found " + expected
+ + " was expecting " + LEN);
+ } else {
+ System.out.println("For JVM stamp " + stamp + " found " + LEN
+ + " lines in correct sequence");
+ }
+ fr.close();
+ br.close();
+
+ }
+
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/LoggingThread.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/LoggingThread.java Thu Nov 13 18:54:51 2008
@@ -0,0 +1,45 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.multiJVM;
+
+import org.slf4j.Logger;
+
+public class LoggingThread extends Thread {
+ static String msgLong = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+
+ final long len;
+ final Logger logger;
+ private double durationPerLog;
+
+ public LoggingThread(Logger logger, long len) {
+ this.logger = logger;
+ this.len = len;
+ }
+
+ public void run() {
+ long before = System.nanoTime();
+ for (int i = 0; i < len; i++) {
+ logger.debug(msgLong + " " + i);
+// try {
+// Thread.sleep(100);
+// } catch (InterruptedException e) {
+// }
+ }
+ // in microseconds
+ durationPerLog = (System.nanoTime() - before) / (len * 1000.0);
+ }
+
+ public double getDurationPerLogInMicroseconds() {
+ return durationPerLog;
+ }
+
+
+}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/SafeModeFileAppender.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/multiJVM/SafeModeFileAppender.java Thu Nov 13 18:54:51 2008
@@ -0,0 +1,95 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.multiJVM;
+
+import org.slf4j.Logger;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.FileAppender;
+
+/**
+ * An application to write to a file using a FileAppender in safe mode.
+ *
+ * @author Ceki Gulcu
+ *
+ */
+public class SafeModeFileAppender {
+
+ static long LEN;
+ static String FILENAME;
+ static String STAMP;
+
+ static public void main(String[] argv) throws Exception {
+ if (argv.length != 3) {
+ usage("Wrong number of arguments.");
+ }
+
+ STAMP = argv[0];
+ LEN = Integer.parseInt(argv[1]);
+ FILENAME = argv[2];
+ writeContinously(STAMP, FILENAME, true);
+ }
+
+ static void usage(String msg) {
+ System.err.println(msg);
+ System.err.println("Usage: java " + SafeModeFileAppender.class.getName()
+ + " stamp runLength filename\n" + " stamp JVM instance stamp\n"
+ + " runLength (integer) the number of logs to generate perthread"
+ + " filename (string) the filename where to write\n");
+ System.exit(1);
+ }
+
+ static LoggerContext buildLoggerContext(String stamp, String filename,
+ boolean safetyMode) {
+ LoggerContext loggerContext = new LoggerContext();
+
+ FileAppender<LoggingEvent> fa = new FileAppender<LoggingEvent>();
+
+ PatternLayout patternLayout = new PatternLayout();
+ patternLayout.setPattern(stamp + " %5p - %m%n");
+ patternLayout.setContext(loggerContext);
+ patternLayout.start();
+
+ fa.setLayout(patternLayout);
+ fa.setFile(filename);
+ fa.setAppend(true);
+ fa.setImmediateFlush(true);
+ fa.setBufferedIO(false);
+ fa.setSafeMode(safetyMode);
+ fa.setContext(loggerContext);
+ fa.start();
+
+ ch.qos.logback.classic.Logger root = loggerContext
+ .getLogger(LoggerContext.ROOT_NAME);
+ root.addAppender(fa);
+
+ return loggerContext;
+ }
+
+ static void writeContinously(String stamp, String filename, boolean safetyMode)
+ throws Exception {
+ LoggerContext lc = buildLoggerContext(stamp, filename, safetyMode);
+ Logger logger = lc.getLogger(SafeModeFileAppender.class);
+
+ long before = System.nanoTime();
+ for (int i = 0; i < LEN; i++) {
+ logger.debug(LoggingThread.msgLong + " " + i);
+ }
+ lc.stop();
+ double durationPerLog = (System.nanoTime() - before) / (LEN * 1000.0);
+
+ System.out.println("Average duration of " + (durationPerLog)
+ + " microseconds per log. Safety mode " + safetyMode);
+ System.out.println("------------------------------------------------");
+ }
+}
Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java (original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/FileAppender.java Thu Nov 13 18:54:51 2008
@@ -14,6 +14,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
import ch.qos.logback.core.status.ErrorStatus;
import ch.qos.logback.core.status.InfoStatus;
@@ -51,6 +53,10 @@
*/
protected int bufferSize = 8 * 1024;
+ private boolean safeMode = false;
+
+ private FileChannel fileChannel = null;
+
/**
* As in most cases, the default constructor does nothing.
*/
@@ -149,7 +155,11 @@
}
}
- Writer w = createWriter(new FileOutputStream(fileName, append));
+ FileOutputStream fileOutputStream = new FileOutputStream(fileName, append);
+ if (safeMode) {
+ fileChannel = fileOutputStream.getChannel();
+ }
+ Writer w = createWriter(fileOutputStream);
if (bufferedIO) {
w = new BufferedWriter(w, bufferSize);
}
@@ -172,7 +182,48 @@
this.bufferSize = bufferSize;
}
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public boolean isSafeMode() {
+ return safeMode;
+ }
+
+ public void setSafeMode(boolean safeMode) {
+ this.safeMode = safeMode;
+ }
+
public void setAppend(boolean append) {
this.append = append;
}
+
+ @Override
+ protected void writerWrite(String s, boolean flush) throws IOException {
+ if (safeMode && fileChannel != null) {
+ FileLock fileLock = null;
+ try {
+ fileLock = fileChannel.lock();
+ long position = fileChannel.position();
+ long size = fileChannel.size();
+ if(size != position) {
+ //System.out.println("position size mismatch, pos ="+position+" size="+size);
+ fileChannel.position(size);
+ } else {
+ //System.out.println(position+" size="+size);
+ }
+ super.writerWrite(s, true);
+ } finally {
+ if (fileLock != null) {
+ fileLock.release();
+ }
+ }
+ } else {
+ super.writerWrite(s, flush);
+ }
+ }
}
Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java (original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/WriterAppender.java Thu Nov 13 18:54:51 2008
@@ -36,16 +36,14 @@
* is a good chance that the last few logs events are not actually written to
* persistent media if and when the application crashes.
*
- * <p>
- * The <code>immediateFlush</code> variable is set to <code>true</code> by
- * default.
+ * <p> The <code>immediateFlush</code> variable is set to <code>true</code>
+ * by default.
*/
private boolean immediateFlush = true;
/**
- * The encoding to use when opening an InputStream.
- * <p>
- * The <code>encoding</code> variable is set to <code>null</null> by default
+ * The encoding to use when opening an InputStream. <p> The
+ * <code>encoding</code> variable is set to <code>null</null> by default
* which results in the use of the system's default encoding.
*/
private String encoding;
@@ -71,14 +69,12 @@
* If the <b>ImmediateFlush</b> option is set to <code>true</code>, the
* appender will flush at the end of each write. This is the default behavior.
* If the option is set to <code>false</code>, then the underlying stream
- * can defer writing to physical medium to a later time.
- * <p>
- * Avoiding the flush operation at the end of each append results in a
- * performance gain of 10 to 20 percent. However, there is safety tradeoff
- * involved in skipping flushing. Indeed, when flushing is skipped, then it is
- * likely that the last few log events will not be recorded on disk when the
- * application exits. This is a high price to pay even for a 20% performance
- * gain.
+ * can defer writing to physical medium to a later time. <p> Avoiding the
+ * flush operation at the end of each append results in a performance gain of
+ * 10 to 20 percent. However, there is safety tradeoff involved in skipping
+ * flushing. Indeed, when flushing is skipped, then it is likely that the last
+ * few log events will not be recorded on disk when the application exits.
+ * This is a high price to pay even for a 20% performance gain.
*/
public void setImmediateFlush(boolean value) {
immediateFlush = value;
@@ -127,8 +123,7 @@
* Stop this appender instance. The underlying stream or writer is also
* closed.
*
- * <p>
- * Stopped appenders cannot be reused.
+ * <p> Stopped appenders cannot be reused.
*/
public synchronized void stop() {
closeWriter();
@@ -205,21 +200,17 @@
void writeHeader() {
if (layout != null && (this.writer != null)) {
try {
-
- String h = layout.getFileHeader();
- if (h != null) {
- this.writer.write(h);
- }
- String ph = layout.getPresentationHeader();
- if (ph != null) {
- this.writer.write(ph);
- }
- // If at least one of file header or presentation header were not null, then append a line separator.
- // This should be useful in most cases and should not hurt.
- if ((h != null) || (ph != null)) {
- this.writer.write(Layout.LINE_SEP);
- this.writer.flush();
+ StringBuilder sb = new StringBuilder();
+ appendIfNotNull(sb, layout.getFileHeader());
+ appendIfNotNull(sb, layout.getPresentationHeader());
+ if (sb.length() > 0) {
+ sb.append(Layout.LINE_SEP);
+ // If at least one of file header or presentation header were not
+ // null, then append a line separator.
+ // This should be useful in most cases and should not hurt.
+ writerWrite(sb.toString(), true);
}
+
} catch (IOException ioe) {
this.started = false;
addStatus(new ErrorStatus("Failed to write header for appender named ["
@@ -228,19 +219,21 @@
}
}
+ private void appendIfNotNull(StringBuilder sb, String s) {
+ if (s != null) {
+ sb.append(s);
+ }
+ }
+
void writeFooter() {
if (layout != null && this.writer != null) {
try {
- String pf = layout.getPresentationFooter();
- if (pf != null) {
- this.writer.write(pf);
- }
- String h = layout.getFileFooter();
- if (h != null) {
- this.writer.write(h);
+ StringBuilder sb = new StringBuilder();
+ appendIfNotNull(sb, layout.getPresentationFooter());
+ appendIfNotNull(sb, layout.getFileFooter());
+ if (sb.length() > 0) {
+ writerWrite(sb.toString(), true); // force flush
}
- // flushing is mandatory if the writer is not later closed.
- this.writer.flush();
} catch (IOException ioe) {
this.started = false;
addStatus(new ErrorStatus("Failed to write footer for appender named ["
@@ -250,10 +243,9 @@
}
/**
- * <p>
- * Sets the Writer where the log output will go. The specified Writer must be
- * opened by the user and be writable. The <code>java.io.Writer</code> will
- * be closed when the appender instance is closed.
+ * <p> Sets the Writer where the log output will go. The specified Writer must
+ * be opened by the user and be writable. The <code>java.io.Writer</code>
+ * will be closed when the appender instance is closed.
*
* @param writer
* An already opened Writer.
@@ -266,11 +258,16 @@
writeHeader();
}
+ protected void writerWrite(String s, boolean flush) throws IOException {
+ this.writer.write(s);
+ if (flush) {
+ this.writer.flush();
+ }
+ }
+
/**
- * Actual writing occurs here.
- * <p>
- * Most subclasses of <code>WriterAppender</code> will need to override this
- * method.
+ * Actual writing occurs here. <p> Most subclasses of
+ * <code>WriterAppender</code> will need to override this method.
*
* @since 0.9.0
*/
@@ -280,10 +277,7 @@
}
try {
- this.writer.write(this.layout.doLayout(event));
- if (this.immediateFlush) {
- this.writer.flush();
- }
+ writerWrite(this.layout.doLayout(event), this.immediateFlush);
} catch (IOException ioe) {
// as soon as an exception occurs, move to non-started state
// and add a single ErrorStatus to the SM.
Modified: logback/trunk/logback-examples/src/main/java/chapter4/IO.java
==============================================================================
--- logback/trunk/logback-examples/src/main/java/chapter4/IO.java (original)
+++ logback/trunk/logback-examples/src/main/java/chapter4/IO.java Thu Nov 13 18:54:51 2008
@@ -1,7 +1,7 @@
/**
- * Logback: the reliable, generic, fast and flexible logging framework.
+ * Logback: the generic, reliable, fast and flexible logging framework.
*
- * Copyright (C) 1999-2006, QOS.ch
+ * Copyright (C) 2000-2008, QOS.ch
*
* This library is free software, you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
@@ -117,7 +117,7 @@
threads[i].start();
}
- // wait for them to stop, compute the average throughputs
+ // wait for them to stop, compute the average throughput
double sum = 0;
for (int i = 0; i < numThreads; i++) {
@@ -131,8 +131,8 @@
counterThread.join();
}
- System.out.println("On average throughput of " + (sum / numThreads) +
- " logs per millisecond.");
+ System.out.println("On average throughput of " + (sum / numThreads)*1000 +
+ " logs per microsecond.");
System.out.println("------------------------------------------------");
}
@@ -143,16 +143,16 @@
msg = msgLong;
}
- long before = System.currentTimeMillis();
+ long before = System.nanoTime();
for (int i = 0; i < len; i++) {
logger.debug(msg);
}
- throughput = (len * 1.0) / (System.currentTimeMillis() - before);
+ throughput = (len * 1.0) / (System.nanoTime() - before);
System.out.println(getName() + ", buffered: " + buffered +
", immediateFlush: " + immediateFlush + ", throughput: " + throughput +
- " logs per millisecond.");
+ " logs per nanosecond.");
}
}
@@ -162,14 +162,14 @@
public double counter = 0;
public void run() {
- long before = System.currentTimeMillis();
+ long before = System.nanoTime();
while (!interrupted) {
- counter += 0.001;
+ counter += 1.0;
}
- double tput = (counter * 1.0) / (System.currentTimeMillis() - before);
+ double tput = (counter * 1.0) / (System.nanoTime() - before);
System.out.println("Counter thread " + getName() +
- " incremented counter by " + tput + " per millisecond.");
+ " incremented counter by " + tput + " per nanosecond.");
}
}
2
1
13 Nov '08
Author: ceki
Date: Thu Nov 13 18:57:21 2008
New Revision: 1969
Added:
logback/trunk/logback-classic/src/test/testSafeMode.sh
Log:
LBCORE-29
Experimental support for multiple JVM's writing to the same file
Added: logback/trunk/logback-classic/src/test/testSafeMode.sh
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/testSafeMode.sh Thu Nov 13 18:57:21 2008
@@ -0,0 +1,44 @@
+echo "File name $1"
+echo "run length $2"
+
+
+
+#On windows
+#CLASSPATH="${CLASSPATH};./target/classes/"
+#CLASSPATH="${CLASSPATH};./target/test-classes/"
+#CLASSPATH="${CLASSPATH};../logback-core/target/classes"
+#CLASSPATH="${CLASSPATH};../logback-examples/lib/slf4j-api-1.5.5.jar"
+
+# On Unix
+#CLASSPATH="${CLASSPATH}:./target/classes/"
+#CLASSPATH="${CLASSPATH}:./target/test-classes/"
+#CLASSPATH="${CLASSPATH}:../logback-core/target/classes"
+#CLASSPATH="${CLASSPATH}:../logback-examples/lib/slf4j-api-1.5.5.jar"
+
+if [ -f $1 ]
+then
+ echo Removing $1 before tests
+ rm $1;
+fi
+
+if [ $# -lt 3 ]
+then
+ echo "Usage: testSafeMode.sh filename runLen stamp0 ... stampN"
+ exit 1;
+fi
+
+FILENAME=$1
+LEN=$2
+
+shift 2
+
+for stamp in $@
+do
+ echo running safe mode with $stamp
+ java ch.qos.logback.classic.multiJVM.SafeModeFileAppender $stamp $LEN $FILENAME &
+done
+
+wait
+
+echo Checking results...
+java ch.qos.logback.classic.multiJVM.Checker $LEN $FILENAME $*
1
0
svn commit: r1967 - in logback/trunk: logback-classic/src/main/java/ch/qos/logback/classic/pattern logback-classic/src/test/java/ch/qos/logback/classic/pattern logback-site/src/site/pages logback-site/src/site/pages/css logback-site/src/site/pages/manual
by noreply.ceki@qos.ch 12 Nov '08
by noreply.ceki@qos.ch 12 Nov '08
12 Nov '08
Author: ceki
Date: Wed Nov 12 19:40:35 2008
New Revision: 1967
Added:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameOnlyAbbreviator.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviator.java
- copied, changed from r1899, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameAbbreviator.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviatorTest.java
- copied, changed from r1899, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ClassNameAbbreviatorTest.java
Removed:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameAbbreviator.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ClassNameAbbreviatorTest.java
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/NamedConverter.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ConverterTest.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/PackageTest.java
logback/trunk/logback-site/src/site/pages/css/common.css
logback/trunk/logback-site/src/site/pages/manual/layouts.html
logback/trunk/logback-site/src/site/pages/news.html
Log:
The logger and class name converters now consider zero as
having special meaning, and will return the simple class name,
removing the package name prefix. This feature was asked by
Silvano Maffeis.
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameOnlyAbbreviator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameOnlyAbbreviator.java Wed Nov 12 19:40:35 2008
@@ -0,0 +1,30 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.pattern;
+
+import ch.qos.logback.classic.ClassicGlobal;
+
+/**
+ * This abbreviator returns the class name from a fully qualified class name,
+ * removing the leading package name.
+ *
+ * @author Ceki Gülcü
+ */
+public class ClassNameOnlyAbbreviator implements Abbreviator {
+
+ public String abbreviate(String fqClassName) {
+ int lastIndex = fqClassName.lastIndexOf(ClassicGlobal.DOT);
+ if (lastIndex != -1) {
+ return fqClassName.substring(lastIndex + 1, fqClassName.length());
+ } else {
+ return fqClassName;
+ }
+ }
+}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/NamedConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/NamedConverter.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/NamedConverter.java Wed Nov 12 19:40:35 2008
@@ -29,8 +29,10 @@
if (optStr != null) {
try {
int targetLen = Integer.parseInt(optStr);
- if (targetLen > 0) {
- abbreviator = new ClassNameAbbreviator(targetLen);
+ if (targetLen == 0) {
+ abbreviator = new ClassNameOnlyAbbreviator();
+ } else if (targetLen > 0) {
+ abbreviator = new TargetLengthBasedClassNameAbbreviator(targetLen);
}
} catch (NumberFormatException nfe) {
// FIXME: better error reporting
Copied: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviator.java (from r1899, /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameAbbreviator.java)
==============================================================================
--- /logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ClassNameAbbreviator.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviator.java Wed Nov 12 19:40:35 2008
@@ -11,7 +11,7 @@
import ch.qos.logback.classic.ClassicGlobal;
-public class ClassNameAbbreviator implements Abbreviator {
+public class TargetLengthBasedClassNameAbbreviator implements Abbreviator {
static private final int BUF_LIMIT = 256;
static private final int MAX_DOTS = 12;
@@ -19,19 +19,19 @@
final int targetLength;
StringBuffer buf;
- public ClassNameAbbreviator(int targetLength) {
+ public TargetLengthBasedClassNameAbbreviator(int targetLength) {
this.targetLength = targetLength;
buf = new StringBuffer(targetLength);
}
- public String abbreviate(String className) {
- if (className == null) {
+ public String abbreviate(String fqClassName) {
+ if (fqClassName == null) {
throw new IllegalArgumentException("Class name may not be null");
}
- int inLen = className.length();
+ int inLen = fqClassName.length();
if (inLen < targetLength) {
- return className;
+ return fqClassName;
}
if (buf.capacity() > BUF_LIMIT) {
@@ -42,30 +42,31 @@
int[] dotArray = new int[MAX_DOTS];
int[] lengthArray = new int[MAX_DOTS];
- int dotCount = computeIndexes(className, dotArray);
+ int dotCount = computeIndexes(fqClassName, dotArray);
- //System.out.println();
- //System.out.println("Dot count for [" + className + "] is " + dotCount);
+ // System.out.println();
+ // System.out.println("Dot count for [" + className + "] is " + dotCount);
// if there are not dots than abbreviation is not possible
if (dotCount == 0) {
- return className;
+ return fqClassName;
}
- //printArray("dotArray: ", dotArray);
- computeLengthArray(className, dotArray, lengthArray, dotCount);
- //printArray("lengthArray: ", lengthArray);
+ // printArray("dotArray: ", dotArray);
+ computeLengthArray(fqClassName, dotArray, lengthArray, dotCount);
+ // printArray("lengthArray: ", lengthArray);
for (int i = 0; i <= dotCount; i++) {
if (i == 0) {
- buf.append(className.substring(0, lengthArray[i] - 1));
+ buf.append(fqClassName.substring(0, lengthArray[i] - 1));
} else {
- buf.append(className.substring(dotArray[i - 1], dotArray[i - 1]
+ buf.append(fqClassName.substring(dotArray[i - 1], dotArray[i - 1]
+ lengthArray[i]));
}
- //System.out.println("i=" + i + ", buf=" + buf);
+ // System.out.println("i=" + i + ", buf=" + buf);
}
return buf.toString();
}
+
static int computeIndexes(final String className, int[] dotArray) {
int dotCount = 0;
int k = 0;
@@ -85,9 +86,9 @@
void computeLengthArray(final String className, int[] dotArray,
int[] lengthArray, int dotCount) {
int toTrim = className.length() - targetLength;
- //System.out.println("toTrim=" + toTrim);
-
- //int toTrimAvarage = 0;
+ // System.out.println("toTrim=" + toTrim);
+
+ // int toTrimAvarage = 0;
int len;
for (int i = 0; i < dotCount; i++) {
@@ -99,7 +100,7 @@
// System.out.println("i=" + i + ", available = " + available);
len = (available < 1) ? available : 1;
- //System.out.println("i=" + i + ", toTrim = " + toTrim);
+ // System.out.println("i=" + i + ", toTrim = " + toTrim);
if (toTrim > 0) {
len = (available < 1) ? available : 1;
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ConverterTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ConverterTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ConverterTest.java Wed Nov 12 19:40:35 2008
@@ -9,11 +9,13 @@
*/
package ch.qos.logback.classic.pattern;
+import static org.junit.Assert.*;
+
import java.util.ArrayList;
import java.util.List;
-import junit.framework.TestCase;
-
+import org.junit.Before;
+import org.junit.Test;
import org.slf4j.MDC;
import org.slf4j.MarkerFactory;
@@ -27,29 +29,16 @@
import ch.qos.logback.core.pattern.DynamicConverter;
import ch.qos.logback.core.pattern.FormatInfo;
-public class ConverterTest extends TestCase {
+public class ConverterTest {
LoggerContext lc = new LoggerContext();
Logger logger = lc.getLogger(ConverterTest.class);
LoggingEvent le;
List<String> optionList = new ArrayList<String>();
- public ConverterTest(String arg0) {
- super(arg0);
-
- Exception rootEx = getException("Innermost", null);
- Exception nestedEx = getException("Nested", rootEx);
-
- Exception ex = new Exception("Bogus exception", nestedEx);
-
- le = makeLoggingEvent(ex);
- // ex.printStackTrace();
- }
-
// The LoggingEvent is massaged with an FCQN of FormattingConverter. This
- // forces the
- // returned caller information to match the caller stack for this this
- // particular test.
+ // forces the returned caller information to match the caller stack for this
+ // this particular test.
LoggingEvent makeLoggingEvent(Exception ex) {
return new LoggingEvent(
ch.qos.logback.core.pattern.FormattingConverter.class.getName(),
@@ -60,24 +49,28 @@
return new Exception(msg, cause);
}
- protected void setUp() throws Exception {
- super.setUp();
- }
+ @Before
+ public void setUp() throws Exception {
+ Exception rootEx = getException("Innermost", null);
+ Exception nestedEx = getException("Nested", rootEx);
- protected void tearDown() throws Exception {
- super.tearDown();
+ Exception ex = new Exception("Bogus exception", nestedEx);
+
+ le = makeLoggingEvent(ex);
}
+ @Test
public void testLineOfCaller() {
{
DynamicConverter<LoggingEvent> converter = new LineOfCallerConverter();
StringBuffer buf = new StringBuffer();
converter.write(buf, le);
// the number below should be the line number of the previous line
- assertEquals("75", buf.toString());
+ assertEquals("67", buf.toString());
}
}
+ @Test
public void testLevel() {
{
DynamicConverter<LoggingEvent> converter = new LevelConverter();
@@ -94,6 +87,7 @@
}
}
+ @Test
public void testThread() {
DynamicConverter<LoggingEvent> converter = new ThreadConverter();
StringBuffer buf = new StringBuffer();
@@ -102,6 +96,7 @@
assertTrue(buf.toString().matches(regex));
}
+ @Test
public void testMessage() {
DynamicConverter<LoggingEvent> converter = new MessageConverter();
StringBuffer buf = new StringBuffer();
@@ -109,6 +104,7 @@
assertEquals("Some message", buf.toString());
}
+ @Test
public void testLineSeparator() {
DynamicConverter<LoggingEvent> converter = new LineSeparatorConverter();
StringBuffer buf = new StringBuffer();
@@ -116,12 +112,12 @@
assertEquals(CoreConstants.LINE_SEPARATOR, buf.toString());
}
+ @Test
public void testException() {
{
DynamicConverter<LoggingEvent> converter = new ThrowableProxyConverter();
StringBuffer buf = new StringBuffer();
converter.write(buf, le);
- // System.out.println(buf);
}
{
@@ -130,10 +126,10 @@
converter.setOptionList(this.optionList);
StringBuffer buf = new StringBuffer();
converter.write(buf, le);
- // System.out.println(buf);
}
}
+ @Test
public void testLogger() {
{
DynamicConverter<LoggingEvent> converter = new LoggerConverter();
@@ -151,35 +147,44 @@
converter.write(buf, le);
assertEquals("c.q.l.c.p.ConverterTest", buf.toString());
}
- }
- public void testClass() {
{
- DynamicConverter<LoggingEvent> converter = new ClassOfCallerConverter();
+ DynamicConverter<LoggingEvent> converter = new LoggerConverter();
+ this.optionList.clear();
+ this.optionList.add("0");
+ converter.setOptionList(this.optionList);
+ converter.start();
StringBuffer buf = new StringBuffer();
converter.write(buf, le);
- assertEquals(this.getClass().getName(), buf.toString());
+ assertEquals("ConverterTest", buf.toString());
}
}
+ @Test
+ public void testClass() {
+ DynamicConverter<LoggingEvent> converter = new ClassOfCallerConverter();
+ StringBuffer buf = new StringBuffer();
+ converter.write(buf, le);
+ assertEquals(this.getClass().getName(), buf.toString());
+ }
+
+ @Test
public void testMethodOfCaller() {
- {
- DynamicConverter<LoggingEvent> converter = new MethodOfCallerConverter();
- StringBuffer buf = new StringBuffer();
- converter.write(buf, le);
- assertEquals("testMethodOfCaller", buf.toString());
- }
+ DynamicConverter<LoggingEvent> converter = new MethodOfCallerConverter();
+ StringBuffer buf = new StringBuffer();
+ converter.write(buf, le);
+ assertEquals("testMethodOfCaller", buf.toString());
}
+ @Test
public void testFileOfCaller() {
- {
- DynamicConverter<LoggingEvent> converter = new FileOfCallerConverter();
- StringBuffer buf = new StringBuffer();
- converter.write(buf, le);
- assertEquals("ConverterTest.java", buf.toString());
- }
+ DynamicConverter<LoggingEvent> converter = new FileOfCallerConverter();
+ StringBuffer buf = new StringBuffer();
+ converter.write(buf, le);
+ assertEquals("ConverterTest.java", buf.toString());
}
+ @Test
public void testCallerData() {
{
DynamicConverter<LoggingEvent> converter = new CallerDataConverter();
@@ -262,42 +267,41 @@
}
+ @Test
public void testRelativeTime() throws Exception {
- {
- DynamicConverter<LoggingEvent> converter = new RelativeTimeConverter();
- StringBuffer buf0 = new StringBuffer();
- StringBuffer buf1 = new StringBuffer();
- LoggingEvent e0 = makeLoggingEvent(null);
- LoggingEvent e1 = makeLoggingEvent(null);
- converter.write(buf0, e0);
- converter.write(buf1, e1);
- assertEquals(buf0.toString(), buf1.toString());
- int rt0 = Integer.parseInt(buf0.toString());
- if (rt0 < 50) {
- fail("relative time should be > 50, but it is " + rt0);
- }
+ DynamicConverter<LoggingEvent> converter = new RelativeTimeConverter();
+ StringBuffer buf0 = new StringBuffer();
+ StringBuffer buf1 = new StringBuffer();
+ LoggingEvent e0 = makeLoggingEvent(null);
+ LoggingEvent e1 = makeLoggingEvent(null);
+ converter.write(buf0, e0);
+ converter.write(buf1, e1);
+ assertEquals(buf0.toString(), buf1.toString());
+ int rt0 = Integer.parseInt(buf0.toString());
+ if (rt0 < 50) {
+ fail("relative time should be > 50, but it is " + rt0);
}
}
+ @Test
public void testSyslogStart() throws Exception {
- {
- DynamicConverter<LoggingEvent> converter = new SyslogStartConverter();
- this.optionList.clear();
- this.optionList.add("MAIL");
- converter.setOptionList(this.optionList);
- converter.start();
+ DynamicConverter<LoggingEvent> converter = new SyslogStartConverter();
+ this.optionList.clear();
+ this.optionList.add("MAIL");
+ converter.setOptionList(this.optionList);
+ converter.start();
- LoggingEvent event = makeLoggingEvent(null);
+ LoggingEvent event = makeLoggingEvent(null);
- StringBuffer buf = new StringBuffer();
- converter.write(buf, event);
+ StringBuffer buf = new StringBuffer();
+ converter.write(buf, event);
- String expected = "<"
- + (SyslogConstants.LOG_MAIL + SyslogConstants.INFO_SEVERITY) + ">";
- assertTrue(buf.toString().startsWith(expected));
- }
+ String expected = "<"
+ + (SyslogConstants.LOG_MAIL + SyslogConstants.INFO_SEVERITY) + ">";
+ assertTrue(buf.toString().startsWith(expected));
}
+ @Test
public void testMDCConverter() throws Exception {
MDC.clear();
MDC.put("someKey", "someValue");
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/PackageTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/PackageTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/PackageTest.java Wed Nov 12 19:40:35 2008
@@ -10,6 +10,7 @@
package ch.qos.logback.classic.pattern;
+import junit.framework.JUnit4TestAdapter;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
@@ -18,8 +19,8 @@
public static Test suite() {
TestSuite suite = new TestSuite();
- suite.addTestSuite(ConverterTest.class);
- suite.addTestSuite(ClassNameAbbreviatorTest.class);
+ suite.addTest(new JUnit4TestAdapter(ConverterTest.class));
+ suite.addTest(new JUnit4TestAdapter(TargetLengthBasedClassNameAbbreviatorTest.class));
suite.addTestSuite(MDCConverterTest.class);
suite.addTestSuite(MarkerConverterTest.class);
return suite;
Copied: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviatorTest.java (from r1899, /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ClassNameAbbreviatorTest.java)
==============================================================================
--- /logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/ClassNameAbbreviatorTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/TargetLengthBasedClassNameAbbreviatorTest.java Wed Nov 12 19:40:35 2008
@@ -1,147 +1,143 @@
/**
- * LOGBack: the reliable, fast and flexible logging library for Java.
- *
- * Copyright (C) 1999-2006, QOS.ch
- *
- * This library is free software, you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
*/
package ch.qos.logback.classic.pattern;
-import junit.framework.TestCase;
+import static org.junit.Assert.*;
-import ch.qos.logback.classic.pattern.ClassNameAbbreviator;
+import org.junit.Test;
-public class ClassNameAbbreviatorTest extends TestCase {
+import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator;
- public ClassNameAbbreviatorTest(String arg0) {
- super(arg0);
- }
-
- protected void setUp() throws Exception {
- super.setUp();
- }
+public class TargetLengthBasedClassNameAbbreviatorTest {
- protected void tearDown() throws Exception {
- super.tearDown();
- }
+ @Test
public void testShortName() {
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(100);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(100);
String name = "hello";
assertEquals(name, abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(100);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(100);
String name = "hello.world";
assertEquals(name, abbreviator.abbreviate(name));
}
}
+ @Test
public void testNoDot() {
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "hello";
assertEquals(name, abbreviator.abbreviate(name));
}
+ @Test
public void testOneDot() {
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "hello.world";
assertEquals("h.world", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "h.world";
assertEquals("h.world", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = ".world";
assertEquals(".world", abbreviator.abbreviate(name));
}
}
+ @Test
public void testTwoDot() {
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "com.logback.Foobar";
assertEquals("c.l.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "c.logback.Foobar";
assertEquals("c.l.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "c..Foobar";
assertEquals("c..Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "..Foobar";
assertEquals("..Foobar", abbreviator.abbreviate(name));
}
}
-
+
+ @Test
public void test3Dot() {
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "com.logback.xyz.Foobar";
assertEquals("c.l.x.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(13);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(13);
String name = "com.logback.xyz.Foobar";
assertEquals("c.l.x.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(14);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(14);
String name = "com.logback.xyz.Foobar";
assertEquals("c.l.xyz.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(15);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(15);
String name = "com.logback.alligator.Foobar";
assertEquals("c.l.a.Foobar", abbreviator.abbreviate(name));
}
}
-
+ @Test
public void testXDot() {
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(21);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(21);
String name = "com.logback.wombat.alligator.Foobar";
assertEquals("c.l.w.a.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(22);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(22);
String name = "com.logback.wombat.alligator.Foobar";
assertEquals("c.l.w.alligator.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(1);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(1);
String name = "com.logback.wombat.alligator.tomato.Foobar";
assertEquals("c.l.w.a.t.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(21);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(21);
String name = "com.logback.wombat.alligator.tomato.Foobar";
assertEquals("c.l.w.a.tomato.Foobar", abbreviator.abbreviate(name));
}
{
- ClassNameAbbreviator abbreviator = new ClassNameAbbreviator(29);
+ TargetLengthBasedClassNameAbbreviator abbreviator = new TargetLengthBasedClassNameAbbreviator(29);
String name = "com.logback.wombat.alligator.tomato.Foobar";
assertEquals("c.l.w.alligator.tomato.Foobar", abbreviator.abbreviate(name));
}
Modified: logback/trunk/logback-site/src/site/pages/css/common.css
==============================================================================
--- logback/trunk/logback-site/src/site/pages/css/common.css (original)
+++ logback/trunk/logback-site/src/site/pages/css/common.css Wed Nov 12 19:40:35 2008
@@ -124,6 +124,11 @@
}
+/* apply to tr elements of tables which are both bodytable and dark */
+table[class="bodyTable dark"] tr {
+ background-color: #ddd;
+}
+
table.bodyTable tr.a {
background-color: #ddd;
}
@@ -178,6 +183,7 @@
color: red;
font-weight: bold;
}
+
.greenBold {
color: green;
font-weight: bold;
Modified: logback/trunk/logback-site/src/site/pages/manual/layouts.html
==============================================================================
--- logback/trunk/logback-site/src/site/pages/manual/layouts.html (original)
+++ logback/trunk/logback-site/src/site/pages/manual/layouts.html Wed Nov 12 19:40:35 2008
@@ -208,7 +208,8 @@
the logging request was sent.
</p>
<p>Here is the implementation of this class:</p>
-<div class="source"><pre>package chapter5;
+
+ <p class="source">package chapter5;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.LayoutBase;
@@ -247,7 +248,7 @@
sbuf.append(LINE_SEP);
return sbuf.toString();
}
-}</pre></div>
+}</p>
<p>The addition of the corresponding setter method is all that is
@@ -260,7 +261,7 @@
</p>
-<div class="source"><pre><configuration>
+ <p class="source"><configuration>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
@@ -274,25 +275,22 @@
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
-</configuration></pre></div>
+</configuration></p>
- <p>
-
- </p>
+ <p></p>
<h3><a name="ClassicPatternLayout"
href="#ClassicPatternLayout">PatternLayout</a></h3>
- <p>
- Logback classic ships with a flexible layout called <a
- href="../xref/ch/qos/logback/classic/PatternLayout.html">
- <code>PatternLayout</code></a>. As all layouts,
- <code>PatternLayout</code> takes a logging event and returns a
- <code>String</code>. However, this <code>String</code> can be
- customized at will by tweaking the conversion pattern of
- <code>PatternLayout</code>.
+ <p>Logback classic ships with a flexible layout called <a
+ href="../xref/ch/qos/logback/classic/PatternLayout.html">
+ <code>PatternLayout</code></a>. As all layouts,
+ <code>PatternLayout</code> takes a logging event and returns a
+ <code>String</code>. However, this <code>String</code> can be
+ customized at will by tweaking the conversion pattern of
+ <code>PatternLayout</code>.
</p>
<p>The conversion pattern of <code>PatternLayout</code> is closely
@@ -301,7 +299,7 @@
composed of literal text and format control expressions called
conversion specifiers. You are free to insert any literal text
within the conversion pattern. Each conversion specifier starts
- with a percent sign (%) and is followed by optional format
+ with a percent sign '%' and is followed by optional format
modifiers, a conversion word and optional parameters between
braces. The conversion word controls the type of data to use, e.g.
logger name, level, date, thread name. The format modifiers
@@ -341,25 +339,23 @@
}
}</pre></div>
- <p>
- The conversion pattern is set to be <b>"%-5level [%thread]:
- %message%n"</b>. Running PatternSample will yield the following
- output on the console.
- </p>
- <div class="source"><pre>DEBUG [main]: Message 1
-WARN [main]: Message 2</pre></div>
- <p>
- Note that in the conversion pattern <b>"%-5level [%thread]:
- %message%n"</b> there is no explicit separator between literal
- text and conversion specifiers. When parsing a conversion
- pattern,
- <code>PatternLayout</code>
- is capable of differentiating between literal text (space
- characters, the brackets, colon character) and conversion
- specifiers. In the example above, the conversion specifier
- %-5level means the level of the logging event should be left
- justified to a width of five characters. Format specifiers
- will be explained in a short moment.
+ <p>The conversion pattern is set to be <b>"%-5level [%thread]:
+ %message%n"</b>. Running PatternSample will yield the following
+ output on the console.
+ </p>
+
+ <p class="source">DEBUG [main]: Message 1
+WARN [main]: Message 2</p>
+
+ <p>Note that in the conversion pattern <b>"%-5level [%thread]:
+ %message%n"</b> there is no explicit separator between literal
+ text and conversion specifiers. When parsing a conversion pattern,
+ <code>PatternLayout</code> is capable of differentiating between
+ literal text (space characters, the brackets, colon character) and
+ conversion specifiers. In the example above, the conversion
+ specifier %-5level means the level of the logging event should be
+ left justified to a width of five characters. Format specifiers
+ will be explained in a short moment.
</p>
<p>In PatternLayout, parenthesis can be used to group conversion
@@ -402,43 +398,52 @@
the logging event.
</p>
- <p>This conversion word can take an integer as first and
+ <p>This conversion word can take an integer as its first and
only option. The converter's abbreviation algorithm will
shorten the logger name, usually without significant loss of
- meaning. The next table provides examples of the
- abbreviation algorithm in action.
+ meaning. Setting the value of this option to zero will cause
+ the conversoin specifier to return the string right to the
+ rightmost dot character. The next table provides examples of
+ the abbreviation algorithm in action.
</p>
- <table class="bodyTable" border="0" cellpadding="8">
- <tr class="a">
+ <table class="bodyTable dark" border="0" cellpadding="8">
+ <tr>
<th>Conversion specifier</th>
<th>Logger name</th>
<th>Result</th>
</tr>
- <tr class="a">
+ <tr>
<td>%logger</td>
<td>mainPackage.sub.sample.Bar</td>
<td>mainPackage.sub.sample.Bar</td>
</tr>
- <tr class="a">
+
+ <tr>
+ <td>%logger{0}</td>
+ <td>mainPackage.sub.sample.Bar</td>
+ <td>Bar</td>
+ </tr>
+
+ <tr>
<td>%logger{10}</td>
<td>mainPackage.sub.sample.Bar</td>
<td>m.s.s.Bar</td>
</tr>
- <tr class="a">
+ <tr>
<td>%logger{15}</td>
<td>mainPackage.sub.sample.Bar</td>
<td>m.s.sample.Bar</td>
</tr>
- <tr class="a">
+ <tr>
<td>%logger{16}</td>
<td>mainPackage.sub.sample.Bar</td>
<td>m.sub.sample.Bar</td>
</tr>
- <tr class="a">
+ <tr>
<td>%logger{26}</td>
<td>mainPackage.sub.sample.Bar</td>
<td>mainPackage.sub.sample.Bar</td>
@@ -459,12 +464,15 @@
</p>
<p> Just like the <em>%logger</em> conversion word above,
this word can take an interger as it's first option and use
- its abbreviation algorithm to shorten the class name. By
+ its abbreviation algorithm to shorten the class name. Zero
+ carries special meaning and w will cause the simple class
+ name to be output without its package name prefix. By
default the class name is output in full.
</p>
- <p>Generating the caller class information is not
- particularly fast. Thus, it's use should be avoided unless
- execution speed is not an issue.
+
+ <p>Generating the caller class information is not
+ particularly fast. Thus, it's use should be avoided unless
+ execution speed is not an issue.
</p>
</td>
</tr>
@@ -491,24 +499,24 @@
actual date is Friday 20th of October, 2006 and that the
author finished his meal a short while ago.</p>
- <table class="bodyTable" cellpadding="8">
- <tr class="a">
+ <table class="bodyTable dark" cellpadding="8">
+ <tr>
<th>Conversion Pattern</th>
<th>Result</th>
</tr>
- <tr class="a">
+ <tr>
<td>%date</td>
<td>2006-10-20 14:46:49,812</td>
</tr>
- <tr class="a">
+ <tr>
<td>%date{ISO8601}</td>
<td>2006-10-20 14:46:49,812</td>
</tr>
- <tr class="a">
+ <tr>
<td>%date{HH:mm:ss.SSS}</td>
<td>14:46:49.812</td>
</tr>
- <tr class="a">
+ <tr>
<td>%date{dd MMM yyyy ;HH:mm:ss.SSS}</td>
<td>20 oct. 2006;14:46:49.812 </td>
</tr>
@@ -522,7 +530,7 @@
</td>
<td>
- <p> Used to output the file name of the Java source file
+ <p>Used to output the file name of the Java source file
where the logging request was issued.
</p>
Modified: logback/trunk/logback-site/src/site/pages/news.html
==============================================================================
--- logback/trunk/logback-site/src/site/pages/news.html (original)
+++ logback/trunk/logback-site/src/site/pages/news.html Wed Nov 12 19:40:35 2008
@@ -45,29 +45,35 @@
<code>NullPointerException</code> would be thrown.
</p>
- <p>In reponse to <a
- href="http://jira.qos.ch/browse/LBCLASSIC-61">LBCLASSIC-61</a>, <a
- href="http://jira.qos.ch/browse/LBCLASSIC-33">LBCLASSIC-33</a>, <a
- href="http://jira.qos.ch/browse/LBCLASSIC-14">LBCLASSIC-24</a> and
- <a href="http://jira.qos.ch/browse/LBCLASSIC-24">LBCLASSIC-14</a>
- JMXConfigurator has been redesigned.
- </p>
+ <p>In reponse to <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-61">LBCLASSIC-61</a>, <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-33">LBCLASSIC-33</a>, <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-14">LBCLASSIC-24</a> and
+ <a href="http://jira.qos.ch/browse/LBCLASSIC-24">LBCLASSIC-14</a>
+ JMXConfigurator has been redesigned.
+ </p>
- <p>Fixed improvement request <a
- href="http://jira.qos.ch/browse/LBCLASSIC-59">LBCLASSIC-59</a>
- relation to StatusListeners, originally submitted by Anton Tagunov.
- </p>
+ <p>Fixed improvement request <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-59">LBCLASSIC-59</a>
+ relation to StatusListeners, originally submitted by Anton Tagunov.
+ </p>
- <p>In response to <a href="http://jira.qos.ch/browse/LBCLASSIC-54">
- LBCLASSIC-54</a> support for turbo filters has refactored. The
- present code is safe under concurrent access while still offering
- good performance.
- </p>
+ <p>The logger and class name converters now consider zero as
+ having special meaning, and will return the simple class name,
+ removing the package name prefix. This feature was asked by
+ Silvano Maffeis.</p>
+
+ <p>In response to <a
+ href="http://jira.qos.ch/browse/LBCLASSIC-54"> LBCLASSIC-54</a>
+ support for turbo filters has refactored. The present code is safe
+ under concurrent access while still offering good performance.
+ </p>
- <p>Fixed <a href="http://jira.qos.ch/browse/LBCORE-43">LBCORE-43</a>
- reported by Bruno Navert. Configuration files can now look up
- property files from classpath resources.
- </p>
+ <p>Fixed <a
+ href="http://jira.qos.ch/browse/LBCORE-43">LBCORE-43</a> reported
+ by Bruno Navert. Configuration files can now look up property
+ files from classpath resources.
+ </p>
<!-- ======================== minor ================== -->
1
0