
Author: seb Date: Mon Nov 13 11:36:19 2006 New Revision: 900 Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java Log: Modified SyslogAppender so that events containing an exception result in multiple sendings to the server. Updated test class. Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java ============================================================================== --- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java (original) +++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/net/SyslogAppender.java Mon Nov 13 11:36:19 2006 @@ -9,12 +9,15 @@ */ package ch.qos.logback.classic.net; +import java.io.IOException; + import ch.qos.logback.classic.PatternLayout; import ch.qos.logback.classic.pattern.SyslogStartConverter; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.classic.util.LevelToSyslogSeverity; import ch.qos.logback.core.Layout; import ch.qos.logback.core.net.SyslogAppenderBase; +import ch.qos.logback.core.net.SyslogWriter; /** * @@ -23,31 +26,37 @@ public class SyslogAppender extends SyslogAppenderBase { String prefixPattern; - - static final public String DEFAULT_SUFFIX_PATTERN = "[%thread] %logger %msg %exception"; - + PatternLayout prefixLayout; + + static final public String DEFAULT_SUFFIX_PATTERN = "[%thread] %logger %msg"; + public Layout buildLayout(String facilityStr) { - - PatternLayout pl = new PatternLayout(); - pl.getInstanceConverterMap().put("syslogStart", SyslogStartConverter.class.getName()); + + prefixPattern = "%syslogStart{" + facilityStr + "}%nopex"; + prefixLayout = new PatternLayout(); + prefixLayout.getInstanceConverterMap().put("syslogStart", + SyslogStartConverter.class.getName()); + prefixLayout.setPattern(prefixPattern); + prefixLayout.setContext(getContext()); + prefixLayout.start(); - if(prefixPattern == null) { - prefixPattern = "%syslogStart{"+facilityStr+"}"; - } + PatternLayout fullLayout = new PatternLayout(); + fullLayout.getInstanceConverterMap().put("syslogStart", + SyslogStartConverter.class.getName()); - if(suffixPattern == null) { + if (suffixPattern == null) { suffixPattern = DEFAULT_SUFFIX_PATTERN; } - - pl.setPattern(prefixPattern+suffixPattern); - pl.setContext(getContext()); - pl.start(); - return pl; + + fullLayout.setPattern(prefixPattern + suffixPattern); + fullLayout.setContext(getContext()); + fullLayout.start(); + return fullLayout; } - + /* - * Convert a level to equivalent syslog severity. Only levels for printing methods - * i.e DEBUG, WARN, INFO and ERROR are converted. + * Convert a level to equivalent syslog severity. Only levels for printing + * methods i.e DEBUG, WARN, INFO and ERROR are converted. * * @see ch.qos.logback.core.net.SyslogAppenderBase#getSeverityForEvent(java.lang.Object) */ @@ -57,4 +66,24 @@ return LevelToSyslogSeverity.convert(event); } + @Override + protected void postProcess(Object eventObject, SyslogWriter sw) { + LoggingEvent event = (LoggingEvent) eventObject; + + String prefix = prefixLayout.doLayout(event); + + if (event.getThrowableInformation() != null) { + String[] strRep = event.getThrowableInformation().getThrowableStrRep(); + try { + for (String line : strRep) { + sw.write(prefix + line); + sw.flush(); + } + } catch (IOException e) { + } + + } + + } + } Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/MockSyslogServer.java Mon Nov 13 11:36:19 2006 @@ -44,9 +44,9 @@ for (int i = 0; i < loopLen; i++) { byte[] buf = new byte[2048]; DatagramPacket packet = new DatagramPacket(buf, buf.length); - System.out.println("Waiting for message"); + //System.out.println("Waiting for message"); socket.receive(packet); - System.out.println("Got message"); + //System.out.println("Got message"); String msg = new String(buf, 0, packet.getLength()); msgList.add(msg); } Modified: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java ============================================================================== --- logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java (original) +++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/net/SyslogAppenderTest.java Mon Nov 13 11:36:19 2006 @@ -44,7 +44,7 @@ sa.setSyslogHost("localhost"); sa.setFacility("MAIL"); sa.setPort(port); - sa.setSuffixPattern("[%thread] %logger %msg %exception"); + sa.setSuffixPattern("[%thread] %logger %msg"); sa.start(); assertTrue(sa.isStarted()); @@ -69,13 +69,13 @@ String first = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} \\w* "; String threadName = Thread.currentThread().getName(); assertTrue(msg.matches(first + "\\[" + threadName + "\\] " + loggerName - + " " + logMsg + " ")); + + " " + logMsg)); } public void testException() throws InterruptedException { int port = MockSyslogServer.PORT + 2; - MockSyslogServer mockServer = new MockSyslogServer(1, port); + MockSyslogServer mockServer = new MockSyslogServer(21, port); mockServer.start(); // give MockSyslogServer head start Thread.sleep(100); @@ -87,7 +87,7 @@ sa.setSyslogHost("localhost"); sa.setFacility("MAIL"); sa.setPort(port); - sa.setSuffixPattern("[%thread] %logger %msg %exception"); + sa.setSuffixPattern("[%thread] %logger %msg"); sa.start(); assertTrue(sa.isStarted()); @@ -104,19 +104,23 @@ // much sooner than that. mockServer.join(8000); assertTrue(mockServer.finished); - assertEquals(1, mockServer.msgList.size()); + + //message + 20 lines of stacktrace + assertEquals(21, mockServer.msgList.size()); +// int i = 0; +// for (String line: mockServer.msgList) { +// System.out.println(i++ + ": " + line); +// } + String msg = mockServer.msgList.get(0); - String expected = "<" + (SyslogConstants.LOG_MAIL + SyslogConstants.DEBUG_SEVERITY) + ">"; assertTrue(msg.startsWith(expected)); - -// String first = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} \\w* "; -// String threadName = Thread.currentThread().getName(); -// String expectedResult = first + "\\[" + threadName + "\\] " + loggerName -// + " " + logMsg + " " + ex.getClass().getCanonicalName() + ": " + exMsg + "\n"; -// assertTrue(msg.matches(expectedResult)); - - // fail("check exceptions"); + + String expectedPrefix = "<\\d{2}>\\w{3} \\d{2} \\d{2}(:\\d{2}){2} \\w* "; + String threadName = Thread.currentThread().getName(); + String expectedResult = expectedPrefix + "\\[" + threadName + "\\] " + loggerName + + " " + logMsg; + assertTrue(msg.matches(expectedResult)); } } Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java ============================================================================== --- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java (original) +++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogAppenderBase.java Mon Nov 13 11:36:19 2006 @@ -16,16 +16,16 @@ protected String suffixPattern; SyslogWriter sw; int port = SyslogConstants.SYSLOG_PORT; - + public void start() { int errorCount = 0; if (facilityStr == null) { addError("The Facility option is mandatory"); errorCount++; } - + facility = facilityStringToint(facilityStr); - + try { sw = new SyslogWriter(syslogHost, port); } catch (UnknownHostException e) { @@ -35,42 +35,47 @@ errorCount++; addError("Failed to bind to a random datagram socket ", e); } - - if(layout == null) { + + if (layout == null) { layout = buildLayout(facilityStr); } - - if(errorCount == 0) { + + if (errorCount == 0) { super.start(); } } - + abstract public Layout buildLayout(String facilityStr); - + abstract public int getSeverityForEvent(Object eventObject); - + @Override protected void append(Object eventObject) { - if(!isStarted()) { + if (!isStarted()) { return; } - + try { String msg = layout.doLayout(eventObject); sw.write(msg); sw.flush(); - - } catch(IOException ioe) { - addError("Failed to send diagram to "+syslogHost, ioe); + postProcess(eventObject, sw); + } catch (IOException ioe) { + addError("Failed to send diagram to " + syslogHost, ioe); stop(); } } + + protected void postProcess(Object event, SyslogWriter sw) { + + } /** * Returns the integer value corresponding to the named syslog facility. * - * @throws IllegalArgumentException if the facility string is not recognized - * */ + * @throws IllegalArgumentException + * if the facility string is not recognized + */ static public int facilityStringToint(String facilityStr) { if ("KERN".equalsIgnoreCase(facilityStr)) { return SyslogConstants.LOG_KERN; @@ -113,11 +118,11 @@ } else if ("LOCAL7".equalsIgnoreCase(facilityStr)) { return SyslogConstants.LOG_LOCAL7; } else { - throw new IllegalArgumentException(facilityStr + " is not a valid syslog facility string"); + throw new IllegalArgumentException(facilityStr + + " is not a valid syslog facility string"); } } - /** * Returns the value of the <b>SyslogHost</b> option. */ @@ -128,7 +133,7 @@ /** * The <b>SyslogHost</b> option is the name of the the syslog host where log * output should go. - * + * * <b>WARNING</b> If the SyslogHost is not set, then this appender will fail. */ public void setSyslogHost(String syslogHost) { @@ -137,7 +142,7 @@ /** * Returns the string value of the <b>Facility</b> option. - * + * * See {@link #setFacility} for the set of allowed values. */ public String getFacility() { @@ -145,16 +150,17 @@ } /** - * The <b>Facility</b> option must be set one of the strings KERN, - * USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, - * NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, + * The <b>Facility</b> option must be set one of the strings KERN, USER, + * MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, + * AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, * LOCAL6, LOCAL7. Case is not important. - * - * <p>See {@link SyslogConstants} and RFC 3164 for more information about the + * + * <p> + * See {@link SyslogConstants} and RFC 3164 for more information about the * <b>Facility</b> option. */ public void setFacility(String facilityStr) { - if(facilityStr != null) { + if (facilityStr != null) { facilityStr = facilityStr.trim(); } this.facilityStr = facilityStr; @@ -177,7 +183,7 @@ } /** - * You can override + * You can override */ public Layout getLayout() { return layout; @@ -186,7 +192,7 @@ public void setLayout(Layout layout) { this.layout = layout; } - + @Override public void stop() { sw.close(); @@ -203,7 +209,7 @@ } /** - * The <b>suffixPattern</b> option specifies the fortmat of the + * The <b>suffixPattern</b> option specifies the fortmat of the * non-standardized part the message sent to the syslog server. * * @param pattern Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java ============================================================================== --- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java (original) +++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/net/SyslogWriter.java Mon Nov 13 11:36:19 2006 @@ -12,7 +12,7 @@ * SyslogWriter is a wrapper around the {@link DatagramSocket} class so that it * behaves like a {@link Writer}. */ -class SyslogWriter extends Writer { +public class SyslogWriter extends Writer { /** * The maximum length after which we discard the existing string buffer and