001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.log4j;
019
020import java.io.IOException;
021import java.io.OutputStream;
022import org.apache.log4j.helpers.LogLog;
023
024/**
025  * ConsoleAppender appends log events to <code>System.out</code> or
026  * <code>System.err</code> using a layout specified by the user. The
027  * default target is <code>System.out</code>.
028  *
029  * @author Ceki G&uuml;lc&uuml; 
030  * @author Curt Arnold
031  * @since 1.1 */
032public class ConsoleAppender extends WriterAppender {
033
034  public static final String SYSTEM_OUT = "System.out";
035  public static final String SYSTEM_ERR = "System.err";
036
037  protected String target = SYSTEM_OUT;
038
039  /**
040   *  Determines if the appender honors reassignments of System.out
041   *  or System.err made after configuration.
042   */
043  private boolean follow = false;
044
045  /**
046    * Constructs an unconfigured appender.
047    */
048  public ConsoleAppender() {
049  }
050
051    /**
052     * Creates a configured appender.
053     *
054     * @param layout layout, may not be null.
055     */
056  public ConsoleAppender(Layout layout) {
057    this(layout, SYSTEM_OUT);
058  }
059
060    /**
061     *   Creates a configured appender.
062     * @param layout layout, may not be null.
063     * @param target target, either "System.err" or "System.out".
064     */
065  public ConsoleAppender(Layout layout, String target) {
066    setLayout(layout);
067    setTarget(target);
068    activateOptions();
069  }
070
071  /**
072   *  Sets the value of the <b>Target</b> option. Recognized values
073   *  are "System.out" and "System.err". Any other value will be
074   *  ignored.  
075   * */
076  public
077  void setTarget(String value) {
078    String v = value.trim();
079
080    if (SYSTEM_OUT.equalsIgnoreCase(v)) {
081      target = SYSTEM_OUT;
082    } else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
083      target = SYSTEM_ERR;
084    } else {
085      targetWarn(value);
086    }
087  }
088
089  /**
090   * Returns the current value of the <b>Target</b> property. The
091   * default value of the option is "System.out".
092   *
093   * See also {@link #setTarget}.
094   * */
095  public
096  String getTarget() {
097    return target;
098  }
099  
100  /**
101   *  Sets whether the appender honors reassignments of System.out
102   *  or System.err made after configuration.
103   *  @param newValue if true, appender will use value of System.out or
104   *  System.err in force at the time when logging events are appended.
105   *  @since 1.2.13
106   */
107  public final void setFollow(final boolean newValue) {
108     follow = newValue;
109  }
110  
111  /**
112   *  Gets whether the appender honors reassignments of System.out
113   *  or System.err made after configuration.
114   *  @return true if appender will use value of System.out or
115   *  System.err in force at the time when logging events are appended.
116   *  @since 1.2.13
117   */
118  public final boolean getFollow() {
119      return follow;
120  }
121
122  void targetWarn(String val) {
123    LogLog.warn("["+val+"] should be System.out or System.err.");
124    LogLog.warn("Using previously set target, System.out by default.");
125  }
126
127  /**
128    *   Prepares the appender for use.
129    */
130   public void activateOptions() {
131        if (follow) {
132            if (target.equals(SYSTEM_ERR)) {
133               setWriter(createWriter(new SystemErrStream()));
134            } else {
135               setWriter(createWriter(new SystemOutStream()));
136            }
137        } else {
138            if (target.equals(SYSTEM_ERR)) {
139               setWriter(createWriter(System.err));
140            } else {
141               setWriter(createWriter(System.out));
142            }
143        }
144
145        super.activateOptions();
146  }
147  
148  /**
149   *  {@inheritDoc}
150   */
151  protected
152  final
153  void closeWriter() {
154     if (follow) {
155        super.closeWriter();
156     }
157  }
158  
159
160    /**
161     * An implementation of OutputStream that redirects to the
162     * current System.err.
163     *
164     */
165    private static class SystemErrStream extends OutputStream {
166        public SystemErrStream() {
167        }
168
169        public void close() {
170        }
171
172        public void flush() {
173            System.err.flush();
174        }
175
176        public void write(final byte[] b) throws IOException {
177            System.err.write(b);
178        }
179
180        public void write(final byte[] b, final int off, final int len)
181            throws IOException {
182            System.err.write(b, off, len);
183        }
184
185        public void write(final int b) throws IOException {
186            System.err.write(b);
187        }
188    }
189
190    /**
191     * An implementation of OutputStream that redirects to the
192     * current System.out.
193     *
194     */
195    private static class SystemOutStream extends OutputStream {
196        public SystemOutStream() {
197        }
198
199        public void close() {
200        }
201
202        public void flush() {
203            System.out.flush();
204        }
205
206        public void write(final byte[] b) throws IOException {
207            System.out.write(b);
208        }
209
210        public void write(final byte[] b, final int off, final int len)
211            throws IOException {
212            System.out.write(b, off, len);
213        }
214
215        public void write(final int b) throws IOException {
216            System.out.write(b);
217        }
218    }
219
220}