logback-dev
Threads by month
- ----- 2025 -----
- 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

svn commit: r567 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic/pattern test/java/ch/qos/logback/classic/pattern
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 17:33:31 2006
New Revision: 567
Added:
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/MDCConverterTest.java
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
Log:
- corrected MDCConverter output format
- added test class
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java Tue Sep 12 17:33:31 2006
@@ -38,7 +38,7 @@
if (key == null) {
// if no key is specified, return all the
// values present in the MDC, separated with a single space.
- StringBuffer buf = new StringBuffer("{");
+ StringBuffer buf = new StringBuffer();
Set<String> keys = mdcPropertyMap.keySet();
Iterator it = keys.iterator();
String tmpKey;
@@ -47,7 +47,10 @@
tmpKey = (String)it.next();
tmpValue = (String)mdcPropertyMap.get(tmpKey);
//format: {testeKey=testValue, testKey2=testValue2}
- buf.append(tmpKey).append('=').append(tmpValue).append(", ");
+ buf.append(tmpKey).append('=').append(tmpValue);
+ if (it.hasNext()) {
+ buf.append(", ");
+ }
}
return buf.toString();
}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/MDCConverterTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/pattern/MDCConverterTest.java Tue Sep 12 17:33:31 2006
@@ -0,0 +1,45 @@
+package ch.qos.logback.classic.pattern;
+
+import junit.framework.TestCase;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.MDC;
+import ch.qos.logback.classic.spi.LoggingEvent;
+
+public class MDCConverterTest extends TestCase {
+
+ LoggerContext lc;
+ MDCConverter converter;
+
+ public void setUp() throws Exception {
+ lc = new LoggerContext();
+ converter = new MDCConverter();
+ converter.start();
+ }
+
+ public void tearDown() throws Exception {
+ lc = null;
+ converter.stop();
+ converter = null;
+ }
+
+ public void testConverWithOneEntry() {
+ MDC.put("testKey", "testValue");
+ LoggingEvent le = createLoggingEvent();
+ String result = converter.convert(le);
+ assertEquals("testKey=testValue", result);
+ }
+
+ public void testConverWithMultipleEntries() {
+ MDC.put("testKey2", "testValue2");
+ LoggingEvent le = createLoggingEvent();
+ String result = converter.convert(le);
+ assertEquals("testKey=testValue, testKey2=testValue2", result);
+ }
+
+ private LoggingEvent createLoggingEvent() {
+ LoggingEvent le = new LoggingEvent(this.getClass().getName(), lc.getLogger(LoggerContext.ROOT_NAME),
+ Level.DEBUG, "test message", null, null);
+ return le;
+ }
+}
1
0

svn commit: r566 - in logback/trunk: logback-classic logback-classic/src/main/java/ch/qos/logback/classic/net logback-classic/src/test/java/ch/qos/logback/classic/net logback-core logback-core/src/main/java/ch/qos/logback/core/net
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 17:20:42 2006
New Revision: 566
Added:
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
Modified:
logback/trunk/logback-classic/pom.xml
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SMTPAppenderTest.java
logback/trunk/logback-core/pom.xml
Log:
- added a SMTPAppenderBase class in logback core
- modified SMTPAppender accordingly
- updated tests
- updated pom.xml files
Modified: logback/trunk/logback-classic/pom.xml
==============================================================================
--- logback/trunk/logback-classic/pom.xml (original)
+++ logback/trunk/logback-classic/pom.xml Tue Sep 12 17:20:42 2006
@@ -36,12 +36,6 @@
<artifactId>logback-core</artifactId>
<scope>compile</scope>
</dependency>
-
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <scope>compile</scope>
- </dependency>
<dependency>
<groupId>dom4j</groupId>
@@ -50,6 +44,12 @@
</dependency>
<dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<classifier>tests</classifier>
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java Tue Sep 12 17:20:42 2006
@@ -11,27 +11,12 @@
package ch.qos.logback.classic.net;
import java.io.File;
-import java.util.Date;
-import java.util.Properties;
-
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.AddressException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.helpers.CyclicBuffer;
import ch.qos.logback.classic.spi.LoggingEvent;
-import ch.qos.logback.core.AppenderBase;
-import ch.qos.logback.core.Layout;
+import ch.qos.logback.core.net.SMTPAppenderBase;
import ch.qos.logback.core.rolling.TriggeringPolicy;
-import ch.qos.logback.core.util.OptionHelper;
/**
* Send an e-mail when a specific logging event occurs, typically on errors or
@@ -47,22 +32,11 @@
* @author Ceki Gülcü
* @author Sébastien Pennec
*
- * @since 1.0
*/
-public class SMTPAppender extends AppenderBase {
- private Layout layout;
+public class SMTPAppender extends SMTPAppenderBase {
- private String to;
- private String from;
- private String subject;
- private String smtpHost;
private int bufferSize = 512;
- private boolean locationInfo = false;
-
protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
- protected Message msg;
-
- protected TriggeringPolicy evaluator;
/**
* The default constructor will instantiate the appender with a
@@ -82,194 +56,33 @@
}
/**
- * Start the appender
- */
- public void start() {
- Properties props = new Properties(System.getProperties());
- if (smtpHost != null) {
- props.put("mail.smtp.host", smtpHost);
- }
-
- Session session = Session.getInstance(props, null);
- // session.setDebug(true);
- msg = new MimeMessage(session);
-
- try {
- if (from != null) {
- msg.setFrom(getAddress(from));
- } else {
- msg.setFrom();
- }
-
- msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
- if (subject != null) {
- msg.setSubject(subject);
- }
-
- started = true;
-
- } catch (MessagingException e) {
- addError("Could not activate SMTPAppender options.", e);
- }
- }
-
- /**
* Perform SMTPAppender specific appending actions, mainly adding the event to
- * a cyclic buffer and checking if the event triggers an e-mail to be sent.
+ * a cyclic buffer.
*/
- protected void append(Object eventObject) {
+ protected void subAppend(Object eventObject) {
LoggingEvent event = (LoggingEvent) eventObject;
- if (!checkEntryConditions()) {
- return;
- }
-
event.getThreadName();
- // if (locationInfo) {
- // event.getLocationInformation();
- // }
cb.add(event);
// addInfo("Added event to the cyclic buffer: " + event.getMessage());
-
- if (evaluator.isTriggeringEvent(null, event)) {
- sendBuffer();
- }
}
- /**
- * This method determines if there is a sense in attempting to append.
- *
- * <p>
- * It checks whether there is a set output target and also if there is a set
- * layout. If these checks fail, then the boolean value <code>false</code>
- * is returned.
- */
- protected boolean checkEntryConditions() {
- if (this.msg == null) {
- addError("Message object not configured.");
- return false;
- }
-
- if (this.evaluator == null) {
- addError("No TriggeringPolicy is set for appender [" + name + "].");
- return false;
+ @Override
+ protected void fillBuffer(StringBuffer sbuf) {
+ int len = cb.length();
+ for (int i = 0; i < len; i++) {
+ // sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
+ LoggingEvent event = cb.get();
+ sbuf.append(layout.doLayout(event));
+ // if (layout.ignoresThrowable()) {
+ // String[] s = event.getThrowableStrRep();
+ // if (s != null) {
+ // for (int j = 0; j < s.length; j++) {
+ // sbuf.append(s[j]);
+ // }
+ // }
+ // }
}
-
- if (this.layout == null) {
- addError("No layout set for appender named [" + name + "].");
- return false;
- }
- return true;
- }
-
- synchronized public void stop() {
- this.started = false;
- }
-
- InternetAddress getAddress(String addressStr) {
- try {
- return new InternetAddress(addressStr);
- } catch (AddressException e) {
- addError("Could not parse address [" + addressStr + "].", e);
- return null;
- }
- }
-
- InternetAddress[] parseAddress(String addressStr) {
- try {
- return InternetAddress.parse(addressStr, true);
- } catch (AddressException e) {
- addError("Could not parse address [" + addressStr + "].", e);
- return null;
- }
- }
-
- /**
- * Returns value of the <b>To</b> option.
- */
- public String getTo() {
- return to;
- }
-
- /**
- * Send the contents of the cyclic buffer as an e-mail message.
- */
- protected void sendBuffer() {
-
- // Note: this code already owns the monitor for this
- // appender. This frees us from needing to synchronize on 'cb'.
- try {
- MimeBodyPart part = new MimeBodyPart();
-
- StringBuffer sbuf = new StringBuffer();
- String t = layout.getHeader();
- if (t != null)
- sbuf.append(t);
- int len = cb.length();
- for (int i = 0; i < len; i++) {
- // sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
- LoggingEvent event = cb.get();
- sbuf.append(layout.doLayout(event));
- // if (layout.ignoresThrowable()) {
- // String[] s = event.getThrowableStrRep();
- // if (s != null) {
- // for (int j = 0; j < s.length; j++) {
- // sbuf.append(s[j]);
- // }
- // }
- // }
- }
- t = layout.getFooter();
- if (t != null)
- sbuf.append(t);
- part.setContent(sbuf.toString(), "text/plain");
-
- Multipart mp = new MimeMultipart();
- mp.addBodyPart(part);
- msg.setContent(mp);
-
- msg.setSentDate(new Date());
- Transport.send(msg);
- } catch (Exception e) {
- addError("Error occured while sending e-mail notification.", e);
- }
- }
-
- /**
- * Returns value of the <b>EvaluatorClass</b> option.
- */
- public String getEvaluatorClass() {
- return evaluator == null ? null : evaluator.getClass().getName();
- }
-
- /**
- * Returns value of the <b>From</b> option.
- */
- public String getFrom() {
- return from;
- }
-
- /**
- * Returns value of the <b>Subject</b> option.
- */
- public String getSubject() {
- return subject;
- }
-
- /**
- * The <b>From</b> option takes a string value which should be a e-mail
- * address of the sender.
- */
- public void setFrom(String from) {
- this.from = from;
- }
-
- /**
- * The <b>Subject</b> option takes a string value which should be a the
- * subject of the e-mail message.
- */
- public void setSubject(String subject) {
- this.subject = subject;
}
/**
@@ -285,79 +98,11 @@
}
/**
- * The <b>SMTPHost</b> option takes a string value which should be a the host
- * name of the SMTP server that will send the e-mail message.
- */
- public void setSMTPHost(String smtpHost) {
- this.smtpHost = smtpHost;
- }
-
- /**
- * Returns value of the <b>SMTPHost</b> option.
- */
- public String getSMTPHost() {
- return smtpHost;
- }
-
- /**
- * The <b>To</b> option takes a string value which should be a comma
- * separated list of e-mail address of the recipients.
- */
- public void setTo(String to) {
- this.to = to;
- }
-
- /**
* Returns value of the <b>BufferSize</b> option.
*/
public int getBufferSize() {
return bufferSize;
}
-
- /**
- * The <b>EvaluatorClass</b> option takes a string value representing the
- * name of the class implementing the {@link TriggeringEventEvaluator}
- * interface. A corresponding object will be instantiated and assigned as the
- * triggering event evaluator for the SMTPAppender.
- */
- public void setEvaluatorClass(String value) {
- try {
- evaluator = (TriggeringPolicy) OptionHelper.instantiateByClassName(value,
- TriggeringPolicy.class);
- } catch (Exception ex) {
- addError("Evaluator class instanciation failed");
- }
- }
-
- /**
- * The <b>LocationInfo</b> option takes a boolean value. By default, it is
- * set to false which means there will be no effort to extract the location
- * information related to the event. As a result, the layout that formats the
- * events as they are sent out in an e-mail is likely to place the wrong
- * location information (if present in the format).
- *
- * <p>
- * Location information extraction is comparatively very slow and should be
- * avoided unless performance is not a concern.
- */
- public void setLocationInfo(boolean locationInfo) {
- this.locationInfo = locationInfo;
- }
-
- /**
- * Returns value of the <b>LocationInfo</b> option.
- */
- public boolean getLocationInfo() {
- return locationInfo;
- }
-
- public Layout getLayout() {
- return layout;
- }
-
- public void setLayout(Layout layout) {
- this.layout = layout;
- }
}
class DefaultEvaluator implements TriggeringPolicy {
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SMTPAppenderTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SMTPAppenderTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SMTPAppenderTest.java Tue Sep 12 17:20:42 2006
@@ -12,102 +12,101 @@
public class SMTPAppenderTest extends TestCase {
- SMTPAppender appender;
+ SMTPAppender appender;
- public void setUp() throws Exception {
- super.setUp();
- LoggerContext lc = new LoggerContext();
- appender = new SMTPAppender();
- appender.setContext(lc);
- appender.setName("smtp");
- appender.setFrom("user(a)host.dom");
- appender.setLayout(buildLayout(lc));
- appender.setSMTPHost("mail2.qos.ch");
- appender.setSubject("logging report");
- appender.setTo("sebastien.nospam(a)qos.ch");
- appender.start();
- }
-
- public void tearDown() throws Exception {
- super.tearDown();
- appender = null;
- }
-
- public void testStart() {
- try {
- Address[] addressArray = appender.msg.getFrom();
- Address address = addressArray[0];
- assertEquals("user(a)host.dom", address.toString());
-
- addressArray = null;
- address = null;
-
- addressArray = appender.msg.getAllRecipients();
- address = addressArray[0];
- assertEquals("sebastien.nospam(a)qos.ch", address.toString());
-
- assertEquals("logging report", appender.msg.getSubject());
-
- assertTrue(appender.isStarted());
-
- } catch (MessagingException ex) {
- fail("Unexpected exception.");
- }
- }
-
- public void testAppendNonTriggeringEvent() {
- LoggingEvent event = new LoggingEvent();
- event.setThreadName("thead name");
- event.setLevel(Level.DEBUG);
- appender.append(event);
- assertEquals(1, appender.cb.length());
- }
-
- public void testEntryConditionsCheck() {
- appender.checkEntryConditions();
- assertEquals(0, appender.getContext().getStatusManager().getCount());
- }
-
- public void testEntryConditionsCheckNoMessage() {
- appender.msg = null;
- appender.checkEntryConditions();
- assertEquals(1, appender.getContext().getStatusManager().getCount());
- }
-
- public void testEntryConditionsCheckNoEvaluator() {
- appender.evaluator = null;
- appender.checkEntryConditions();
- assertEquals(1, appender.getContext().getStatusManager().getCount());
- }
-
- public void testEntryConditionsCheckNoLayout() {
- appender.setLayout(null);
- appender.checkEntryConditions();
- assertEquals(1, appender.getContext().getStatusManager().getCount());
- }
-
-
- public void testDefaultEvaluatorNoTrigger() {
- DefaultEvaluator evaluator = new DefaultEvaluator();
- LoggingEvent le = new LoggingEvent();
- le.setLevel(Level.DEBUG);
- assertFalse(evaluator.isTriggeringEvent(null,le));
- }
-
- public void testDefaultEvaluatorTrigger() {
- DefaultEvaluator evaluator = new DefaultEvaluator();
- LoggingEvent le = new LoggingEvent();
- le.setLevel(Level.ERROR);
- assertTrue(evaluator.isTriggeringEvent(null,le));
- }
-
- private static Layout buildLayout(LoggerContext lc) {
- PatternLayout layout = new PatternLayout();
- layout.setContext(lc);
- layout.setHeader("Some header\n");
- layout.setPattern("%-4relative [%thread] %-5level %class - %msg%n");
- layout.setFooter("Some footer");
- layout.start();
- return layout;
- }
+ public void setUp() throws Exception {
+ super.setUp();
+ LoggerContext lc = new LoggerContext();
+ appender = new SMTPAppender();
+ appender.setContext(lc);
+ appender.setName("smtp");
+ appender.setFrom("user(a)host.dom");
+ appender.setLayout(buildLayout(lc));
+ appender.setSMTPHost("mail2.qos.ch");
+ appender.setSubject("logging report");
+ appender.setTo("sebastien.nospam(a)qos.ch");
+ appender.start();
+ }
+
+ public void tearDown() throws Exception {
+ super.tearDown();
+ appender = null;
+ }
+
+ public void testStart() {
+ try {
+ Address[] addressArray = appender.getMessage().getFrom();
+ Address address = addressArray[0];
+ assertEquals("user(a)host.dom", address.toString());
+
+ addressArray = null;
+ address = null;
+
+ addressArray = appender.getMessage().getAllRecipients();
+ address = addressArray[0];
+ assertEquals("sebastien.nospam(a)qos.ch", address.toString());
+
+ assertEquals("logging report", appender.getMessage().getSubject());
+
+ assertTrue(appender.isStarted());
+
+ } catch (MessagingException ex) {
+ fail("Unexpected exception.");
+ }
+ }
+
+ public void testAppendNonTriggeringEvent() {
+ LoggingEvent event = new LoggingEvent();
+ event.setThreadName("thead name");
+ event.setLevel(Level.DEBUG);
+ appender.subAppend(event);
+ assertEquals(1, appender.cb.length());
+ }
+
+ public void testEntryConditionsCheck() {
+ appender.checkEntryConditions();
+ assertEquals(0, appender.getContext().getStatusManager().getCount());
+ }
+
+ public void testEntryConditionsCheckNoMessage() {
+ appender.setMessage(null);
+ appender.checkEntryConditions();
+ assertEquals(1, appender.getContext().getStatusManager().getCount());
+ }
+
+ public void testEntryConditionsCheckNoEvaluator() {
+ appender.setEvaluator(null);
+ appender.checkEntryConditions();
+ assertEquals(1, appender.getContext().getStatusManager().getCount());
+ }
+
+ public void testEntryConditionsCheckNoLayout() {
+ appender.setLayout(null);
+ appender.checkEntryConditions();
+ assertEquals(1, appender.getContext().getStatusManager().getCount());
+ }
+
+ public void testDefaultEvaluatorNoTrigger() {
+ DefaultEvaluator evaluator = new DefaultEvaluator();
+ LoggingEvent le = new LoggingEvent();
+ le.setLevel(Level.DEBUG);
+ assertFalse(evaluator.isTriggeringEvent(null, le));
+ }
+
+ public void testDefaultEvaluatorTrigger() {
+ DefaultEvaluator evaluator = new DefaultEvaluator();
+ LoggingEvent le = new LoggingEvent();
+ le.setLevel(Level.ERROR);
+ assertTrue(evaluator.isTriggeringEvent(null, le));
+ }
+
+ private static Layout buildLayout(LoggerContext lc) {
+ PatternLayout layout = new PatternLayout();
+ layout.setContext(lc);
+ layout.setHeader("Some header\n");
+ layout.setPattern("%-4relative [%thread] %-5level %class - %msg%n");
+ layout.setFooter("Some footer");
+ layout.start();
+ return layout;
+ }
}
Modified: logback/trunk/logback-core/pom.xml
==============================================================================
--- logback/trunk/logback-core/pom.xml (original)
+++ logback/trunk/logback-core/pom.xml Tue Sep 12 17:20:42 2006
@@ -35,6 +35,11 @@
<groupId>janino</groupId>
<artifactId>janino</artifactId>
</dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java Tue Sep 12 17:20:42 2006
@@ -0,0 +1,285 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ *
+ * 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.
+ */
+
+package ch.qos.logback.core.net;
+
+import java.util.Date;
+import java.util.Properties;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.Layout;
+import ch.qos.logback.core.rolling.TriggeringPolicy;
+import ch.qos.logback.core.util.OptionHelper;
+
+/**
+ * An abstract class that provides basic support for
+ * sending events to an email address.
+ *
+ * @author Ceki Gülcü
+ * @author Sébastien Pennec
+ *
+ */
+public abstract class SMTPAppenderBase extends AppenderBase {
+ protected Layout layout;
+
+ private String to;
+ private String from;
+ private String subject;
+ private String smtpHost;
+
+ protected Message msg;
+
+ protected TriggeringPolicy evaluator;
+
+ /**
+ * Start the appender
+ */
+ public void start() {
+ Properties props = new Properties(System.getProperties());
+ if (smtpHost != null) {
+ props.put("mail.smtp.host", smtpHost);
+ }
+
+ Session session = Session.getInstance(props, null);
+ // session.setDebug(true);
+ msg = new MimeMessage(session);
+
+ try {
+ if (from != null) {
+ msg.setFrom(getAddress(from));
+ } else {
+ msg.setFrom();
+ }
+
+ msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
+ if (subject != null) {
+ msg.setSubject(subject);
+ }
+
+ started = true;
+
+ } catch (MessagingException e) {
+ addError("Could not activate SMTPAppender options.", e);
+ }
+ }
+
+ /**
+ * Perform SMTPAppender specific appending actions, delegating some
+ * of them to a subclass and checking if the event triggers an e-mail to be sent.
+ */
+ protected void append(Object eventObject) {
+
+ if (!checkEntryConditions()) {
+ return;
+ }
+
+ subAppend(eventObject);
+
+ if (evaluator.isTriggeringEvent(null, eventObject)) {
+ sendBuffer();
+ }
+ }
+
+ abstract protected void subAppend(Object eventObject);
+
+ /**
+ * This method determines if there is a sense in attempting to append.
+ *
+ * <p>
+ * It checks whether there is a set output target and also if there is a set
+ * layout. If these checks fail, then the boolean value <code>false</code>
+ * is returned.
+ */
+ public boolean checkEntryConditions() {
+ if (this.msg == null) {
+ addError("Message object not configured.");
+ return false;
+ }
+
+ if (this.evaluator == null) {
+ addError("No TriggeringPolicy is set for appender [" + name + "].");
+ return false;
+ }
+
+ if (this.layout == null) {
+ addError("No layout set for appender named [" + name + "].");
+ return false;
+ }
+ return true;
+ }
+
+ synchronized public void stop() {
+ this.started = false;
+ }
+
+ InternetAddress getAddress(String addressStr) {
+ try {
+ return new InternetAddress(addressStr);
+ } catch (AddressException e) {
+ addError("Could not parse address [" + addressStr + "].", e);
+ return null;
+ }
+ }
+
+ InternetAddress[] parseAddress(String addressStr) {
+ try {
+ return InternetAddress.parse(addressStr, true);
+ } catch (AddressException e) {
+ addError("Could not parse address [" + addressStr + "].", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns value of the <b>To</b> option.
+ */
+ public String getTo() {
+ return to;
+ }
+
+ /**
+ * Send the contents of the cyclic buffer as an e-mail message.
+ */
+ protected void sendBuffer() {
+
+ // Note: this code already owns the monitor for this
+ // appender. This frees us from needing to synchronize on 'cb'.
+ try {
+ MimeBodyPart part = new MimeBodyPart();
+
+ StringBuffer sbuf = new StringBuffer();
+ String t = layout.getHeader();
+ fillBuffer(sbuf);
+ t = layout.getFooter();
+ if (t != null)
+ sbuf.append(t);
+ part.setContent(sbuf.toString(), "text/plain");
+
+ Multipart mp = new MimeMultipart();
+ mp.addBodyPart(part);
+ msg.setContent(mp);
+
+ msg.setSentDate(new Date());
+ Transport.send(msg);
+ } catch (Exception e) {
+ addError("Error occured while sending e-mail notification.", e);
+ }
+ }
+
+ abstract protected void fillBuffer(StringBuffer sbuf);
+
+ /**
+ * Returns value of the <b>EvaluatorClass</b> option.
+ */
+ public String getEvaluatorClass() {
+ return evaluator == null ? null : evaluator.getClass().getName();
+ }
+
+ /**
+ * Returns value of the <b>From</b> option.
+ */
+ public String getFrom() {
+ return from;
+ }
+
+ /**
+ * Returns value of the <b>Subject</b> option.
+ */
+ public String getSubject() {
+ return subject;
+ }
+
+ /**
+ * The <b>From</b> option takes a string value which should be a e-mail
+ * address of the sender.
+ */
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ /**
+ * The <b>Subject</b> option takes a string value which should be a the
+ * subject of the e-mail message.
+ */
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ /**
+ * The <b>SMTPHost</b> option takes a string value which should be a the host
+ * name of the SMTP server that will send the e-mail message.
+ */
+ public void setSMTPHost(String smtpHost) {
+ this.smtpHost = smtpHost;
+ }
+
+ /**
+ * Returns value of the <b>SMTPHost</b> option.
+ */
+ public String getSMTPHost() {
+ return smtpHost;
+ }
+
+ /**
+ * The <b>To</b> option takes a string value which should be a comma
+ * separated list of e-mail address of the recipients.
+ */
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ //for testing purpose only
+ public Message getMessage() {
+ return msg;
+ }
+
+ //for testing purpose only
+ public void setMessage(Message msg) {
+ this.msg = msg;
+ }
+
+ public void setEvaluator(TriggeringPolicy evaluator) {
+ this.evaluator = evaluator;
+ }
+
+ /**
+ * The <b>EvaluatorClass</b> option takes a string value representing the
+ * name of the class implementing the {@link TriggeringEventEvaluator}
+ * interface. A corresponding object will be instantiated and assigned as the
+ * triggering event evaluator for the SMTPAppender.
+ */
+ public void setEvaluatorClass(String value) {
+ try {
+ evaluator = (TriggeringPolicy) OptionHelper.instantiateByClassName(value,
+ TriggeringPolicy.class);
+ } catch (Exception ex) {
+ addError("Evaluator class instanciation failed");
+ }
+ }
+
+ public Layout getLayout() {
+ return layout;
+ }
+
+ public void setLayout(Layout layout) {
+ this.layout = layout;
+ }
+}
1
0

svn commit: r565 - logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 16:37:14 2006
New Revision: 565
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
Log:
better output format
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java Tue Sep 12 16:37:14 2006
@@ -1,8 +1,8 @@
package ch.qos.logback.classic.pattern;
-import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
import ch.qos.logback.classic.spi.LoggingEvent;
@@ -38,13 +38,16 @@
if (key == null) {
// if no key is specified, return all the
// values present in the MDC, separated with a single space.
- StringBuffer buf = new StringBuffer();
- Collection<String> values = mdcPropertyMap.values();
- Iterator it = values.iterator();
- String value;
+ StringBuffer buf = new StringBuffer("{");
+ Set<String> keys = mdcPropertyMap.keySet();
+ Iterator it = keys.iterator();
+ String tmpKey;
+ String tmpValue;
while (it.hasNext()) {
- value = (String)it.next();
- buf.append(value).append(' ');
+ tmpKey = (String)it.next();
+ tmpValue = (String)mdcPropertyMap.get(tmpKey);
+ //format: {testeKey=testValue, testKey2=testValue2}
+ buf.append(tmpKey).append('=').append(tmpValue).append(", ");
}
return buf.toString();
}
1
0

svn commit: r564 - logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 16:08:19 2006
New Revision: 564
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
Log:
removed unused attributes
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java Tue Sep 12 16:08:19 2006
@@ -54,8 +54,6 @@
private String title = "Logback Log Messages";
private CssBuilder cssBuilder;
- private boolean internalCSS = false;
- private String url2ExternalCSS = "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css";
// Does our PatternConverter chain handle throwable on its own?
private boolean chainHandlesThrowable;
1
0

svn commit: r563 - logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 16:07:48 2006
New Revision: 563
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
Log:
modified MDCConverter to return all the values present in the MDC when no key is specified
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/MDCConverter.java Tue Sep 12 16:07:48 2006
@@ -1,5 +1,7 @@
package ch.qos.logback.classic.pattern;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.Map;
import ch.qos.logback.classic.spi.LoggingEvent;
@@ -7,7 +9,8 @@
public class MDCConverter extends ClassicConverter {
String key;
-
+ private static final String EMPTY_STRING = "";
+
public MDCConverter() {
}
@@ -16,25 +19,41 @@
key = getFirstOption();
super.start();
}
-
+
@Override
public void stop() {
key = null;
super.stop();
}
-
+
@Override
public String convert(Object event) {
LoggingEvent loggingEvent = (LoggingEvent) event;
Map<String, String> mdcPropertyMap = loggingEvent.getMDCPropertyMap();
- if (mdcPropertyMap != null) {
- String value = loggingEvent.getMDCPropertyMap().get(key);
- if (value != null) {
- return value;
+
+ if (mdcPropertyMap == null) {
+ return EMPTY_STRING;
+ }
+
+ if (key == null) {
+ // if no key is specified, return all the
+ // values present in the MDC, separated with a single space.
+ StringBuffer buf = new StringBuffer();
+ Collection<String> values = mdcPropertyMap.values();
+ Iterator it = values.iterator();
+ String value;
+ while (it.hasNext()) {
+ value = (String)it.next();
+ buf.append(value).append(' ');
}
- return "";
+ return buf.toString();
+ }
+
+ String value = loggingEvent.getMDCPropertyMap().get(key);
+ if (value != null) {
+ return value;
} else {
- return "";
+ return EMPTY_STRING;
}
}
}
1
0

svn commit: r562 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic/helpers main/java/ch/qos/logback/classic/html test/java/ch/qos/logback/classic/html
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 15:22:21 2006
New Revision: 562
Added:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/CssBuilder.java
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
Log:
- added a CssBuilder class that provides the HTMLLayout with either a default css file,
or builds the link to a user-specified external css file.
- updated test
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/CssBuilder.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/CssBuilder.java Tue Sep 12 15:22:21 2006
@@ -0,0 +1,81 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ *
+ * 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.
+ */
+package ch.qos.logback.classic.helpers;
+
+import static ch.qos.logback.core.Layout.LINE_SEP;
+
+/**
+ * This class helps the HTMLLayout build the CSS link.
+ * It either provides the HTMLLayout with a default css file,
+ * or builds the link to an external, user-specified, file.
+ *
+ * @author Sébastien Pennec
+ */
+public class CssBuilder {
+
+ String url;
+
+ public CssBuilder() {
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void addExternalCSS(StringBuffer sbuf) {
+ sbuf.append("<LINK REL=StyleSheet HREF=\"");
+ sbuf.append(url);
+ sbuf.append("\" TITLE=\"Basic\" />");
+ }
+
+ public static void addDefaultCSS(StringBuffer buf) {
+ buf.append("<STYLE type=\"text/css\">");
+ buf.append(LINE_SEP);
+ buf.append("table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.even { background: #FFFFFF; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.odd { background: #DADADA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.warn TD.level, TR.error TD.level, TR.fatal TD.level {font-weight: bold; color: #FF4040 }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Thread { text-align: left; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Level { text-align: right; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Logger { text-align: left; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.header { background: #9090FF; color: #FFF; font-weight: bold; font-size: larger; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Exception { background: #C0C0F0; font-family: courier, monospace;}");
+ buf.append(LINE_SEP);
+
+ buf.append("</STYLE>");
+ buf.append(LINE_SEP);
+ }
+}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java Tue Sep 12 15:22:21 2006
@@ -12,6 +12,7 @@
import ch.qos.logback.classic.ClassicLayout;
import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.classic.helpers.CssBuilder;
import ch.qos.logback.classic.helpers.Transform;
import ch.qos.logback.classic.pattern.ThrowableHandlingConverter;
import ch.qos.logback.classic.spi.LoggingEvent;
@@ -52,6 +53,7 @@
//private String timezone;
private String title = "Logback Log Messages";
+ private CssBuilder cssBuilder;
private boolean internalCSS = false;
private String url2ExternalCSS = "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css";
@@ -87,6 +89,14 @@
public String getPattern() {
return pattern;
}
+
+ public CssBuilder getCssBuilder() {
+ return cssBuilder;
+ }
+
+ public void setCssBuilder(CssBuilder cssBuilder) {
+ this.cssBuilder = cssBuilder;
+ }
/**
* Parses the pattern and creates the Converter linked list.
@@ -137,50 +147,6 @@
}
/**
- * Returns the value of the internalCSS option. See {@link #setInternalCSS}
- * method for details about the meaning of this option.
- *
- * @return boolean Value of internalCSS option
- */
- public boolean isInternalCSS() {
- return internalCSS;
- }
-
- /**
- * Set the value of the internalCSS option. If set to true, the generated HTML
- * ouput will include an internal cascading style sheet. Otherwise, the
- * generated HTML output will include a reference to an external CSS.
- * <p>
- * By default, <code>internalCSS</code> value is set to false, that is, by
- * default, only a link to an external CSS file will be generated.
- *
- * @see #setURL2ExternalCSS
- *
- * @param internalCSS
- */
- public void setInternalCSS(boolean internalCSS) {
- this.internalCSS = internalCSS;
- }
-
- /**
- * Return the URL to the external CSS file. See {@link #setURL2ExternalCSS}
- * method for details about the meaning of this option.
- *
- * @return URL to the external CSS file.
- */
- public String getURL2ExternalCSS() {
- return url2ExternalCSS;
- }
-
- /**
- * Set the URL for the external CSS file. By default, the external CSS file is
- * set to "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css".
- */
- public void setURL2ExternalCSS(String url2ExternalCSS) {
- this.url2ExternalCSS = url2ExternalCSS;
- }
-
- /**
* Returns the content type output by this layout, i.e "text/html".
*/
public String getContentType() {
@@ -219,12 +185,10 @@
sbuf.append(title);
sbuf.append("</title>");
sbuf.append(LINE_SEP);
- if (internalCSS) {
- getInternalCSS(sbuf);
+ if (cssBuilder == null) {
+ CssBuilder.addDefaultCSS(sbuf);
} else {
- sbuf.append("<LINK REL=StyleSheet HREF=\"");
- sbuf.append(url2ExternalCSS);
- sbuf.append("\" TITLE=\"Basic\" />");
+ cssBuilder.addExternalCSS(sbuf);
}
sbuf.append(LINE_SEP);
sbuf.append("</head>");
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java Tue Sep 12 15:22:21 2006
@@ -32,7 +32,6 @@
layout = new HTMLLayout();
layout.setContext(lc);
layout.setPattern("%level %thread %msg");
- layout.setInternalCSS(true);
layout.start();
appender.setLayout(layout);
logger = lc.getLogger(LoggerContext.ROOT_NAME);
1
0

svn commit: r561 - logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 14:56:45 2006
New Revision: 561
Modified:
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
Log:
updated test
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java Tue Sep 12 14:56:45 2006
@@ -131,7 +131,7 @@
}
// public void testLog() {
-// for (int i = 1; i <= 100000; i++) {
+// for (int i = 1; i <= 1000; i++) {
// logger.debug("test message" + i);
// }
// }
1
0

svn commit: r560 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic/html test/java/ch/qos/logback/classic/html
by noreply.seb@qos.ch 12 Sep '06
by noreply.seb@qos.ch 12 Sep '06
12 Sep '06
Author: seb
Date: Tue Sep 12 11:48:40 2006
New Revision: 560
Modified:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
Log:
- added table break each 10'000 logs
- updated html code to xhtml
- improved test
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java Tue Sep 12 11:48:40 2006
@@ -13,9 +13,7 @@
import ch.qos.logback.classic.ClassicLayout;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.helpers.Transform;
-import ch.qos.logback.classic.pattern.NopThrowableInformationConverter;
import ch.qos.logback.classic.pattern.ThrowableHandlingConverter;
-import ch.qos.logback.classic.pattern.ThrowableInformationConverter;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.ThrowableInformation;
import ch.qos.logback.core.LayoutBase;
@@ -53,7 +51,6 @@
//private String timezone;
private String title = "Logback Log Messages";
- private boolean locationInfo;
private boolean internalCSS = false;
private String url2ExternalCSS = "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css";
@@ -63,6 +60,8 @@
// counter keeping track of the rows output
private long counter = 0;
+ //max number of rows before we close the table and create a new one
+ private static final int ROW_LIMIT = 10000;
/**
* Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
@@ -209,8 +208,8 @@
*/
public String getHeader() {
StringBuffer sbuf = new StringBuffer();
- sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"");
- sbuf.append(" \"http://www.w3.org/TR/html4/loose.dtd\">");
+ sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"");
+ sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
sbuf.append(LINE_SEP);
sbuf.append("<html>");
sbuf.append(LINE_SEP);
@@ -225,7 +224,7 @@
} else {
sbuf.append("<LINK REL=StyleSheet HREF=\"");
sbuf.append(url2ExternalCSS);
- sbuf.append("\" TITLE=\"Basic\">");
+ sbuf.append("\" TITLE=\"Basic\" />");
}
sbuf.append(LINE_SEP);
sbuf.append("</head>");
@@ -233,23 +232,28 @@
sbuf.append("<body>");
sbuf.append(LINE_SEP);
- sbuf.append("<hr size=\"1\" noshade>");
+ sbuf.append("<hr size=\"1\" noshade=\"true\" />");
sbuf.append(LINE_SEP);
sbuf.append("Log session start time ");
sbuf.append(new java.util.Date());
- sbuf.append("<br>");
+ sbuf.append("<br />");
sbuf.append(LINE_SEP);
- sbuf.append("<br>");
+ sbuf.append("<br />");
sbuf.append(LINE_SEP);
sbuf.append("<table cellspacing=\"0\">");
sbuf.append(LINE_SEP);
-
- sbuf.append("<tr class=\"header\">");
- sbuf.append(LINE_SEP);
+ createTableHeader(sbuf);
+
+ return sbuf.toString();
+ }
+
+ private void createTableHeader(StringBuffer sbuf) {
Converter c = head;
String name;
+ sbuf.append("<tr class=\"header\">");
+ sbuf.append(LINE_SEP);
while (c != null) {
name = computeConverterName(c);
if (name == null) {
@@ -259,7 +263,6 @@
sbuf.append("<td class=\"");
sbuf.append(computeConverterName(c));
sbuf.append("\">");
- sbuf.append("<td>");
sbuf.append(computeConverterName(c));
sbuf.append("</td>");
sbuf.append(LINE_SEP);
@@ -267,9 +270,9 @@
}
sbuf.append("</tr>");
sbuf.append(LINE_SEP);
-
- return sbuf.toString();
}
+
+
/**
* Returns the appropriate HTML footers.
@@ -297,7 +300,9 @@
}
public String doLayout(LoggingEvent event) {
-
+ StringBuffer buf = new StringBuffer();
+ handleTableClosing(buf);
+
boolean odd = true;
if (((counter++) & 1) == 0) {
odd = false;
@@ -305,7 +310,7 @@
String level = event.getLevel().toString().toLowerCase();
- StringBuffer buf = new StringBuffer();
+
buf.append(LINE_SEP);
buf.append("<tr class=\"");
buf.append(level);
@@ -355,6 +360,18 @@
return buf.toString();
}
+ private void handleTableClosing(StringBuffer sbuf) {
+ if (this.counter >= ROW_LIMIT) {
+ counter = 0;
+ sbuf.append("</table>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<br />");
+ sbuf.append("<table cellspacing=\"0\">");
+ sbuf.append(LINE_SEP);
+ createTableHeader(sbuf);
+ }
+ }
+
private void appendEventToBuffer(StringBuffer buf, Converter c, LoggingEvent event) {
buf.append("<td class=\"");
buf.append(computeConverterName(c));
Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
==============================================================================
--- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java (original)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java Tue Sep 12 11:48:40 2006
@@ -1,5 +1,7 @@
package ch.qos.logback.classic.html;
+import java.util.List;
+
import junit.framework.TestCase;
import org.dom4j.Document;
@@ -30,6 +32,7 @@
layout = new HTMLLayout();
layout.setContext(lc);
layout.setPattern("%level %thread %msg");
+ layout.setInternalCSS(true);
layout.start();
appender.setLayout(layout);
logger = lc.getLogger(LoggerContext.ROOT_NAME);
@@ -44,14 +47,22 @@
layout = null;
}
+ @SuppressWarnings("unchecked")
public void testHeader() throws Exception {
String header = layout.getHeader();
- // System.out.println(header);
- assertTrue(header.indexOf("Level") == 422);
- assertTrue(header.indexOf("Literal") == 456);
- assertTrue(header.indexOf("Thread") == 494);
- assertTrue(header.lastIndexOf("Literal") == 543);
- assertTrue(header.indexOf("Message") == 139);
+ //System.out.println(header);
+
+ Document doc = parseOutput(header + "</table></body></html>");
+ Element rootElement = doc.getRootElement();
+ Element bodyElement = rootElement.element("body");
+ Element tableElement = bodyElement.element("table");
+ Element trElement = tableElement.element("tr");
+ List<Element> elementList = trElement.elements();
+ assertEquals("Level", elementList.get(0).getText());
+ assertEquals("Literal", elementList.get(1).getText());
+ assertEquals("Thread", elementList.get(2).getText());
+ assertEquals("Literal", elementList.get(3).getText());
+ assertEquals("Message", elementList.get(4).getText());
}
public void testAppendThrowable() throws Exception {
@@ -93,6 +104,7 @@
// System.out.println(result);
}
+ @SuppressWarnings("unchecked")
public void testDoLayoutWithException() throws Exception {
layout.setPattern("%level %thread %msg %ex");
LoggingEvent le = createLoggingEvent();
@@ -100,44 +112,29 @@
"test Exception")));
String result = layout.doLayout(le);
- //System.out.println(result);
-
- Document doc = parseOutput(result);
- Element trElement = doc.getRootElement();
- assertEquals(6, trElement.elements().size());
- {
- Element tdElement = (Element) trElement.elements().get(0);
- assertEquals("DEBUG", tdElement.getText());
- }
- {
- Element tdElement = (Element) trElement.elements().get(1);
- assertEquals(" ", tdElement.getText());
- }
- {
- Element tdElement = (Element) trElement.elements().get(2);
- assertEquals("main", tdElement.getText());
- }
- {
- Element tdElement = (Element) trElement.elements().get(3);
- assertEquals(" ", tdElement.getText());
- }
- {
- Element tdElement = (Element) trElement.elements().get(4);
- assertEquals("test message", tdElement.getText());
- }
-// {
-// Element trElement2 = (Element) trElement.elements().get(5);
-// Element tdElement = (Element) trElement2.elements().get(0);
-// assertTrue(tdElement.getText().contains(
-// "java.lang.Exception: test Exception"));
-// }
+ String stringToParse = layout.getHeader();
+ stringToParse += result;
+ stringToParse += "</table></body></html>";
+
+ System.out.println(stringToParse);
+
+ Document doc = parseOutput(stringToParse);
+ Element rootElement = doc.getRootElement();
+ Element bodyElement = rootElement.element("body");
+ Element tableElement = bodyElement.element("table");
+ List<Element> trElementList = tableElement.elements();
+ Element exceptionRowElement = trElementList.get(2);
+ Element exceptionElement = exceptionRowElement.element("td");
+
+ assertEquals(3, tableElement.elements().size());
+ assertTrue(exceptionElement.getText().contains("java.lang.Exception: test Exception"));
}
- public void testLog() {
- for (int i = 0; i < 2000; i++) {
- logger.debug("test message");
- }
- }
+// public void testLog() {
+// for (int i = 1; i <= 100000; i++) {
+// logger.debug("test message" + i);
+// }
+// }
private LoggingEvent createLoggingEvent() {
LoggingEvent le = new LoggingEvent(this.getClass().getName(), logger,
1
0
Author: seb
Date: Tue Sep 12 09:35:04 2006
New Revision: 559
Added:
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/Transform.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/
logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
Modified:
logback/trunk/logback-classic/pom.xml
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/PatternLayout.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java
logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEvent.java
logback/trunk/pom.xml
Log:
- added HTMLLayout, work in progress
- defaultConverterMap in PatternLayout now is public, to allow sharing of the map with HTMLLayout
- added a Dom4j dependency for Classic tests, in pom.xml
- a few re-format of classes, replacing tabs by spaces
Modified: logback/trunk/logback-classic/pom.xml
==============================================================================
--- logback/trunk/logback-classic/pom.xml (original)
+++ logback/trunk/logback-classic/pom.xml Tue Sep 12 09:35:04 2006
@@ -42,7 +42,13 @@
<artifactId>mail</artifactId>
<scope>compile</scope>
</dependency>
-
+
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/PatternLayout.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/PatternLayout.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/PatternLayout.java Tue Sep 12 09:35:04 2006
@@ -38,7 +38,7 @@
// FIXME fix exception handling
- static final Map<String, String> defaultConverterMap = new HashMap<String, String>();
+ public static final Map<String, String> defaultConverterMap = new HashMap<String, String>();
static {
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/Transform.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/helpers/Transform.java Tue Sep 12 09:35:04 2006
@@ -0,0 +1,98 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ *
+ * 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.
+ */
+package ch.qos.logback.classic.helpers;
+
+/**
+ * Utility class for transforming strings.
+ *
+ * @author Ceki Gülcü
+ * @author Michael A. McAngus
+ */
+public class Transform {
+ private static final String CDATA_START = "<![CDATA[";
+ private static final String CDATA_END = "]]>";
+ private static final String CDATA_PSEUDO_END = "]]>";
+ private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END
+ + CDATA_START;
+ private static final int CDATA_END_LEN = CDATA_END.length();
+
+ /**
+ * This method takes a string which may contain HTML tags (ie, <b>,
+ * <table>, etc) and replaces any '<' and '>' characters with
+ * respective predefined entity references.
+ *
+ * @param input
+ * The text to be converted.
+ */
+ public static String escapeTags(final String input) {
+ // Check if the string is null or zero length -- if so, return
+ // what was sent in.
+ if ((input == null) || (input.length() == 0)
+ || (input.indexOf("<") == -1 && input.indexOf(">") == -1)) {
+ return input;
+ }
+
+ StringBuffer buf = new StringBuffer(input);
+ for (int i = 0; i < buf.length(); i++) {
+ char ch = buf.charAt(i);
+ if (ch == '<') {
+ buf.replace(i, i + 1, "<");
+ } else if (ch == '>') {
+ buf.replace(i, i + 1, ">");
+ }
+ }
+ return buf.toString();
+ }
+
+ // public static void appendEscapingCDATA(StringBuffer buf, String str) {
+ //
+ // }
+
+ /**
+ * Ensures that embeded CDEnd strings (]]>) are handled properly within
+ * message, NDC and throwable tag text.
+ *
+ * @param output
+ * Writer. The initial CDSutart (<![CDATA[) and final CDEnd (]]>) of
+ * the CDATA section are the responsibility of the calling method.
+ *
+ * @param str
+ * The String that is inserted into an existing CDATA Section.
+ */
+ public static void appendEscapingCDATA(StringBuffer output, String str) {
+ if (str == null) {
+ return;
+ }
+
+ int end = str.indexOf(CDATA_END);
+
+ if (end < 0) {
+ output.append(str);
+
+ return;
+ }
+
+ int start = 0;
+
+ while (end > -1) {
+ output.append(str.substring(start, end));
+ output.append(CDATA_EMBEDED_END);
+ start = end + CDATA_END_LEN;
+
+ if (start < str.length()) {
+ end = str.indexOf(CDATA_END, start);
+ } else {
+ return;
+ }
+ }
+
+ output.append(str.substring(start));
+ }
+}
Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/html/HTMLLayout.java Tue Sep 12 09:35:04 2006
@@ -0,0 +1,424 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ *
+ * 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.
+ */
+
+package ch.qos.logback.classic.html;
+
+import ch.qos.logback.classic.ClassicLayout;
+import ch.qos.logback.classic.PatternLayout;
+import ch.qos.logback.classic.helpers.Transform;
+import ch.qos.logback.classic.pattern.NopThrowableInformationConverter;
+import ch.qos.logback.classic.pattern.ThrowableHandlingConverter;
+import ch.qos.logback.classic.pattern.ThrowableInformationConverter;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.classic.spi.ThrowableInformation;
+import ch.qos.logback.core.LayoutBase;
+import ch.qos.logback.core.pattern.Converter;
+import ch.qos.logback.core.pattern.DynamicConverter;
+import ch.qos.logback.core.pattern.parser.Node;
+import ch.qos.logback.core.pattern.parser.Parser;
+import ch.qos.logback.core.pattern.parser.ScanException;
+
+/**
+ *
+ * HTMLLayout outputs events in an HTML table. The content of the table columns
+ * are specified using a conversion pattern. See
+ * {@link ch.qos.logback.classic.PatternLayout} for documentation on the
+ * available patterns.
+ *
+ * @author Ceki Gülcü
+ * @author Sébastien Pennec
+ */
+public class HTMLLayout extends LayoutBase implements ClassicLayout {
+
+ /**
+ * Default pattern string for log output. Currently set to the string <b>"%m"
+ * </b> which just prints the application supplied message.
+ */
+ static final String DEFAULT_CONVERSION_PATTERN = "%date%thread%level%logger%mdc%msg";
+
+ static final String TRACE_PREFIX = "<br /> ";
+ protected final int BUF_SIZE = 256;
+ protected final int MAX_CAPACITY = 1024;
+
+ private String pattern;
+
+ private Converter head;
+
+ //private String timezone;
+ private String title = "Logback Log Messages";
+ private boolean locationInfo;
+
+ private boolean internalCSS = false;
+ private String url2ExternalCSS = "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css";
+
+ // Does our PatternConverter chain handle throwable on its own?
+ private boolean chainHandlesThrowable;
+
+ // counter keeping track of the rows output
+ private long counter = 0;
+
+ /**
+ * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
+ *
+ * The default pattern just produces the application supplied message.
+ */
+ public HTMLLayout() {
+ pattern = DEFAULT_CONVERSION_PATTERN;
+ }
+
+ /**
+ * Set the <b>ConversionPattern </b> option. This is the string which controls
+ * formatting and consists of a mix of literal content and conversion
+ * specifiers.
+ */
+ public void setPattern(String conversionPattern) {
+ pattern = conversionPattern;
+ }
+
+ /**
+ * Returns the value of the <b>ConversionPattern </b> option.
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Parses the pattern and creates the Converter linked list.
+ */
+ public void start() {
+ try {
+ Parser p = new Parser(pattern);
+ if (getContext() != null) {
+ p.setStatusManager(getContext().getStatusManager());
+ }
+ Node t = p.parse();
+ this.head = p.compile(t, PatternLayout.defaultConverterMap);
+ postCompileProcessing(head);
+ DynamicConverter.startConverters(this.head);
+ } catch (ScanException ex) {
+ addError("Incorrect pattern found", ex);
+ }
+
+ started = true;
+ }
+
+ private void postCompileProcessing(Converter c) {
+ while (c != null) {
+ if (c instanceof ThrowableHandlingConverter) {
+ chainHandlesThrowable = true;
+ }
+ c = c.getNext();
+ }
+ chainHandlesThrowable = false;
+ }
+
+ /**
+ * The <b>Title </b> option takes a String value. This option sets the
+ * document title of the generated HTML document.
+ *
+ * <p>
+ * Defaults to 'Logback Log Messages'.
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * Returns the current value of the <b>Title </b> option.
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Returns the value of the internalCSS option. See {@link #setInternalCSS}
+ * method for details about the meaning of this option.
+ *
+ * @return boolean Value of internalCSS option
+ */
+ public boolean isInternalCSS() {
+ return internalCSS;
+ }
+
+ /**
+ * Set the value of the internalCSS option. If set to true, the generated HTML
+ * ouput will include an internal cascading style sheet. Otherwise, the
+ * generated HTML output will include a reference to an external CSS.
+ * <p>
+ * By default, <code>internalCSS</code> value is set to false, that is, by
+ * default, only a link to an external CSS file will be generated.
+ *
+ * @see #setURL2ExternalCSS
+ *
+ * @param internalCSS
+ */
+ public void setInternalCSS(boolean internalCSS) {
+ this.internalCSS = internalCSS;
+ }
+
+ /**
+ * Return the URL to the external CSS file. See {@link #setURL2ExternalCSS}
+ * method for details about the meaning of this option.
+ *
+ * @return URL to the external CSS file.
+ */
+ public String getURL2ExternalCSS() {
+ return url2ExternalCSS;
+ }
+
+ /**
+ * Set the URL for the external CSS file. By default, the external CSS file is
+ * set to "http://logging.apache.org/log4j/docs/css/eventTable-1.0.css".
+ */
+ public void setURL2ExternalCSS(String url2ExternalCSS) {
+ this.url2ExternalCSS = url2ExternalCSS;
+ }
+
+ /**
+ * Returns the content type output by this layout, i.e "text/html".
+ */
+ public String getContentType() {
+ return "text/html";
+ }
+
+ void appendThrowableAsHTML(final String[] s, final StringBuffer sbuf) {
+ if (s != null) {
+ int len = s.length;
+ if (len == 0) {
+ return;
+ }
+ sbuf.append(Transform.escapeTags(s[0]));
+ sbuf.append(LINE_SEP);
+ for (int i = 1; i < len; i++) {
+ sbuf.append(TRACE_PREFIX);
+ sbuf.append(Transform.escapeTags(s[i]));
+ sbuf.append(LINE_SEP);
+ }
+ }
+ }
+
+ /**
+ * Returns appropriate HTML headers.
+ */
+ public String getHeader() {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"");
+ sbuf.append(" \"http://www.w3.org/TR/html4/loose.dtd\">");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<html>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<head>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<title>");
+ sbuf.append(title);
+ sbuf.append("</title>");
+ sbuf.append(LINE_SEP);
+ if (internalCSS) {
+ getInternalCSS(sbuf);
+ } else {
+ sbuf.append("<LINK REL=StyleSheet HREF=\"");
+ sbuf.append(url2ExternalCSS);
+ sbuf.append("\" TITLE=\"Basic\">");
+ }
+ sbuf.append(LINE_SEP);
+ sbuf.append("</head>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<body>");
+ sbuf.append(LINE_SEP);
+
+ sbuf.append("<hr size=\"1\" noshade>");
+ sbuf.append(LINE_SEP);
+
+ sbuf.append("Log session start time ");
+ sbuf.append(new java.util.Date());
+ sbuf.append("<br>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<br>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<table cellspacing=\"0\">");
+ sbuf.append(LINE_SEP);
+
+ sbuf.append("<tr class=\"header\">");
+ sbuf.append(LINE_SEP);
+
+ Converter c = head;
+ String name;
+ while (c != null) {
+ name = computeConverterName(c);
+ if (name == null) {
+ c = c.getNext();
+ continue;
+ }
+ sbuf.append("<td class=\"");
+ sbuf.append(computeConverterName(c));
+ sbuf.append("\">");
+ sbuf.append("<td>");
+ sbuf.append(computeConverterName(c));
+ sbuf.append("</td>");
+ sbuf.append(LINE_SEP);
+ c = c.getNext();
+ }
+ sbuf.append("</tr>");
+ sbuf.append(LINE_SEP);
+
+ return sbuf.toString();
+ }
+
+ /**
+ * Returns the appropriate HTML footers.
+ */
+ public String getFooter() {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.append("</table>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("<br>");
+ sbuf.append(LINE_SEP);
+ sbuf.append("</body></html>");
+ return sbuf.toString();
+ }
+
+ /**
+ * The HTML layout handles the throwable contained in logging events. Hence,
+ * this method return <code>false</code>.
+ */
+ public boolean ignoresThrowable() {
+ return false;
+ }
+
+ public String doLayout(Object event) {
+ return doLayout((LoggingEvent) event);
+ }
+
+ public String doLayout(LoggingEvent event) {
+
+ boolean odd = true;
+ if (((counter++) & 1) == 0) {
+ odd = false;
+ }
+
+ String level = event.getLevel().toString().toLowerCase();
+
+ StringBuffer buf = new StringBuffer();
+ buf.append(LINE_SEP);
+ buf.append("<tr class=\"");
+ buf.append(level);
+ if (odd) {
+ buf.append(" odd\">");
+ } else {
+ buf.append(" even\">");
+ }
+ buf.append(LINE_SEP);
+
+ Converter c = head;
+ while (c != null) {
+ if (c instanceof ThrowableHandlingConverter) {
+ ThrowableHandlingConverter converter = (ThrowableHandlingConverter)c;
+ if (converter.onNewLine(event)) {
+ buf.append("</tr>");
+ buf.append("<tr>");
+ appendEventToBuffer(buf, c, event);
+ if (c.getNext() != null) {
+ //here we assume that when we exist the while loop,
+ //a </tr> tag is added.
+ buf.append("</tr>");
+ buf.append("<tr>");
+ }
+ }
+ } else {
+ appendEventToBuffer(buf, c, event);
+ }
+ c = c.getNext();
+ }
+ buf.append("</tr>");
+ buf.append(LINE_SEP);
+
+ // if the pattern chain handles throwables then no need to do it again here.
+ if (!chainHandlesThrowable) {
+ ThrowableInformation ti = event.getThrowableInformation();
+ if (ti != null) {
+ String[] s = ti.getThrowableStrRep();
+ if (s != null) {
+ buf.append("<tr><td class=\"Exception\" colspan=\"6\">");
+ appendThrowableAsHTML(s, buf);
+ buf.append("</td></tr>");
+ buf.append(LINE_SEP);
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ private void appendEventToBuffer(StringBuffer buf, Converter c, LoggingEvent event) {
+ buf.append("<td class=\"");
+ buf.append(computeConverterName(c));
+ buf.append("\">");
+ buf.append(c.convert(event));
+ buf.append("</td>");
+ buf.append(LINE_SEP);
+ }
+
+ /**
+ * Generate an internal CSS file.
+ *
+ * @param buf The StringBuffer where the CSS file will be placed.
+ */
+ void getInternalCSS(StringBuffer buf) {
+
+ buf.append("<STYLE type=\"text/css\">");
+ buf.append(LINE_SEP);
+ buf.append("table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.even { background: #FFFFFF; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.odd { background: #DADADA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.warn TD.level, TR.error TD.level, TR.fatal TD.level {font-weight: bold; color: #FF4040 }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Time, TD.Date { text-align: right; font-family: courier, monospace; font-size: smaller; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Thread { text-align: left; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Level { text-align: right; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Logger { text-align: left; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TR.header { background: #9090FF; color: #FFF; font-weight: bold; font-size: larger; }");
+ buf.append(LINE_SEP);
+
+ buf.append("TD.Exception { background: #C0C0F0; font-family: courier, monospace;}");
+ buf.append(LINE_SEP);
+
+ buf.append("</STYLE>");
+ buf.append(LINE_SEP);
+
+ }
+
+ private String computeConverterName(Converter c) {
+ String className = c.getClass().getSimpleName();
+ int index = className.indexOf("Converter");
+ if (index == -1) {
+ return className;
+ } else {
+ return className.substring(0, index);
+ }
+ }
+
+}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java Tue Sep 12 09:35:04 2006
@@ -50,342 +50,341 @@
* @since 1.0
*/
public class SMTPAppender extends AppenderBase {
- private Layout layout;
+ private Layout layout;
- private String to;
- private String from;
- private String subject;
- private String smtpHost;
- private int bufferSize = 512;
- private boolean locationInfo = false;
-
- protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
- protected Message msg;
-
- protected TriggeringPolicy evaluator;
-
- /**
- * The default constructor will instantiate the appender with a
- * {@link TriggeringEventEvaluator} that will trigger on events with level
- * ERROR or higher.
- */
- public SMTPAppender() {
- this(new DefaultEvaluator());
- }
-
- /**
- * Use <code>evaluator</code> passed as parameter as the {@link
- * TriggeringEventEvaluator} for this SMTPAppender.
- */
- public SMTPAppender(TriggeringPolicy evaluator) {
- this.evaluator = evaluator;
- }
-
- /**
- * Start the appender
- */
- public void start() {
- Properties props = new Properties(System.getProperties());
- if (smtpHost != null) {
- props.put("mail.smtp.host", smtpHost);
- }
-
- Session session = Session.getInstance(props, null);
- // session.setDebug(true);
- msg = new MimeMessage(session);
-
- try {
- if (from != null) {
- msg.setFrom(getAddress(from));
- } else {
- msg.setFrom();
- }
-
- msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
- if (subject != null) {
- msg.setSubject(subject);
- }
-
- started = true;
-
- } catch (MessagingException e) {
- addError("Could not activate SMTPAppender options.", e);
- }
- }
-
- /**
- * Perform SMTPAppender specific appending actions, mainly adding the event to
- * a cyclic buffer and checking if the event triggers an e-mail to be sent.
- */
- protected void append(Object eventObject) {
- LoggingEvent event = (LoggingEvent) eventObject;
-
- if (!checkEntryConditions()) {
- return;
- }
-
- event.getThreadName();
- // event.getNDC();
- // if (locationInfo) {
- // event.getLocationInformation();
- // }
- cb.add(event);
- //addInfo("Added event to the cyclic buffer: " + event.getMessage());
-
- if (evaluator.isTriggeringEvent(null, event)) {
- sendBuffer();
- }
- }
-
- /**
- * This method determines if there is a sense in attempting to append.
- *
- * <p>
- * It checks whether there is a set output target and also if there is a set
- * layout. If these checks fail, then the boolean value <code>false</code>
- * is returned.
- */
- protected boolean checkEntryConditions() {
- if (this.msg == null) {
- addError("Message object not configured.");
- return false;
- }
-
- if (this.evaluator == null) {
- addError("No TriggeringPolicy is set for appender [" + name + "].");
- return false;
- }
-
- if (this.layout == null) {
- addError("No layout set for appender named [" + name + "].");
- return false;
- }
- return true;
- }
-
- synchronized public void stop() {
- this.started = false;
- }
-
- InternetAddress getAddress(String addressStr) {
- try {
- return new InternetAddress(addressStr);
- } catch (AddressException e) {
- addError("Could not parse address [" + addressStr + "].", e);
- return null;
- }
- }
-
- InternetAddress[] parseAddress(String addressStr) {
- try {
- return InternetAddress.parse(addressStr, true);
- } catch (AddressException e) {
- addError("Could not parse address [" + addressStr + "].", e);
- return null;
- }
- }
-
- /**
- * Returns value of the <b>To</b> option.
- */
- public String getTo() {
- return to;
- }
-
- /**
- * Send the contents of the cyclic buffer as an e-mail message.
- */
- protected void sendBuffer() {
-
- // Note: this code already owns the monitor for this
- // appender. This frees us from needing to synchronize on 'cb'.
- try {
- MimeBodyPart part = new MimeBodyPart();
-
- StringBuffer sbuf = new StringBuffer();
- String t = layout.getHeader();
- if (t != null)
- sbuf.append(t);
- int len = cb.length();
- for (int i = 0; i < len; i++) {
- //sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
- LoggingEvent event = cb.get();
- sbuf.append(layout.doLayout(event));
- // if (layout.ignoresThrowable()) {
- // String[] s = event.getThrowableStrRep();
- // if (s != null) {
- // for (int j = 0; j < s.length; j++) {
- // sbuf.append(s[j]);
- // }
- // }
- // }
- }
- t = layout.getFooter();
- if (t != null)
- sbuf.append(t);
- part.setContent(sbuf.toString(), "text/plain");
-
- Multipart mp = new MimeMultipart();
- mp.addBodyPart(part);
- msg.setContent(mp);
-
- msg.setSentDate(new Date());
- Transport.send(msg);
- } catch (Exception e) {
- addError("Error occured while sending e-mail notification.", e);
- }
- }
-
- /**
- * Returns value of the <b>EvaluatorClass</b> option.
- */
- public String getEvaluatorClass() {
- return evaluator == null ? null : evaluator.getClass().getName();
- }
-
- /**
- * Returns value of the <b>From</b> option.
- */
- public String getFrom() {
- return from;
- }
-
- /**
- * Returns value of the <b>Subject</b> option.
- */
- public String getSubject() {
- return subject;
- }
-
- /**
- * The <b>From</b> option takes a string value which should be a e-mail
- * address of the sender.
- */
- public void setFrom(String from) {
- this.from = from;
- }
-
- /**
- * The <b>Subject</b> option takes a string value which should be a the
- * subject of the e-mail message.
- */
- public void setSubject(String subject) {
- this.subject = subject;
- }
-
- /**
- * The <b>BufferSize</b> option takes a positive integer representing the
- * maximum number of logging events to collect in a cyclic buffer. When the
- * <code>BufferSize</code> is reached, oldest events are deleted as new
- * events are added to the buffer. By default the size of the cyclic buffer is
- * 512 events.
- */
- public void setBufferSize(int bufferSize) {
- this.bufferSize = bufferSize;
- cb.resize(bufferSize);
- }
-
- /**
- * The <b>SMTPHost</b> option takes a string value which should be a the host
- * name of the SMTP server that will send the e-mail message.
- */
- public void setSMTPHost(String smtpHost) {
- this.smtpHost = smtpHost;
- }
-
- /**
- * Returns value of the <b>SMTPHost</b> option.
- */
- public String getSMTPHost() {
- return smtpHost;
- }
-
- /**
- * The <b>To</b> option takes a string value which should be a comma
- * separated list of e-mail address of the recipients.
- */
- public void setTo(String to) {
- this.to = to;
- }
-
- /**
- * Returns value of the <b>BufferSize</b> option.
- */
- public int getBufferSize() {
- return bufferSize;
- }
-
- /**
- * The <b>EvaluatorClass</b> option takes a string value representing the
- * name of the class implementing the {@link TriggeringEventEvaluator}
- * interface. A corresponding object will be instantiated and assigned as the
- * triggering event evaluator for the SMTPAppender.
- */
- public void setEvaluatorClass(String value) {
- try {
- evaluator = (TriggeringPolicy) OptionHelper.instantiateByClassName(value,
- TriggeringPolicy.class);
- } catch (Exception ex) {
- addError("Evaluator class instanciation failed");
- }
- }
-
- /**
- * The <b>LocationInfo</b> option takes a boolean value. By default, it is
- * set to false which means there will be no effort to extract the location
- * information related to the event. As a result, the layout that formats the
- * events as they are sent out in an e-mail is likely to place the wrong
- * location information (if present in the format).
- *
- * <p>
- * Location information extraction is comparatively very slow and should be
- * avoided unless performance is not a concern.
- */
- public void setLocationInfo(boolean locationInfo) {
- this.locationInfo = locationInfo;
- }
-
- /**
- * Returns value of the <b>LocationInfo</b> option.
- */
- public boolean getLocationInfo() {
- return locationInfo;
- }
-
- public Layout getLayout() {
- return layout;
- }
-
- public void setLayout(Layout layout) {
- this.layout = layout;
- }
+ private String to;
+ private String from;
+ private String subject;
+ private String smtpHost;
+ private int bufferSize = 512;
+ private boolean locationInfo = false;
+
+ protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
+ protected Message msg;
+
+ protected TriggeringPolicy evaluator;
+
+ /**
+ * The default constructor will instantiate the appender with a
+ * {@link TriggeringEventEvaluator} that will trigger on events with level
+ * ERROR or higher.
+ */
+ public SMTPAppender() {
+ this(new DefaultEvaluator());
+ }
+
+ /**
+ * Use <code>evaluator</code> passed as parameter as the {@link
+ * TriggeringEventEvaluator} for this SMTPAppender.
+ */
+ public SMTPAppender(TriggeringPolicy evaluator) {
+ this.evaluator = evaluator;
+ }
+
+ /**
+ * Start the appender
+ */
+ public void start() {
+ Properties props = new Properties(System.getProperties());
+ if (smtpHost != null) {
+ props.put("mail.smtp.host", smtpHost);
+ }
+
+ Session session = Session.getInstance(props, null);
+ // session.setDebug(true);
+ msg = new MimeMessage(session);
+
+ try {
+ if (from != null) {
+ msg.setFrom(getAddress(from));
+ } else {
+ msg.setFrom();
+ }
+
+ msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
+ if (subject != null) {
+ msg.setSubject(subject);
+ }
+
+ started = true;
+
+ } catch (MessagingException e) {
+ addError("Could not activate SMTPAppender options.", e);
+ }
+ }
+
+ /**
+ * Perform SMTPAppender specific appending actions, mainly adding the event to
+ * a cyclic buffer and checking if the event triggers an e-mail to be sent.
+ */
+ protected void append(Object eventObject) {
+ LoggingEvent event = (LoggingEvent) eventObject;
+
+ if (!checkEntryConditions()) {
+ return;
+ }
+
+ event.getThreadName();
+ // if (locationInfo) {
+ // event.getLocationInformation();
+ // }
+ cb.add(event);
+ // addInfo("Added event to the cyclic buffer: " + event.getMessage());
+
+ if (evaluator.isTriggeringEvent(null, event)) {
+ sendBuffer();
+ }
+ }
+
+ /**
+ * This method determines if there is a sense in attempting to append.
+ *
+ * <p>
+ * It checks whether there is a set output target and also if there is a set
+ * layout. If these checks fail, then the boolean value <code>false</code>
+ * is returned.
+ */
+ protected boolean checkEntryConditions() {
+ if (this.msg == null) {
+ addError("Message object not configured.");
+ return false;
+ }
+
+ if (this.evaluator == null) {
+ addError("No TriggeringPolicy is set for appender [" + name + "].");
+ return false;
+ }
+
+ if (this.layout == null) {
+ addError("No layout set for appender named [" + name + "].");
+ return false;
+ }
+ return true;
+ }
+
+ synchronized public void stop() {
+ this.started = false;
+ }
+
+ InternetAddress getAddress(String addressStr) {
+ try {
+ return new InternetAddress(addressStr);
+ } catch (AddressException e) {
+ addError("Could not parse address [" + addressStr + "].", e);
+ return null;
+ }
+ }
+
+ InternetAddress[] parseAddress(String addressStr) {
+ try {
+ return InternetAddress.parse(addressStr, true);
+ } catch (AddressException e) {
+ addError("Could not parse address [" + addressStr + "].", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns value of the <b>To</b> option.
+ */
+ public String getTo() {
+ return to;
+ }
+
+ /**
+ * Send the contents of the cyclic buffer as an e-mail message.
+ */
+ protected void sendBuffer() {
+
+ // Note: this code already owns the monitor for this
+ // appender. This frees us from needing to synchronize on 'cb'.
+ try {
+ MimeBodyPart part = new MimeBodyPart();
+
+ StringBuffer sbuf = new StringBuffer();
+ String t = layout.getHeader();
+ if (t != null)
+ sbuf.append(t);
+ int len = cb.length();
+ for (int i = 0; i < len; i++) {
+ // sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
+ LoggingEvent event = cb.get();
+ sbuf.append(layout.doLayout(event));
+ // if (layout.ignoresThrowable()) {
+ // String[] s = event.getThrowableStrRep();
+ // if (s != null) {
+ // for (int j = 0; j < s.length; j++) {
+ // sbuf.append(s[j]);
+ // }
+ // }
+ // }
+ }
+ t = layout.getFooter();
+ if (t != null)
+ sbuf.append(t);
+ part.setContent(sbuf.toString(), "text/plain");
+
+ Multipart mp = new MimeMultipart();
+ mp.addBodyPart(part);
+ msg.setContent(mp);
+
+ msg.setSentDate(new Date());
+ Transport.send(msg);
+ } catch (Exception e) {
+ addError("Error occured while sending e-mail notification.", e);
+ }
+ }
+
+ /**
+ * Returns value of the <b>EvaluatorClass</b> option.
+ */
+ public String getEvaluatorClass() {
+ return evaluator == null ? null : evaluator.getClass().getName();
+ }
+
+ /**
+ * Returns value of the <b>From</b> option.
+ */
+ public String getFrom() {
+ return from;
+ }
+
+ /**
+ * Returns value of the <b>Subject</b> option.
+ */
+ public String getSubject() {
+ return subject;
+ }
+
+ /**
+ * The <b>From</b> option takes a string value which should be a e-mail
+ * address of the sender.
+ */
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ /**
+ * The <b>Subject</b> option takes a string value which should be a the
+ * subject of the e-mail message.
+ */
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ /**
+ * The <b>BufferSize</b> option takes a positive integer representing the
+ * maximum number of logging events to collect in a cyclic buffer. When the
+ * <code>BufferSize</code> is reached, oldest events are deleted as new
+ * events are added to the buffer. By default the size of the cyclic buffer is
+ * 512 events.
+ */
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ cb.resize(bufferSize);
+ }
+
+ /**
+ * The <b>SMTPHost</b> option takes a string value which should be a the host
+ * name of the SMTP server that will send the e-mail message.
+ */
+ public void setSMTPHost(String smtpHost) {
+ this.smtpHost = smtpHost;
+ }
+
+ /**
+ * Returns value of the <b>SMTPHost</b> option.
+ */
+ public String getSMTPHost() {
+ return smtpHost;
+ }
+
+ /**
+ * The <b>To</b> option takes a string value which should be a comma
+ * separated list of e-mail address of the recipients.
+ */
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ /**
+ * Returns value of the <b>BufferSize</b> option.
+ */
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ /**
+ * The <b>EvaluatorClass</b> option takes a string value representing the
+ * name of the class implementing the {@link TriggeringEventEvaluator}
+ * interface. A corresponding object will be instantiated and assigned as the
+ * triggering event evaluator for the SMTPAppender.
+ */
+ public void setEvaluatorClass(String value) {
+ try {
+ evaluator = (TriggeringPolicy) OptionHelper.instantiateByClassName(value,
+ TriggeringPolicy.class);
+ } catch (Exception ex) {
+ addError("Evaluator class instanciation failed");
+ }
+ }
+
+ /**
+ * The <b>LocationInfo</b> option takes a boolean value. By default, it is
+ * set to false which means there will be no effort to extract the location
+ * information related to the event. As a result, the layout that formats the
+ * events as they are sent out in an e-mail is likely to place the wrong
+ * location information (if present in the format).
+ *
+ * <p>
+ * Location information extraction is comparatively very slow and should be
+ * avoided unless performance is not a concern.
+ */
+ public void setLocationInfo(boolean locationInfo) {
+ this.locationInfo = locationInfo;
+ }
+
+ /**
+ * Returns value of the <b>LocationInfo</b> option.
+ */
+ public boolean getLocationInfo() {
+ return locationInfo;
+ }
+
+ public Layout getLayout() {
+ return layout;
+ }
+
+ public void setLayout(Layout layout) {
+ this.layout = layout;
+ }
}
class DefaultEvaluator implements TriggeringPolicy {
- private boolean started;
+ private boolean started;
- /**
- * Is this <code>event</code> the e-mail triggering event?
- *
- * <p>
- * This method returns <code>true</code>, if the event level has ERROR
- * level or higher. Otherwise it returns <code>false</code>.
- */
- public boolean isTriggeringEvent(File file, Object eventObject) {
- LoggingEvent event = (LoggingEvent) eventObject;
- return event.getLevel().isGreaterOrEqual(Level.ERROR);
- }
-
- public boolean isStarted() {
- return started == true;
- }
-
- public void start() {
- started = true;
- }
-
- public void stop() {
- started = false;
- }
+ /**
+ * Is this <code>event</code> the e-mail triggering event?
+ *
+ * <p>
+ * This method returns <code>true</code>, if the event level has ERROR
+ * level or higher. Otherwise it returns <code>false</code>.
+ */
+ public boolean isTriggeringEvent(File file, Object eventObject) {
+ LoggingEvent event = (LoggingEvent) eventObject;
+ return event.getLevel().isGreaterOrEqual(Level.ERROR);
+ }
+
+ public boolean isStarted() {
+ return started == true;
+ }
+
+ public void start() {
+ started = true;
+ }
+
+ public void stop() {
+ started = false;
+ }
}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java Tue Sep 12 09:35:04 2006
@@ -1,6 +1,7 @@
package ch.qos.logback.classic.pattern;
import ch.qos.logback.classic.pattern.ClassicConverter;
+import ch.qos.logback.classic.spi.LoggingEvent;
/**
@@ -12,4 +13,9 @@
boolean handlesThrowable() {
return true;
}
+
+ // tentatively...
+ public boolean onNewLine(LoggingEvent le) {
+ return le.getThrowableInformation() != null;
+ }
}
Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEvent.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEvent.java (original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggingEvent.java Tue Sep 12 09:35:04 2006
@@ -41,247 +41,247 @@
*/
public class LoggingEvent implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 3022264832697160750L;
-
- /**
- *
- */
- private static long startTime = System.currentTimeMillis();
-
- /**
- * Fully qualified name of the calling Logger class. This field does not
- * survive serialization.
- *
- * <p>
- * Note that the getCallerInformation() method relies on this fact.
- */
- transient String fqnOfLoggerClass;
-
- /**
- * The name of thread in which this logging event was generated.
- */
- private String threadName;
-
- /**
- * Level of logging event.
- *
- * <p>
- * This field should not be accessed directly. You shoud use the {@link
- * #getLevel} method instead.
- * </p>
- *
- */
- private transient Level level;
-
- private String message;
- private String formattedMessage;
-
- private Object[] argumentArray;
-
- private ThrowableInformation throwableInfo;
-
- private CallerData[] callerDataArray;
- private LoggerRemoteView loggerRemoteView;
-
- private Marker marker;
-
- private Map<String, String> mdcPropertyMap;
-
- /**
- * The number of milliseconds elapsed from 1/1/1970 until logging event was
- * created.
- */
- private long timeStamp;
-
- public LoggingEvent() {
- }
-
- public LoggingEvent(String fqcn, Logger logger, Level level, String message,
- Throwable throwable, Object[] argArray) {
- this.fqnOfLoggerClass = fqcn;
- this.loggerRemoteView = logger.getLoggerRemoteView();
- this.level = level;
- this.message = message;
-
- if (throwable != null) {
- this.throwableInfo = new ThrowableInformation(throwable);
- }
-
- if (argArray != null) {
- formattedMessage = MessageFormatter.arrayFormat(message, argArray);
- } else {
- formattedMessage = message;
- }
- timeStamp = System.currentTimeMillis();
-
- mdcPropertyMap = MDC.getPropertyMap();
- }
-
- public void setArgumentArray(Object[] argArray) {
- if (this.argumentArray != null) {
- throw new IllegalStateException("argArray has been already set");
- }
- this.argumentArray = argArray;
- }
-
- public Object[] getArgumentArray() {
- return this.argumentArray;
- }
-
- public Level getLevel() {
- return level;
- }
-
- public String getThreadName() {
- if (threadName == null) {
- threadName = (Thread.currentThread()).getName();
- }
- return threadName;
- }
-
- /**
- * @param threadName
- * The threadName to set.
- * @throws IllegalStateException
- * If threadName has been already set.
- */
- public void setThreadName(String threadName) throws IllegalStateException {
- if (this.threadName != null) {
- throw new IllegalStateException("threadName has been already set");
- }
- this.threadName = threadName;
- }
-
- /**
- * Returns the throwable information contained within this event. May be
- * <code>null</code> if there is no such information.
- */
- public ThrowableInformation getThrowableInformation() {
- return throwableInfo;
- }
-
- /**
- * Set this event's throwable information.
- */
- public void setThrowableInformation(ThrowableInformation ti) {
- if (throwableInfo != null) {
- throw new IllegalStateException(
- "ThrowableInformation has been already set.");
- } else {
- throwableInfo = ti;
- }
- }
-
- /**
- * This method should be called prior to serializing an event. It should also
- * be called when using asynchronous logging.
- */
- public void prepareForDeferredProcessing() {
- this.getThreadName();
- }
-
- public LoggerRemoteView getLoggerRemoteView() {
- return loggerRemoteView;
- }
-
- public void setLoggerRemoteView(LoggerRemoteView loggerRemoteView) {
- this.loggerRemoteView = loggerRemoteView;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- if (this.message != null) {
- throw new IllegalStateException(
- "The message for this event has been set already.");
- }
- this.message = message;
- }
-
- public long getTimeStamp() {
- return timeStamp;
- }
-
- public void setTimeStamp(long timeStamp) {
- this.timeStamp = timeStamp;
- }
-
- public void setLevel(Level level) {
- if (this.level != null) {
- throw new IllegalStateException(
- "The level has been already set for this event.");
- }
- this.level = level;
- }
-
- /**
- * The time at which this class was loaded into memory, expressed in
- * millisecond elapsed since the epoch (1.1.1970).
- *
- * @return The time as measured when this class was loaded into memory.
- */
- public static final long getStartTime() {
- return startTime;
- }
-
- /**
- * Get the caller information for this logging event. If caller information is
- * null at the time of its invocation, this method extracts location
- * information. The collected information is cached for future use.
- *
- * <p>
- * Note that after serialization it is impossible to correctly extract caller
- * information.
- * </p>
- */
- public CallerData[] getCallerData() {
- // we rely on the fact that fqnOfLoggerClass does not survive
- // serialization
- if (callerDataArray == null && fqnOfLoggerClass != null) {
- callerDataArray = CallerData.extract(new Throwable(), fqnOfLoggerClass);
- }
- return callerDataArray;
- }
-
- public void setCallerInformation(CallerData[] callerDataArray) {
- this.callerDataArray = callerDataArray;
- }
-
- public Marker getMarker() {
- return marker;
- }
-
- public void setMarker(Marker marker) {
- if (this.marker != null) {
- throw new IllegalStateException(
- "The marker has been already set for this event.");
- }
- this.marker = marker;
- }
-
- public String getFormattedMessage() {
- return formattedMessage;
- }
-
- public Map<String, String> getMDCPropertyMap() {
- return mdcPropertyMap;
- }
-
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.defaultWriteObject();
- out.writeInt(level.levelInt);
- }
-
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- in.defaultReadObject();
- int levelInt = in.readInt();
- level = Level.toLevel(levelInt);
- }
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3022264832697160750L;
+
+ /**
+ *
+ */
+ private static long startTime = System.currentTimeMillis();
+
+ /**
+ * Fully qualified name of the calling Logger class. This field does not
+ * survive serialization.
+ *
+ * <p>
+ * Note that the getCallerInformation() method relies on this fact.
+ */
+ transient String fqnOfLoggerClass;
+
+ /**
+ * The name of thread in which this logging event was generated.
+ */
+ private String threadName;
+
+ /**
+ * Level of logging event.
+ *
+ * <p>
+ * This field should not be accessed directly. You shoud use the {@link
+ * #getLevel} method instead.
+ * </p>
+ *
+ */
+ private transient Level level;
+
+ private String message;
+ private String formattedMessage;
+
+ private Object[] argumentArray;
+
+ private ThrowableInformation throwableInfo;
+
+ private CallerData[] callerDataArray;
+ private LoggerRemoteView loggerRemoteView;
+
+ private Marker marker;
+
+ private Map<String, String> mdcPropertyMap;
+
+ /**
+ * The number of milliseconds elapsed from 1/1/1970 until logging event was
+ * created.
+ */
+ private long timeStamp;
+
+ public LoggingEvent() {
+ }
+
+ public LoggingEvent(String fqcn, Logger logger, Level level, String message,
+ Throwable throwable, Object[] argArray) {
+ this.fqnOfLoggerClass = fqcn;
+ this.loggerRemoteView = logger.getLoggerRemoteView();
+ this.level = level;
+ this.message = message;
+
+ if (throwable != null) {
+ this.throwableInfo = new ThrowableInformation(throwable);
+ }
+
+ if (argArray != null) {
+ formattedMessage = MessageFormatter.arrayFormat(message, argArray);
+ } else {
+ formattedMessage = message;
+ }
+ timeStamp = System.currentTimeMillis();
+
+ mdcPropertyMap = MDC.getPropertyMap();
+ }
+
+ public void setArgumentArray(Object[] argArray) {
+ if (this.argumentArray != null) {
+ throw new IllegalStateException("argArray has been already set");
+ }
+ this.argumentArray = argArray;
+ }
+
+ public Object[] getArgumentArray() {
+ return this.argumentArray;
+ }
+
+ public Level getLevel() {
+ return level;
+ }
+
+ public String getThreadName() {
+ if (threadName == null) {
+ threadName = (Thread.currentThread()).getName();
+ }
+ return threadName;
+ }
+
+ /**
+ * @param threadName
+ * The threadName to set.
+ * @throws IllegalStateException
+ * If threadName has been already set.
+ */
+ public void setThreadName(String threadName) throws IllegalStateException {
+ if (this.threadName != null) {
+ throw new IllegalStateException("threadName has been already set");
+ }
+ this.threadName = threadName;
+ }
+
+ /**
+ * Returns the throwable information contained within this event. May be
+ * <code>null</code> if there is no such information.
+ */
+ public ThrowableInformation getThrowableInformation() {
+ return throwableInfo;
+ }
+
+ /**
+ * Set this event's throwable information.
+ */
+ public void setThrowableInformation(ThrowableInformation ti) {
+ if (throwableInfo != null) {
+ throw new IllegalStateException(
+ "ThrowableInformation has been already set.");
+ } else {
+ throwableInfo = ti;
+ }
+ }
+
+ /**
+ * This method should be called prior to serializing an event. It should also
+ * be called when using asynchronous logging.
+ */
+ public void prepareForDeferredProcessing() {
+ this.getThreadName();
+ }
+
+ public LoggerRemoteView getLoggerRemoteView() {
+ return loggerRemoteView;
+ }
+
+ public void setLoggerRemoteView(LoggerRemoteView loggerRemoteView) {
+ this.loggerRemoteView = loggerRemoteView;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ if (this.message != null) {
+ throw new IllegalStateException(
+ "The message for this event has been set already.");
+ }
+ this.message = message;
+ }
+
+ public long getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void setTimeStamp(long timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ public void setLevel(Level level) {
+ if (this.level != null) {
+ throw new IllegalStateException(
+ "The level has been already set for this event.");
+ }
+ this.level = level;
+ }
+
+ /**
+ * The time at which this class was loaded into memory, expressed in
+ * millisecond elapsed since the epoch (1.1.1970).
+ *
+ * @return The time as measured when this class was loaded into memory.
+ */
+ public static final long getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Get the caller information for this logging event. If caller information is
+ * null at the time of its invocation, this method extracts location
+ * information. The collected information is cached for future use.
+ *
+ * <p>
+ * Note that after serialization it is impossible to correctly extract caller
+ * information.
+ * </p>
+ */
+ public CallerData[] getCallerData() {
+ // we rely on the fact that fqnOfLoggerClass does not survive
+ // serialization
+ if (callerDataArray == null && fqnOfLoggerClass != null) {
+ callerDataArray = CallerData.extract(new Throwable(), fqnOfLoggerClass);
+ }
+ return callerDataArray;
+ }
+
+ public void setCallerInformation(CallerData[] callerDataArray) {
+ this.callerDataArray = callerDataArray;
+ }
+
+ public Marker getMarker() {
+ return marker;
+ }
+
+ public void setMarker(Marker marker) {
+ if (this.marker != null) {
+ throw new IllegalStateException(
+ "The marker has been already set for this event.");
+ }
+ this.marker = marker;
+ }
+
+ public String getFormattedMessage() {
+ return formattedMessage;
+ }
+
+ public Map<String, String> getMDCPropertyMap() {
+ return mdcPropertyMap;
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ out.writeInt(level.levelInt);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
+ in.defaultReadObject();
+ int levelInt = in.readInt();
+ level = Level.toLevel(levelInt);
+ }
}
Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/html/HTMLLayoutTest.java Tue Sep 12 09:35:04 2006
@@ -0,0 +1,158 @@
+package ch.qos.logback.classic.html;
+
+import junit.framework.TestCase;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.classic.spi.ThrowableInformation;
+import ch.qos.logback.core.appender.ListAppender;
+
+public class HTMLLayoutTest extends TestCase {
+
+ LoggerContext lc;
+ Logger logger;
+ HTMLLayout layout;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ lc = new LoggerContext();
+ lc.setName("default");
+
+ ListAppender appender = new ListAppender();
+ appender.setContext(lc);
+ layout = new HTMLLayout();
+ layout.setContext(lc);
+ layout.setPattern("%level %thread %msg");
+ layout.start();
+ appender.setLayout(layout);
+ logger = lc.getLogger(LoggerContext.ROOT_NAME);
+ logger.addAppender(appender);
+ appender.start();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ lc = null;
+ layout = null;
+ }
+
+ public void testHeader() throws Exception {
+ String header = layout.getHeader();
+ // System.out.println(header);
+ assertTrue(header.indexOf("Level") == 422);
+ assertTrue(header.indexOf("Literal") == 456);
+ assertTrue(header.indexOf("Thread") == 494);
+ assertTrue(header.lastIndexOf("Literal") == 543);
+ assertTrue(header.indexOf("Message") == 139);
+ }
+
+ public void testAppendThrowable() throws Exception {
+ StringBuffer buf = new StringBuffer();
+ String[] strArray = { "test1", "test2" };
+ layout.appendThrowableAsHTML(strArray, buf);
+ // System.out.println(buf.toString());
+ String[] result = buf.toString().split(HTMLLayout.LINE_SEP);
+ assertEquals("test1", result[0]);
+ assertEquals(HTMLLayout.TRACE_PREFIX + "test2", result[1]);
+ }
+
+ public void testDoLayout() throws Exception {
+ LoggingEvent le = createLoggingEvent();
+ String result = layout.doLayout(le);
+ Document doc = parseOutput(result);
+ Element trElement = doc.getRootElement();
+ assertEquals(5, trElement.elements().size());
+ {
+ Element tdElement = (Element) trElement.elements().get(0);
+ assertEquals("DEBUG", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(1);
+ assertEquals(" ", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(2);
+ assertEquals("main", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(3);
+ assertEquals(" ", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(4);
+ assertEquals("test message", tdElement.getText());
+ }
+ // System.out.println(result);
+ }
+
+ public void testDoLayoutWithException() throws Exception {
+ layout.setPattern("%level %thread %msg %ex");
+ LoggingEvent le = createLoggingEvent();
+ le.setThrowableInformation(new ThrowableInformation(new Exception(
+ "test Exception")));
+ String result = layout.doLayout(le);
+
+ //System.out.println(result);
+
+ Document doc = parseOutput(result);
+ Element trElement = doc.getRootElement();
+ assertEquals(6, trElement.elements().size());
+ {
+ Element tdElement = (Element) trElement.elements().get(0);
+ assertEquals("DEBUG", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(1);
+ assertEquals(" ", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(2);
+ assertEquals("main", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(3);
+ assertEquals(" ", tdElement.getText());
+ }
+ {
+ Element tdElement = (Element) trElement.elements().get(4);
+ assertEquals("test message", tdElement.getText());
+ }
+// {
+// Element trElement2 = (Element) trElement.elements().get(5);
+// Element tdElement = (Element) trElement2.elements().get(0);
+// assertTrue(tdElement.getText().contains(
+// "java.lang.Exception: test Exception"));
+// }
+ }
+
+ public void testLog() {
+ for (int i = 0; i < 2000; i++) {
+ logger.debug("test message");
+ }
+ }
+
+ private LoggingEvent createLoggingEvent() {
+ LoggingEvent le = new LoggingEvent(this.getClass().getName(), logger,
+ Level.DEBUG, "test message", null, null);
+ return le;
+ }
+
+ Document parseOutput(String output) {
+ try {
+ Document document = DocumentHelper.parseText(output);
+ return document;
+ } catch (Exception e) {
+ System.err.println(e);
+ fail();
+ }
+ return null;
+ }
+}
Modified: logback/trunk/pom.xml
==============================================================================
--- logback/trunk/pom.xml (original)
+++ logback/trunk/pom.xml Tue Sep 12 09:35:04 2006
@@ -64,7 +64,11 @@
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
-
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1</version>
+ </dependency>
<!-- Access Module Dependencies -->
<dependency>
1
0

svn commit: r558 - logback/trunk/logback-site/src/site/xdocTemplates
by noreply.ceki@qos.ch 11 Sep '06
by noreply.ceki@qos.ch 11 Sep '06
11 Sep '06
Author: ceki
Date: Mon Sep 11 23:38:20 2006
New Revision: 558
Modified:
logback/trunk/logback-site/src/site/xdocTemplates/license.xml
Log:
minor update
Modified: logback/trunk/logback-site/src/site/xdocTemplates/license.xml
==============================================================================
--- logback/trunk/logback-site/src/site/xdocTemplates/license.xml (original)
+++ logback/trunk/logback-site/src/site/xdocTemplates/license.xml Mon Sep 11 23:38:20 2006
@@ -28,6 +28,10 @@
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation.</div>
+ <p>Please note that logback is intended to be used behind the
+ SLF4J API, which is licensed under <a
+ href="http://www.slf4j.org/license.html">an X11 type license</a>.
+ </p>
</body>
</document>
\ No newline at end of file
1
0