[JIRA] Created: (LBCORE-143) ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically.

ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ---------------------------------------------------------------------------------------------------------------------------------- Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err"; protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); } private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } } private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } } private static class WrapperOutputStream extends OutputStream { private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; } @Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } } -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] tomliliu updated LBCORE-143: ---------------------------- Attachment: ConsoleAppender.java
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu commented on LBCORE-143: ----------------------------------- Hello Tom, Thank you for this patch. I was not aware that Junit captured the console. What does Junit do with the console after capturing it?
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu edited comment on LBCORE-143 at 3/16/10 7:34 PM: ------------------------------------------------------------ Hello Tom, Thank you for this patch. I was not aware that Junit captured the console. What does Junit do with the console after capturing it? Looking at the code, it seems that Junit just writes to the console via an abstraction called RealSystem which implements JUnitSystem. Of course, nothing prevents developers from handing a test runner a different implementation of JUnitSystem. I am assuming that in your environment the JUnitSystem instance is changing over time although I cannot readily imagine a scenario where this would be the case. Could you please give more details about your environment? was (Author: noreply.ceki@qos.ch): Hello Tom, Thank you for this patch. I was not aware that Junit captured the console. What does Junit do with the console after capturing it?
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] tomliliu commented on LBCORE-143: --------------------------------- Hi Ceki, Thanks for the quick response. I digged into the code a bit found that it's not junit capturing the stdout/stdin, but the JUnitTestRunner in ant. So ConsoleAppender actually does not work nicely in ANT + JUNIT. If you take look at org.apache.tools.ant.taskdefs.optional.junit.JunitTestRunner.run() : 326 (ant 1.8.0), it calls setupIOStream which will do the stdout/stderr redirection. Please consider fix ConsoleAppender as to me. The semantic of ConsoleAppender is always logging to the CURRENT System.out/System.err. Thanks, Tom
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu commented on LBCORE-143: ----------------------------------- In my previous comment, I failed to mention that your patch made sense.
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu resolved LBCORE-143. ------------------------------- Fix Version/s: 0.9.19 Resolution: Fixed Fixed in http://github.com/ceki/logback/commit/3faa7d8bc51 I also added your name as an author to ConsoleAppender and ConsoleOutputStreamWrapper.
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] tomliliu commented on LBCORE-143: --------------------------------- Woo. I'm so happy that you put my name on the author list. Thanks very much!
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü commented on LBCORE-143: --------------------------- I refactored the code a bit, removing the ConsoleOutputStreamWrapper... what do you think?
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, patch
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü updated LBCORE-143: ---------------------- Attachment: patch
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, patch
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü updated LBCORE-143: ---------------------- Attachment: refactoring I refactored the code a bit, removing the ConsoleOutputStreamWrapper and the switches. Please find the patch attachment... what do you think?
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü edited comment on LBCORE-143 at 3/17/10 5:54 PM: ---------------------------------------------------- I refactored the code a bit, removing the ConsoleOutputStreamWrapper and the switches. Please find the patch attachment... what do you think? was (Author: rd): I refactored the code a bit, removing the ConsoleOutputStreamWrapper... what do you think?
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü updated LBCORE-143: ---------------------- Comment: was deleted
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Rü updated LBCORE-143: ---------------------- Attachment: (was: patch)
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu commented on LBCORE-143: ----------------------------------- Pretty nice code, thank you, But I bet the test cases don't pass...
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu edited comment on LBCORE-143 at 3/17/10 7:14 PM: ------------------------------------------------------------ Pretty nice code, thank you. I applied the patch and all the tests pass. was (Author: noreply.ceki@qos.ch): Pretty nice code, thank you, But I bet the test cases don't pass...
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira

[ http://jira.qos.ch/browse/LBCORE-143?page=com.atlassian.jira.plugin.system.i... ] Ceki Gulcu edited comment on LBCORE-143 at 3/17/10 7:33 PM: ------------------------------------------------------------ Pretty nice code, thank you. I applied the patch and all the tests pass. Applied the patch as is, except that the addition of the flush() method to the anonymous OutputStream class. was (Author: noreply.ceki@qos.ch): Pretty nice code, thank you. I applied the patch and all the tests pass.
ConsoleAppender should always write to current System.out / System.err. The underlying outputstream should not be bind statically. ----------------------------------------------------------------------------------------------------------------------------------
Key: LBCORE-143 URL: http://jira.qos.ch/browse/LBCORE-143 Project: logback-core Issue Type: Bug Components: Appender Affects Versions: 0.9.18 Reporter: tomliliu Assignee: Logback dev list Fix For: 0.9.19
Attachments: ConsoleAppender.java, refactoring
Hi logback-dev, ConsoleAppender does not work nicely with JUnit. Symptom: when running junit tests with logback (default configuration, no logback configuration is provided), only the first test case's output was captured, the subsequent test cases' output were not captured by junit. The problem is that console appender binds itself to stdout / stderr statically. Illustrate what happens: Junit run test 1 -> System.out is set to test1.out -> Logback auto configure -> Console appender is bind to System.out, which is test1.out Junit run test 2 -> System.out is set to test2.out -> Console appender is still bind to test1.out -> The output of subsequent test cases are not correctly redirected. The ConsoleAppender's behavior is not correct as it should always write to current System.out / System.err. I worked out a simple fix and hope it will be useful: /** * Logback: the generic, reliable, fast and flexible logging framework. * * Copyright (C) 2000-2009, 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; import java.io.IOException; import java.io.OutputStream; import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.WarnStatus; /** * ConsoleAppender appends log events to <code>System.out</code> or <code>System.err</code> using a layout specified by * the user. The default target is <code>System.out</code>. * * For more information about this appender, please refer to the online manual at * http://logback.qos.ch/manual/appenders.html#ConsoleAppender * * @author Ceki Gülcü */ public class ConsoleAppender<E> extends WriterAppender<E> { public static final String SYSTEM_OUT = "System.out"; public static final String SYSTEM_ERR = "System.err";
protected String target = SYSTEM_OUT; private interface OutputStreamProvider { OutputStream getOutputStream(); }
private static class SysoutProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.out; } }
private static class SyserrProvider implements OutputStreamProvider { @Override public OutputStream getOutputStream() { return System.err; } }
private static class WrapperOutputStream extends OutputStream {
private final OutputStreamProvider provider; WrapperOutputStream(OutputStreamProvider provider) { this.provider = provider; }
@Override public void write(int b) throws IOException { provider.getOutputStream().write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { provider.getOutputStream().write(b, off, len); } @Override public void write(byte[] b) throws IOException { provider.getOutputStream().write(b); } @Override public void close() throws IOException { provider.getOutputStream().close(); } @Override public void flush() throws IOException { provider.getOutputStream().flush(); } } /** * As in most logback components, the default constructor does nothing. */ public ConsoleAppender() { } /** * Sets the value of the <b>Target</b> option. Recognized values are "System.out" and "System.err". Any other value * will be ignored. */ public void setTarget(String value) { String v = value.trim(); if (SYSTEM_OUT.equalsIgnoreCase(v)) { target = SYSTEM_OUT; } else if (SYSTEM_ERR.equalsIgnoreCase(v)) { target = SYSTEM_ERR; } else { targetWarn(value); } } /** * Returns the current value of the <b>Target</b> property. The default value of the option is "System.out". * * See also {@link #setTarget}. */ public String getTarget() { return target; } void targetWarn(String val) { Status status = new WarnStatus("[" + val + " should be System.out or System.err.", this); status.add(new WarnStatus("Using previously set target, System.out by default.", this)); addStatus(status); } public void start() { if (target.equals(SYSTEM_OUT)) { setWriter(createWriter(new WrapperOutputStream(new SysoutProvider()))); } else { setWriter(createWriter(new WrapperOutputStream(new SyserrProvider()))); } super.start(); } /** * This method overrides the parent {@link WriterAppender#closeWriter} implementation because the console stream is * not ours to close. */ protected final void closeWriter() { writeFooter(); } }
-- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira
participants (3)
-
Ceki Gulcu (JIRA)
-
Rü (JIRA)
-
tomliliu (JIRA)