Skip to content

Commit

Permalink
fix LBCLASSIC-327 and LBCLASSIC-333
Browse files Browse the repository at this point in the history
  • Loading branch information
ceki committed May 31, 2012
1 parent e9e0640 commit 9116969
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 138 deletions.
Expand Up @@ -30,22 +30,27 @@
* This appender can be used to send messages to a remote syslog daemon. <p> For
* more information about this appender, please refer to the online manual at
* http://logback.qos.ch/manual/appenders.html#SyslogAppender
*
*
* @author Ceki G&uuml;lc&uuml;
*/
public class SyslogAppender extends SyslogAppenderBase<ILoggingEvent> {

static final public String DEFAULT_SUFFIX_PATTERN = "[%thread] %logger %msg";
static final public String DEFAULT_STACKTRACE_SUFFIX_PATTERN = ""+CoreConstants.TAB;
static final public String DEFAULT_STACKTRACE_PATTERN = "" + CoreConstants.TAB;

PatternLayout stackTraceLayout = new PatternLayout();
String stackTracePattern = DEFAULT_STACKTRACE_PATTERN;

boolean throwableExcluded = false;


PatternLayout prefixLayout = new PatternLayout();
PatternLayout stacktraceLayout = new PatternLayout();
public void start() {
super.start();
setupStackTraceLayout();
}

public Layout<ILoggingEvent> buildLayout(String facilityStr) {
String prefixPattern = "%syslogStart{" + facilityStr + "}%nopex";
setupPrefixLayout(prefixPattern);
setupStacktraceLayout(prefixPattern);
return setupFullLayout(prefixPattern);
String getPrefixPattern() {
return "%syslogStart{" + getFacility() + "}%nopex";
}

/*
Expand All @@ -62,17 +67,20 @@ public int getSeverityForEvent(Object eventObject) {

@Override
protected void postProcess(Object eventObject, OutputStream sw) {
if (throwableExcluded)
return;

ILoggingEvent event = (ILoggingEvent) eventObject;

String layout = stacktraceLayout.doLayout(event);
String stackTracePrefix = stackTraceLayout.doLayout(event);

IThrowableProxy tp = event.getThrowableProxy();
while (tp != null) {
StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
try {
for (StackTraceElementProxy step : stepArray) {
StringBuilder sb = new StringBuilder();
sb.append(layout).append(step);
sb.append(stackTracePrefix).append(step);
sw.write(sb.toString().getBytes());
sw.flush();
}
Expand All @@ -83,36 +91,63 @@ protected void postProcess(Object eventObject, OutputStream sw) {
}
}

private Layout<ILoggingEvent> setupFullLayout(String prefixPattern) {
PatternLayout fullLayout = new PatternLayout();
fullLayout.getInstanceConverterMap().put("syslogStart",
SyslogStartConverter.class.getName());
if (suffixPattern == null) {
suffixPattern = DEFAULT_SUFFIX_PATTERN;
}
fullLayout.setPattern(prefixPattern + suffixPattern);
fullLayout.setContext(getContext());
fullLayout.start();
return fullLayout;
public Layout<ILoggingEvent> buildLayout() {
PatternLayout layout = new PatternLayout();
layout.getInstanceConverterMap().put("syslogStart",
SyslogStartConverter.class.getName());
if (suffixPattern == null) {
suffixPattern = DEFAULT_SUFFIX_PATTERN;
}
layout.setPattern(getPrefixPattern() + suffixPattern);
layout.setContext(getContext());
layout.start();
return layout;
}

private void setupStackTraceLayout() {
stackTraceLayout.getInstanceConverterMap().put("syslogStart",
SyslogStartConverter.class.getName());

stackTraceLayout.setPattern(getPrefixPattern() + stackTracePattern);
stackTraceLayout.setContext(getContext());
stackTraceLayout.start();
}

private void setupStacktraceLayout(String prefixPattern) {
stacktraceLayout.getInstanceConverterMap().put("syslogStart",
SyslogStartConverter.class.getName());
if (stacktraceSuffixPattern == null) {
stacktraceSuffixPattern = DEFAULT_STACKTRACE_SUFFIX_PATTERN;
}
stacktraceLayout.setPattern(prefixPattern + stacktraceSuffixPattern);
stacktraceLayout.setContext(getContext());
stacktraceLayout.start();
public boolean isThrowableExcluded() {
return throwableExcluded;
}

private void setupPrefixLayout(String prefixPattern) {
prefixLayout.getInstanceConverterMap().put("syslogStart",
SyslogStartConverter.class.getName());
prefixLayout.setPattern(prefixPattern);
prefixLayout.setContext(getContext());
prefixLayout.start();
/**
* Setting throwableExcluded to true causes no Throwable's stack trace data to be sent to
* the syslog daemon. By default, stack trace data is sent to syslog daemon.
*
* @param throwableExcluded
* @since 1.0.4
*/
public void setThrowableExcluded(boolean throwableExcluded) {
this.throwableExcluded = throwableExcluded;
}

/**
* See {@link #setStackTracePattern(String).
*
* @return the stackTraceSuffixPattern
* @since 1.0.4
*/
public String getStackTracePattern() {
return stackTracePattern;
}

/**
* Stack trace lines are sent to the syslog server separately from the main message
* For stack trace lines, the stackTracePattern is used instead of {@link #suffixPattern}.
* The <b>stackTracePattern</b> option allows specification of a separately format for the
* non-standardized part of stack trace lines.
*
* @param stackTracePattern
* @since 1.0.4
*/
public void setStackTracePattern(String stackTracePattern) {
this.stackTracePattern = stackTracePattern;
}
}
Expand Up @@ -18,12 +18,11 @@
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses( { LoggerContextTest.class, LoggerPerfTest.class,
ScenarioBasedLoggerContextTest.class, PatternLayoutTest.class,
LoggerTest.class, LoggerSerializationTest.class,
MessageFormattingTest.class, MDCTest.class,
TurboFilteringInLoggerTest.class })


@SuiteClasses({LoggerContextTest.class, LoggerPerfTest.class,
ScenarioBasedLoggerContextTest.class, PatternLayoutTest.class,
LoggerTest.class, LoggerSerializationTest.class,
MessageFormattingTest.class, MDCTest.class,
TurboFilteringInLoggerTest.class,
AsyncAppenderTest.class})
public class PackageTest {
}
Expand Up @@ -65,7 +65,7 @@ public void setMockServerAndConfigure(int expectedCount)
sa.setFacility("MAIL");
sa.setPort(port);
sa.setSuffixPattern("[%thread] %logger %msg");
sa.setStacktraceSuffixPattern("[%thread] foo "+CoreConstants.TAB);
sa.setStackTracePattern("[%thread] foo "+CoreConstants.TAB);
sa.start();
assertTrue(sa.isStarted());

Expand Down
Expand Up @@ -39,7 +39,6 @@ public abstract class SyslogAppenderBase<E> extends AppenderBase<E> {
String facilityStr;
String syslogHost;
protected String suffixPattern;
protected String stacktraceSuffixPattern;
SyslogOutputStream sos;
int port = SyslogConstants.SYSLOG_PORT;

Expand All @@ -62,15 +61,15 @@ public void start() {
}

if (layout == null) {
layout = buildLayout(facilityStr);
layout = buildLayout();
}

if (errorCount == 0) {
super.start();
}
}

abstract public Layout<E> buildLayout(String facilityStr);
abstract public Layout<E> buildLayout();

abstract public int getSeverityForEvent(Object eventObject);

Expand Down Expand Up @@ -245,26 +244,4 @@ public String getSuffixPattern() {
public void setSuffixPattern(String suffixPattern) {
this.suffixPattern = suffixPattern;
}

/**
* See {@link #setStacktraceSuffixPattern(String).
*
* @return
*/
public String getStacktraceSuffixPattern() {
return stacktraceSuffixPattern;
}

/**
* Stacktrace lines are sent to the syslog server seperately from the main message
* For stacktrace lines, no suffixPattern is added.
* The <b>stacktraceSuffixPattern</b> option allows specification of a seperate format for the
* non-standardized part of stacktrace lines.
*
* @param stacktraceSuffixPattern
*/
public void setStacktraceSuffixPattern(String stacktraceSuffixPattern) {
this.stacktraceSuffixPattern = stacktraceSuffixPattern;
}

}
Expand Up @@ -18,6 +18,10 @@
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses( { ContextBaseTest.class, OutputStreamAppenderTest.class, FileAppenderResilienceTest.class, FileAppenderResilience_AS_ROOT_Test.class })
@SuiteClasses({ContextBaseTest.class,
OutputStreamAppenderTest.class,
FileAppenderResilienceTest.class,
FileAppenderResilience_AS_ROOT_Test.class,
AsyncAppenderBaseTest.class})
public class PackageTest {
}
128 changes: 61 additions & 67 deletions logback-site/src/site/pages/manual/appenders.html
Expand Up @@ -3144,92 +3144,86 @@ <h3><a name="SyslogAppender"
<th>Description</th>
</tr>
<tr>
<td>
<b>
<span class="prop">syslogHost</span>
</b>
</td>
<td>
<code>String</code>
</td>
<td>
The host name of the syslog server.
</td>
<td><b><span class="prop">syslogHost</span></b></td>
<td><code>String</code></td>
<td>The host name of the syslog server.</td>
</tr>
<tr>
<td>
<b>
<span class="prop">port</span>
</b>
</td>
<td>
<code>String</code>
</td>
<td>
The port number on the syslog server to connect to. Normally, one would not want
to change the default value of <em>514</em>.
<td><b><span class="prop">port</span></b></td>
<td><code>String</code></td>
<td>The port number on the syslog server to connect
to. Normally, one would not want to change the default value
of <em>514</em>.
</td>
</tr>
<tr>
<td><b><span class="prop">facility</span></b></td>
<td><code>String</code></td>
<td>
<b>
<span class="prop">facility</span>
</b>
<p>The <span class="prop">facility</span> is meant to identify
the source of a message.</p>
<p>The <span class="prop">facility</span> option must be set
to one of the strings <em>KERN, USER, MAIL, DAEMON, AUTH,
SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT,
ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4,
LOCAL5, LOCAL6, LOCAL7</em>. Case is not important.</p>
</td>
<td>
<code>String</code>
</td>
<td>
<p>
The <span class="prop">facility</span> is meant to identify
the source of a message.
</p>
<p>
The <span class="prop">facility</span> option must be set to one
of the strings <em>KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP,
CRON, AUTHPRIV, FTP, NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7</em>. Case is not important.
</tr>
<tr>
<td><b><span class="prop">suffixPattern</span></b></td>
<td><code>String</code></td>
<td><p>The <span class="prop">suffixPattern</span> option
specifies the format of the non-standardized part of the
message sent to the syslog server. By default, its value is
<em>[%thread] %logger %msg</em>. Any value that a
<code>PatternLayout</code> could use is a correct <span
class="prop">suffixPattern</span> value.
</p>
</td>
</tr>

<tr>
<td>
<b>
<span class="prop">suffixPattern</span>
</b>
</td>
<td>
<code>String</code>
</td>
<td>
<p>The <span class="prop">suffixPattern</span> option
specifies the format of the non-standardized part of the
message sent to the syslog server. By default, its value is
<em>[%thread] %logger %msg</em>. Any value that a
<code>PatternLayout</code> could use is a correct <span
class="prop">suffixPattern</span> value.
</p>
<td><b><span class="prop">stackTracePattern</span></b></td>
<td><code>String</code></td>
<td><p>The <span class="prop">stackTracePattern</span>
property allows the customization of the string appearing just
before each stack trace line. The default value for this
property is "\t", i.e. the tab character. Any value accepted
by <code>PatternLayout</code> is a valid value for <span
class="prop">stackTracePattern</span>.</p>
</td>
</tr>

<tr>
<td><b><span class="prop">throwableExcluded</span></b></td>
<td><code>boolean</code></td>
<td>Setting <span class="prop">throwableExcluded</span> to
<code>true</code> will cause stack trace data associated with
a Throwable to be omitted. By default, <span
class="prop">throwableExcluded</span> is set to
<code>false</code> so that stack trace data is sent to the
syslog server. </td>
</tr>


</table>

<p>
The syslog severity of a logging event is converted from the level of the logging event.
The <em>DEBUG</em> level is converted to <em>7</em>, <em>INFO</em> is converted to
<em>6</em>, <em>WARN</em> is converted to <em>4</em> and <em>ERROR</em> is converted
to <em>3</em>.
<p>The syslog severity of a logging event is converted from the
level of the logging event. The <em>DEBUG</em> level is converted
to <em>7</em>, <em>INFO</em> is converted to <em>6</em>,
<em>WARN</em> is converted to <em>4</em> and <em>ERROR</em> is
converted to <em>3</em>.
</p>

<p>
Since the format of a syslog request follows rather strict rules, there is no layout
to be used with <code>SyslogAppender</code>. However, using the
<span class="prop">suffixPattern</span> option lets the user display whatever
information she wishes.
<p>Since the format of a syslog request follows rather strict
rules, there is no layout to be used with
<code>SyslogAppender</code>. However, using the <span
class="prop">suffixPattern</span> option lets the user display
whatever information she wishes.
</p>

<p>
Here is a sample configuration using a <code>SyslogAppender</code>.
</p>
<p>Here is a sample configuration using a
<code>SyslogAppender</code>.</p>

<p class="example">Example: <code>SyslogAppender</code> configuration (logback-examples/src/main/java/chapters/appenders/conf/logback-syslog.xml)</p>
<span class="asGroovy" onclick="return asGroovy('logback-syslog');">View as .groovy</span>
Expand Down

2 comments on commit 9116969

@ingebrigt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work.

If you want to avoid calling
stackTraceLayout.doLayout(event);
every time postProcess(..) is called, but there is no stacktrace, just add a test:
if (tp == null) return;
and move the doLayout() call down a few lines

Sorry about that, was my fault.

@ceki
Copy link
Member Author

@ceki ceki commented on 9116969 May 31, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.