View | Details | Raw Unified | Return to bug 24159
Collapse All | Expand All

(-)src/java/org/apache/log4j/concurrent/SynchronizedBoolean.java (+54 lines)
Line 0 Link Here
1
2
/*
3
  File: SynchronizedBoolean.java
4
5
  Originally written by Doug Lea and released into the public domain.
6
  This may be used for any purposes whatsoever without acknowledgment.
7
  Thanks for the assistance and support of Sun Microsystems Labs,
8
  and everyone contributing, testing, and using this code.
9
10
  History:
11
  Date       Who                What
12
  19Jun1998  dl               Create public version
13
*/
14
15
package org.apache.log4j.concurrent;
16
17
/**
18
 * A class useful for offloading synch for boolean instance variables.
19
 * A cut down version of the original Doug Lea class.
20
 */
21
public final class SynchronizedBoolean {
22
23
  private boolean value;
24
25
  /** 
26
   * Make a new SynchronizedBoolean with the given initial value,
27
   * and using its own internal lock.
28
   **/
29
  public SynchronizedBoolean(boolean initialValue) { 
30
    value = initialValue; 
31
  }
32
33
  /** 
34
   * Return the current value 
35
   **/
36
  public synchronized boolean get() { return value; }
37
38
  /** 
39
   * Set to newValue.
40
   * @return the old value 
41
   **/
42
  public synchronized boolean set(boolean newValue) { 
43
    boolean old = value;
44
    value = newValue; 
45
    return old;
46
  }
47
48
  /**
49
   * Returns <code>String.valueOf(get()))</code>.
50
   */
51
  public String toString() { return String.valueOf(get()); }
52
53
}
54
(-)src/java/org/apache/log4j/concurrent/ConcurrentAppender.java (+429 lines)
Line 0 Link Here
1
/*
2
 * Copyright 1999,2004 The Apache Software Foundation.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.log4j.concurrent;
18
19
import org.apache.log4j.Layout;
20
import org.apache.log4j.Appender;
21
import org.apache.log4j.Priority;
22
import org.apache.log4j.helpers.ReaderWriterLock;
23
import org.apache.log4j.spi.ComponentBase;
24
import org.apache.log4j.spi.Filter;
25
import org.apache.log4j.spi.LoggingEvent;
26
import org.apache.log4j.spi.OptionHandler;
27
28
/**
29
 * Base class for appenders that can benefit from a concurrency strategy.
30
 * Classes derived from this appender may have the {@link #append} method
31
 * called by multiple threads.  Derived classes must also override {@link
32
 * #internalClose}.
33
 * <p>
34
 * Locking strategy:  Internally, there is a read-write lock to handle
35
 * concurrent modification.  A <i>write</i> lock is obtained to change states
36
 * (including before {@link #close}.)  A <i>read</i> lock is obtained to read
37
 * options.  Subclasses interested in state may check state using a public
38
 * method or within their own {@link #append} method.
39
 * </p>
40
 * <p>
41
 * This class is heavily based on the {@link
42
 * #org.apache.log4j.AppenderSkeleton} class.  It may be a useful base class
43
 * for creating appenders that can benefit from concurrent I/O access.
44
 * </p>
45
 *
46
 * @see #getWriteLock
47
 */
48
public abstract class ConcurrentAppender 
49
  extends ComponentBase implements Appender, OptionHandler
50
{
51
  
52
  /**
53
   * The layout variable does not need to be set if the appender
54
   * implementation has its own layout.
55
   */
56
  private Layout layout;
57
58
  /**
59
   * The name of this appender.
60
   */
61
  protected String name;
62
63
  /**
64
   * There is no level threshold filtering by default.
65
   */
66
  private volatile Priority threshold;
67
68
  /**
69
   * Internal class, internally locked.
70
   */
71
  private FilterChain filters = new FilterChain();
72
73
  /**
74
   * Is this appender closed?
75
   */
76
  private SynchronizedBoolean closed = new SynchronizedBoolean(false);
77
78
  /**
79
   * Set to true when the appender is activated.
80
   * Subclasses can set this to false to indicate things are not in order.
81
   */
82
  protected SynchronizedBoolean active = new SynchronizedBoolean(false);
83
  
84
  /**
85
   * The guard prevents an appender from repeatedly calling its own doAppend
86
   * method.  This prevents same-thread re-entry looping.
87
   */
88
  private ThreadLocal guard = new ThreadLocal();
89
90
  /**
91
   * A write lock is obtained to change options, a read lock is obtained to
92
   * append events.
93
   */
94
  private ReaderWriterLock lock = new ReaderWriterLock();
95
96
97
  /**
98
   * Constructs a ConcurrentAppender.
99
   *
100
   * @param isActive true if appender is ready for use upon construction.
101
   */
102
  protected ConcurrentAppender(final boolean isActive) {
103
    active.set(isActive);
104
  }
105
106
  /**
107
   * Derived appenders should override this method if option structure
108
   * requires it.
109
   * By default, sets {@link #active} to true.
110
   */
111
  public void activateOptions() {
112
    active.set(true);
113
  }
114
115
  /**
116
   * Indicates if the appender is active and not closed.
117
   */
118
  public boolean isActive() {
119
    return active.get() && !closed.get();
120
  }
121
122
  /**
123
   * Adds a filter to end of the filter list.
124
   * @param filter filter to use; cannot be null
125
   */
126
  public void addFilter(Filter filter) {
127
    filters.addFilter(filter);
128
  }
129
130
  /**
131
   * Clears the filters chain.
132
   */
133
  public void clearFilters() {
134
    filters.clear();
135
  }
136
137
  /**
138
   * Returns the first {@link Filter}.
139
   */
140
  public Filter getFilter() {
141
    return filters.getHead();
142
  }
143
144
  /**
145
   * Returns the layout of this appender. May return null if not set.
146
   */
147
  public Layout getLayout() {
148
    return this.layout;
149
  }
150
151
  /**
152
   * Returns the name of this appender.
153
   */
154
  public final String getName() {
155
    return this.name;
156
  }
157
158
  /**
159
   * Returns this appender's threshold level. See the {@link #setThreshold}
160
   * method for the meaning of this option.
161
   */
162
  public Priority getThreshold() {
163
    return threshold;
164
  }
165
166
  /**
167
   * Returns true if the message level is below the appender's threshold. If
168
   * there is no threshold set, returns <code>true</code>.
169
   */
170
  public boolean isAsSevereAsThreshold(final Priority level) {
171
    Priority copy = threshold;
172
    return ((copy == null) || copy.isGreaterOrEqual(level));
173
  }
174
175
  /**
176
   * Performs threshold checks and checks filters before delegating actual
177
   * logging to the subclasses specific {@link #append} method.
178
   * This implementation also checks if this thread already is logging using
179
   * this appender, preventing possible stack overflow.
180
   */
181
  public final void doAppend(LoggingEvent event) {
182
183
    if (!isAsSevereAsThreshold(event.getLevel()))
184
      return;
185
186
    if (!filters.accept(event))
187
      return;
188
189
    // Prevent concurrent re-entry by this thread
190
    // (There might be a cheaper way to do this)
191
    // (Or maybe this lock is not necessary)
192
    if (guard.get() != null)
193
      return;
194
195
    guard.set(this); // arbitrary thread lock object
196
    try {
197
198
      lock.getReadLock();
199
      try {
200
201
202
        if (closed.get()) {
203
          getNonFloodingLogger().error(
204
              "Attempted to use closed appender named [" + name + "].");
205
          return;
206
        }
207
208
        if (!active.get()) {
209
          getNonFloodingLogger().error(
210
              "Attempted to log with inactive named [" + name + "].");
211
          return;
212
        }
213
214
        append(event);
215
216
      } finally {
217
        lock.releaseReadLock();
218
      }
219
220
    } finally {
221
      guard.set(null);
222
    }
223
  }
224
225
  /**
226
   * Sets the layout for this appender. Note that some appenders have their own
227
   * (fixed) layouts or do not use one. For example, the {@link
228
   * org.apache.log4j.net.SocketAppender} ignores the layout set here.
229
   * <p>
230
   * Note that the implementation of {@link Layout} must be thread-safe.
231
   * Common layouts such as {@link org.apache.log4j.PatternLayout} are
232
   * thread-safe.
233
   * </p>
234
   *
235
   * @param layout new layout to use; may be null
236
   */
237
  public void setLayout(Layout layout) {
238
    this.layout = layout;
239
  }
240
241
  /**
242
   * Sets the name of this Appender.
243
   */
244
  public void setName(String name) {
245
    this.name = name;
246
  }
247
248
  /**
249
   * Sets the threshold level. 
250
   * All log events with lower level than the threshold level are ignored by
251
   * the appender.
252
   *
253
   * @param threshold new threshold; may be null
254
   */
255
  public void setThreshold(final Priority threshold) {
256
    this.threshold = threshold;
257
  }
258
259
  /**
260
   * Returns true if this appender is closed.
261
   * An appender, once closed, is closed forever.
262
   */
263
  public boolean getClosed() {
264
    return closed.get();
265
  }
266
267
  /**
268
   * Cleans up this appender.
269
   * Marked as <code>final</code> to prevent subclasses from accidentally
270
   * overriding and forgetting to call <code>super.close()</code> or obtain a
271
   * write lock.
272
   * Calls {@link #internalClose} when completed.
273
   * Implementation note:  Obtains a write lock before starting close.
274
   * Calling this method more than once does nothing.
275
   */
276
  public final void close() {
277
    boolean wasClosed;
278
    getWriteLock();
279
    try {
280
      wasClosed = closed.set(true);
281
    } finally {
282
      lock.releaseWriteLock();
283
    }
284
285
    if (!wasClosed)
286
      internalClose();
287
  }
288
289
  /**
290
   * Called to check if the appender is closed.
291
   */
292
  public boolean isClosed() {
293
    return closed.get();
294
  }
295
296
  public final org.apache.log4j.spi.ErrorHandler getErrorHandler() {
297
    return org.apache.log4j.helpers.OnlyOnceErrorHandler.INSTANCE;
298
  }
299
300
  public final void setErrorHandler(org.apache.log4j.spi.ErrorHandler eh) {
301
  }
302
303
  /**
304
   * Returns a string representation of this object.
305
   */
306
  public String toString() {
307
    return super.toString() + " name=" + name + 
308
      " threshold=" + threshold + 
309
      " layout=" + layout +
310
      " filters=" + filters;
311
  }
312
313
  // PROTECTED METHODS
314
315
  /**
316
   * Subclasses of <code>ConcurrentAppender</code> should implement this method
317
   * to perform actual logging. 
318
   * This object holds a read lock during this method.  This method may be
319
   * called simultaneously by multiple threads.
320
   */
321
  protected abstract void append(LoggingEvent event);
322
323
  /**
324
   * Subclasses must implement their own close routines.
325
   * This method is called by the {@link #close} method.
326
   * This is guaranteed to be called only once, even if {@link #close} is
327
   * invoked more than once.
328
   * Note that further locking is not required, as {@link #append} can no
329
   * longer be called.
330
   */
331
  protected abstract void internalClose();
332
333
  /**
334
   * Obtains a write lock that blocks logging to {@link #append}.
335
   * This is normally done when changing output behavior, closing and reopening
336
   * streams, etc.  Call {@link #releaseWriteLock} to resume logging.
337
   * <p>
338
   * Usage pattern:
339
   <pre>
340
   getWriteLock();
341
   try {
342
      // ...
343
   } finally {
344
      releaseWriteLock();
345
   }
346
   </pre>
347
   * Note:  Do not attempt to re-acquire this lock.  This lock should only be
348
   * used for critical sections and not for long periods of time.
349
   */
350
  protected void getWriteLock() {
351
    lock.getWriteLock();
352
  }
353
354
  /**
355
   * Releases a write lock; allows calls to the {@link #append} method.
356
   * @see #getWriteLock
357
   */
358
  protected void releaseWriteLock() {
359
    lock.releaseWriteLock();
360
  }
361
362
  /**
363
   * Finalizes this appender by calling this {@link #close} method.
364
   */
365
  protected void finalize() {
366
    if (!getClosed())
367
      getLogger().debug("Finalizing appender named [{}].", name);
368
    close();
369
  }
370
371
  /**
372
   * A simple linked-list data structure containing filters.
373
   */
374
  private static class FilterChain {
375
376
    private Filter headFilter = null;
377
    private Filter tailFilter = null;
378
   
379
    public synchronized boolean accept(LoggingEvent event) {
380
      Filter f = headFilter;
381
      while (f != null) {
382
        switch (f.decide(event)) {
383
          case Filter.DENY:
384
            return false;
385
          case Filter.ACCEPT:
386
            return true;
387
          case Filter.NEUTRAL:
388
            f = f.getNext();
389
        }
390
      }
391
      return true;
392
    }
393
394
    public synchronized void addFilter(Filter newFilter) {
395
      if (newFilter == null)
396
        throw new NullPointerException();
397
      if (headFilter == null) {
398
        headFilter = newFilter;
399
        tailFilter = newFilter;
400
      } else {
401
        tailFilter.setNext(newFilter);
402
        tailFilter = newFilter;
403
      }
404
    }
405
406
    public synchronized Filter getHead() {
407
      return headFilter;
408
    }
409
410
    public synchronized void clear() {
411
      headFilter = null;
412
      tailFilter = null;
413
    }
414
415
    public synchronized String toString() {
416
      StringBuffer sb = new StringBuffer();
417
      Filter f = headFilter;
418
      while (f != null) {
419
        sb.append(f);
420
        f = f.getNext();
421
        if (f != null)
422
          sb.append(',');
423
      }
424
      return f.toString();
425
    }
426
427
  }
428
429
}
(-)src/java/org/apache/log4j/concurrent/PerformanceTest.java (+119 lines)
Line 0 Link Here
1
/*
2
 * Copyright 1999,2004 The Apache Software Foundation.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.log4j.concurrent;
18
19
import java.io.Writer;
20
import java.io.StringWriter;
21
import java.io.FileWriter;
22
23
import org.apache.log4j.Logger;
24
import org.apache.log4j.Appender;
25
import org.apache.log4j.AppenderSkeleton;
26
import org.apache.log4j.PatternLayout;
27
import org.apache.log4j.spi.OptionHandler;
28
import org.apache.log4j.spi.LoggingEvent;
29
30
public class PerformanceTest implements Runnable {
31
32
  static Logger log = Logger.getLogger(PerformanceTest.class);
33
34
  String LAYOUT = "%d{ABSOLUTE} [%24c{1}] (%-8X{con} %X{opr})  %m%n";
35
  int times = 1000;
36
  int threads = 5;
37
38
  public void run() {
39
    for (int i = 0; i < times; i++) {
40
      log.info("Hello world", new Exception());
41
    }
42
  }
43
44
  public PerformanceTest(Appender a) throws Exception {
45
46
    log.removeAllAppenders();
47
    log.addAppender(a);
48
49
    Thread t[] = new Thread[threads];
50
    a.setLayout(new PatternLayout(LAYOUT));
51
    ((OptionHandler)a).activateOptions();
52
53
    long start = System.currentTimeMillis();
54
55
    for (int i = 0; i < threads; i++) {
56
      t[i] = new Thread(this);
57
      t[i].start();
58
    }
59
    for (int i = 0; i < threads; i++) {
60
      t[i].join();
61
    }
62
63
    long end = System.currentTimeMillis();
64
    a.close();
65
66
    System.out.println("Appender " + a.getClass());
67
    String msg = "Took " + (end - start) + "ms for " + times + " logs * " + " threads " + threads;
68
    System.out.println(msg);
69
    System.out.println();
70
  }
71
    
72
  public static void main(String s[]) throws Exception {
73
    
74
    System.out.println("Hit CTRL-\\ now");
75
    Thread.sleep(1000);
76
77
    Writer w;
78
    for (int i = 0; i < 5; i++) {
79
80
      /*
81
      ConcurrentAppender ca = new ConcurrentAppender() {
82
        protected void append(LoggingEvent event) {
83
          try { Thread.sleep(1); } catch (InterruptedException e) {}
84
        }
85
        protected void internalClose() {}
86
      };
87
88
      AppenderSkeleton as = new AppenderSkeleton() {
89
        protected void append(LoggingEvent event) {
90
          try { Thread.sleep(1); } catch (InterruptedException e) {}
91
        }
92
        public void close() {}
93
      };
94
95
      System.out.println("ConcurrentAppender");
96
      new PerformanceTest(ca);
97
98
      System.out.println("AppenderSkeleton");
99
      new PerformanceTest(as);
100
      */
101
102
      org.apache.log4j.FileAppender wa = new org.apache.log4j.FileAppender();
103
      wa.setFile("/tmp/blah");
104
      new PerformanceTest(wa);
105
106
      org.apache.log4j.concurrent.FileAppender wa2 = new org.apache.log4j.concurrent.FileAppender();
107
      wa2.setFile("/tmp/blah");
108
      new PerformanceTest(wa2);
109
      /*
110
      */
111
112
    }
113
114
    System.out.println("Hit CTRL-\\ now");
115
    Thread.sleep(1000);
116
117
  }
118
119
}
(-)src/java/org/apache/log4j/concurrent/ConsoleAppender.java (+214 lines)
Line 0 Link Here
1
/*
2
 * Copyright 1999,2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package org.apache.log4j.concurrent;
17
18
import java.io.IOException;
19
import java.io.OutputStream;
20
import org.apache.log4j.Layout;
21
22
23
/**
24
  * ConsoleAppender appends log events to <code>System.out</code> or
25
  * <code>System.err</code> using a layout specified by the user. The
26
  * default target is <code>System.out</code>.
27
  *
28
  * @author <a href="http://www.qos.ch/log4j/">Ceki G&uuml;lc&uuml;</a>
29
  * @author Curt Arnold
30
  * @since 1.1 */
31
public class ConsoleAppender extends WriterAppender {
32
    public static final String SYSTEM_OUT = "System.out";
33
    public static final String SYSTEM_ERR = "System.err";
34
    protected String target = SYSTEM_OUT;
35
36
    /**
37
     *  Determines if the appender honors reassignments of System.out
38
     *  or System.err made after configuration.
39
     */
40
    private boolean follow = false;
41
42
43
    /**
44
     * Constructs an unconfigured appender.
45
     */
46
    public ConsoleAppender() {
47
    }
48
49
    /**
50
     * Creates a configured appender.
51
     *
52
     * @param layout layout, may not be null.
53
     */
54
    public ConsoleAppender(final Layout layout) {
55
        setLayout(layout);
56
        activateOptions();
57
    }
58
59
    /**
60
     *   Creates a configured appender.
61
     * @param layout layout, may not be null.
62
     * @param targetStr target, either "System.err" or "System.out".
63
     */
64
    public ConsoleAppender(final Layout layout, final String targetStr) {
65
        setLayout(layout);
66
        setTarget(targetStr);
67
        activateOptions();
68
    }
69
70
    /**
71
     *  Sets the value of the <b>Target</b> option. Recognized values
72
     *  are "System.out" and "System.err". Any other value will be
73
     *  ignored.
74
     * */
75
    public void setTarget(final String value) {
76
        String v = value.trim();
77
78
        if (SYSTEM_OUT.equalsIgnoreCase(v)) {
79
            target = SYSTEM_OUT;
80
        } else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
81
            target = SYSTEM_ERR;
82
        } else {
83
            getLogger().warn("[{}] should be System.out or System.err.", value);
84
            getLogger().warn("Using previously set target, System.out by default.");
85
        }
86
    }
87
88
    /**
89
     * Returns the current value of the <b>Target</b> property. The
90
     * default value of the option is "System.out".
91
     *
92
     * See also {@link #setTarget}.
93
     * */
94
    public String getTarget() {
95
        return target;
96
    }
97
98
   /**
99
    *  Sets whether the appender honors reassignments of System.out
100
    *  or System.err made after configuration.
101
    *  @param newValue if true, appender will use value of System.out or
102
    *  System.err in force at the time when logging events are appended.
103
    *  @since 1.2.13
104
    */
105
    public final void setFollow(final boolean newValue) {
106
       follow = newValue;
107
    }
108
  
109
   /**
110
    *  Gets whether the appender honors reassignments of System.out
111
    *  or System.err made after configuration.
112
    *  @return true if appender will use value of System.out or
113
    *  System.err in force at the time when logging events are appended.
114
    *  @since 1.2.13
115
    */
116
    public final boolean getFollow() {
117
         return follow;
118
    }
119
120
121
    /**
122
     *   Prepares the appender for use.
123
     */
124
    public void activateOptions() {
125
        if (follow) {
126
            if (target.equals(SYSTEM_ERR)) {
127
               setWriter(createWriter(new SystemErrStream()));
128
            } else {
129
               setWriter(createWriter(new SystemOutStream()));
130
            }
131
        } else {
132
            if (target.equals(SYSTEM_ERR)) {
133
               setWriter(createWriter(System.err));
134
            } else {
135
               setWriter(createWriter(System.out));
136
            }
137
        }
138
139
        super.activateOptions();
140
    }
141
142
  /**
143
   *  {@inheritDoc}
144
   */
145
  protected
146
  final
147
  void closeWriter() {
148
     if (follow) {
149
        super.closeWriter();
150
     }
151
  }
152
153
154
    /**
155
     * An implementation of OutputStream that redirects to the
156
     * current System.err.
157
     *
158
     */
159
    private static class SystemErrStream extends OutputStream {
160
        public SystemErrStream() {
161
        }
162
163
        public void close() {
164
        }
165
166
        public void flush() {
167
            System.err.flush();
168
        }
169
170
        public void write(final byte[] b) throws IOException {
171
            System.err.write(b);
172
        }
173
174
        public void write(final byte[] b, final int off, final int len)
175
            throws IOException {
176
            System.err.write(b, off, len);
177
        }
178
179
        public void write(final int b) throws IOException {
180
            System.err.write(b);
181
        }
182
    }
183
184
    /**
185
     * An implementation of OutputStream that redirects to the
186
     * current System.out.
187
     *
188
     */
189
    private static class SystemOutStream extends OutputStream {
190
        public SystemOutStream() {
191
        }
192
193
        public void close() {
194
        }
195
196
        public void flush() {
197
            System.out.flush();
198
        }
199
200
        public void write(final byte[] b) throws IOException {
201
            System.out.write(b);
202
        }
203
204
        public void write(final byte[] b, final int off, final int len)
205
            throws IOException {
206
            System.out.write(b, off, len);
207
        }
208
209
        public void write(final int b) throws IOException {
210
            System.out.write(b);
211
        }
212
    }
213
}
214
(-)src/java/org/apache/log4j/concurrent/WriterAppender.java (+314 lines)
Line 0 Link Here
1
/*
2
 * Copyright 1999,2004 The Apache Software Foundation.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.log4j.concurrent;
18
19
import org.apache.log4j.spi.LoggingEvent;
20
21
import java.io.IOException;
22
import java.io.OutputStream;
23
import java.io.OutputStreamWriter;
24
import java.io.Writer;
25
import org.apache.log4j.Layout;
26
27
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
28
//              Ben Sandee
29
30
/**
31
   WriterAppender appends log events to a {@link java.io.Writer} or an
32
   {@link java.io.OutputStream} depending on the user's choice.
33
34
   @author Ceki G&uuml;lc&uuml;
35
   @since 1.1 */
36
public class WriterAppender extends ConcurrentAppender {
37
  
38
  /**
39
     Immediate flush means that the underlying writer or output stream
40
     will be flushed at the end of each append operation. Immediate
41
     flush is slower but ensures that each append request is actually
42
     written. If <code>immediateFlush</code> is set to
43
     <code>false</code>, then there is a good chance that the last few
44
     logs events are not actually written to persistent media if and
45
     when the application crashes.
46
47
     <p>The <code>immediateFlush</code> variable is set to
48
     <code>true</code> by default.
49
50
  */
51
  protected boolean immediateFlush = true;
52
53
  /**
54
     The encoding to use when opening an InputStream.  <p>The
55
     <code>encoding</code> variable is set to <code>null</null> by
56
     default which results in the utilization of the system's default
57
     encoding.  */
58
  protected String encoding;
59
60
  /**
61
   * This is the {@link Writer Writer} where we will write to.
62
   * Do not directly use this object without obtaining a write lock.
63
   */
64
  protected Writer writer;
65
66
  /**
67
   * The default constructor does nothing.  
68
   * */
69
  public WriterAppender() {
70
      super(false);
71
  }
72
73
  /**
74
     If the <b>ImmediateFlush</b> option is set to
75
     <code>true</code>, the appender will flush at the end of each
76
     write. This is the default behavior. If the option is set to
77
     <code>false</code>, then the underlying stream can defer writing
78
     to physical medium to a later time.
79
80
     <p>Avoiding the flush operation at the end of each append results in
81
     a performance gain of 10 to 20 percent. However, there is safety
82
     tradeoff involved in skipping flushing. Indeed, when flushing is
83
     skipped, then it is likely that the last few log events will not
84
     be recorded on disk when the application exits. This is a high
85
     price to pay even for a 20% performance gain.
86
   */
87
  public void setImmediateFlush(boolean value) {
88
    immediateFlush = value;
89
  }
90
91
  /**
92
     Returns value of the <b>ImmediateFlush</b> option.
93
   */
94
  public boolean getImmediateFlush() {
95
    return immediateFlush;
96
  }
97
98
  /**
99
   * Activates options.  Should be called only once.
100
   */
101
  public void activateOptions() {
102
103
    if (getLayout() == null) {
104
      getLogger().error(
105
        "No layout set for the appender named [{}].", name);
106
      return;
107
    }
108
109
    if (this.writer == null) {
110
      getLogger().error(
111
        "No writer set for the appender named [{}].", name);
112
      return;
113
    }
114
    
115
    active.set(true);
116
117
  }
118
119
  /**
120
     This method is called by the {@link AppenderSkeleton#doAppend}
121
     method.
122
123
     <p>If the output stream exists and is writable then write a log
124
     statement to the output stream. Otherwise, write a single warning
125
     message to <code>System.err</code>.
126
127
     <p>The format of the output will depend on this appender's
128
     layout.
129
130
  */
131
  public void append(LoggingEvent event) {
132
    subAppend(event);
133
  }
134
135
  /**
136
     Close this appender instance. The underlying stream or writer is
137
     also closed.
138
     <p>Closed appenders cannot be reused.
139
   */
140
  protected void internalClose() {
141
    closeWriter();
142
  }
143
144
  /**
145
   * Close the underlying {@link java.io.Writer}.
146
   */
147
  protected void closeWriter() {
148
    getWriteLock();
149
    try {
150
      if (this.writer == null)
151
        return;
152
      try {
153
        // before closing we have to output the footer
154
        writeFooter();
155
        this.writer.close();
156
        this.writer = null;
157
      } catch (IOException e) {
158
        getLogger().error("Could not close writer for WriterAppener named "+name, e);
159
      }
160
    } finally {
161
      releaseWriteLock();
162
    }
163
  }
164
165
  /**
166
     Returns an OutputStreamWriter when passed an OutputStream.  The
167
     encoding used will depend on the value of the
168
     <code>encoding</code> property.  If the encoding value is
169
     specified incorrectly the writer will be opened using the default
170
     system encoding (an error message will be printed to the loglog.  */
171
  protected OutputStreamWriter createWriter(OutputStream os) {
172
    OutputStreamWriter retval = null;
173
174
    String enc = getEncoding();
175
176
    if (enc != null) {
177
      try {
178
        retval = new OutputStreamWriter(os, enc);
179
      } catch (IOException e) {
180
        getLogger().warn("Error initializing output writer.");
181
        getLogger().warn("Unsupported encoding?");
182
      }
183
    }
184
185
    if (retval == null) {
186
      retval = new OutputStreamWriter(os);
187
    }
188
189
    return retval;
190
  }
191
192
  public String getEncoding() {
193
    return encoding;
194
  }
195
196
  public void setEncoding(String value) {
197
    encoding = value;
198
  }
199
200
  /**
201
    <p>Sets the Writer where the log output will go. The
202
    specified Writer must be opened by the user and be
203
    writable.
204
205
    <p>The <code>java.io.Writer</code> will be closed when the
206
    appender instance is closed.
207
208
209
    <p><b>WARNING:</b> Logging to an unopened Writer will fail.
210
    <p>
211
    @param writer An already opened Writer.  */
212
  public void setWriter(Writer writer) {
213
    // close any previously opened writer
214
    closeWriter();
215
    
216
    getWriteLock();
217
    try {
218
      this.writer = writer;
219
      writeHeader();
220
    } finally {
221
      releaseWriteLock();
222
    }
223
  }
224
225
  /**
226
   * Actual writing occurs here. 
227
   * <p>Most subclasses of <code>WriterAppender</code> will need to override 
228
   * this method.
229
   */
230
  protected void subAppend(LoggingEvent event) {
231
    try {
232
233
      // Format first
234
      Layout layout = getLayout();
235
      String se = layout.format(event);
236
      String st[] = null;
237
      if (layout.ignoresThrowable()) {
238
        st = event.getThrowableStrRep();
239
      }
240
241
      // Write as one message
242
      synchronized (this.writer) {
243
        this.writer.write(se);
244
        if (st != null) {
245
          int len = st.length;
246
          for (int i = 0; i < len; i++) {
247
            this.writer.write(st[i]);
248
            this.writer.write(Layout.LINE_SEP);
249
          }
250
        }
251
      }
252
253
      if (this.immediateFlush)
254
        this.writer.flush();
255
256
    } catch (IOException ioe) {
257
      boolean wasOrder = active.set(false);
258
      if (wasOrder) {
259
        getLogger().error("IO failure for appender named "+name, ioe);
260
      }
261
    }
262
  }
263
264
  /**
265
     The WriterAppender requires a layout. Hence, this method returns
266
     <code>true</code>.
267
  */
268
  public boolean requiresLayout() {
269
    return true;
270
  }
271
272
  /**
273
   * Write a footer as produced by the embedded layout's {@link 
274
   * Layout#getFooter} method.  
275
   */
276
  protected void writeFooter() {
277
    Layout layout = getLayout();
278
    if (layout != null) {
279
      String f = layout.getFooter();
280
281
      if ((f != null) && (this.writer != null)) {
282
        try {
283
          this.writer.write(f);
284
        } catch(IOException ioe) {
285
          active.set(false);
286
          getLogger().error("Failed to write footer for Appender named "+name, ioe);
287
        }
288
      }
289
    }
290
  }
291
292
  /**
293
   * Write a header as produced by the embedded layout's {@link 
294
   * Layout#getHeader} method.  
295
   */
296
  protected void writeHeader() {
297
    Layout layout = getLayout();
298
    if (layout != null) {
299
      String h = layout.getHeader();
300
301
      if ((h != null) && (this.writer != null)) {
302
        try {
303
          this.writer.write(h);
304
          this.writer.flush();
305
        } catch(IOException ioe) {
306
          active.set(false);
307
          getLogger().error("Failed to write header for WriterAppender named "+name, ioe);
308
        }
309
      }
310
    }
311
  }
312
313
314
}
(-)src/java/org/apache/log4j/concurrent/FileAppender.java (+290 lines)
Line 0 Link Here
1
/*
2
 * Copyright 1999,2004 The Apache Software Foundation.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * 
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.log4j.concurrent;
18
19
import java.io.Writer;
20
import java.io.BufferedWriter;
21
import java.io.File;
22
import java.io.FileOutputStream;
23
import java.io.FileNotFoundException;
24
import java.io.IOException;
25
26
import org.apache.log4j.Layout;
27
import org.apache.log4j.helpers.OptionConverter;
28
29
30
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
31
//              Ben Sandee
32
33
/**
34
 *  FileAppender appends log events to a file.
35
 *
36
 *  <p>Support for <code>java.io.Writer</code> and console appending
37
 *  has been deprecated and then removed. See the replacement
38
 *  solutions: {@link WriterAppender} and {@link ConsoleAppender}.
39
 *
40
 * @author Ceki G&uuml;lc&uuml;
41
 * */
42
public class FileAppender extends WriterAppender {
43
44
  public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
45
46
  /** 
47
   * Controls whether to append to or truncate an existing file. 
48
   * The default value for this variable is 
49
   * <code>true</code>, meaning that by default a <code>FileAppender</code> will
50
   *  append to an existing file and not truncate it. 
51
   * 
52
   * <p>This option is meaningful only if the FileAppender opens the file.
53
  */
54
  protected boolean fileAppend = true;
55
56
  /**
57
     The name of the log file. */
58
  protected String fileName = null;
59
60
  /**
61
     Do we do bufferedIO? */
62
  protected boolean bufferedIO = true;
63
64
  /**
65
     The size of the IO buffer. Default is 8K. */
66
  protected int bufferSize = DEFAULT_BUFFER_SIZE;
67
68
  /**
69
     The default constructor does not do anything.
70
  */
71
  public FileAppender() {
72
  }
73
74
  /**
75
    Instantiate a <code>FileAppender</code> and open the file
76
    designated by <code>filename</code>. The opened filename will
77
    become the output destination for this appender.
78
79
    <p>If the <code>append</code> parameter is true, the file will be
80
    appended to. Otherwise, the file designated by
81
    <code>filename</code> will be truncated before being opened.
82
83
    <p>If the <code>bufferedIO</code> parameter is <code>true</code>,
84
    then buffered IO will be used to write to the output file.
85
86
  */
87
  public FileAppender(
88
    Layout layout, String filename, boolean append, boolean bufferedIO,
89
    int bufferSize) throws IOException {
90
    setLayout(layout);
91
    this.setFile(filename, append, bufferedIO, bufferSize);
92
    activateOptions();
93
  }
94
95
  /**
96
    Instantiate a FileAppender and open the file designated by
97
    <code>filename</code>. The opened filename will become the output
98
    destination for this appender.
99
100
    <p>If the <code>append</code> parameter is true, the file will be
101
    appended to. Otherwise, the file designated by
102
    <code>filename</code> will be truncated before being opened.
103
  */
104
  public FileAppender(Layout layout, String filename, boolean append)
105
    throws IOException {
106
    this(layout, filename, append, false, DEFAULT_BUFFER_SIZE);
107
  }
108
109
  /**
110
     Instantiate a FileAppender and open the file designated by
111
    <code>filename</code>. The opened filename will become the output
112
    destination for this appender.
113
114
    <p>The file will be appended to.  */
115
  public FileAppender(Layout layout, String filename) throws IOException {
116
    this(layout, filename, true);
117
    activateOptions();
118
  }
119
120
  /**
121
     The <b>File</b> property takes a string value which should be the
122
     name of the file to append to.
123
124
     <p><font color="#DD0044"><b>Note that the special values
125
     "System.out" or "System.err" are no longer honored.</b></font>
126
127
     <p>Note: Actual opening of the file is made when {@link
128
     #activateOptions} is called, not when the options are set.  */
129
  public void setFile(String file) {
130
    // Trim spaces from both ends. The users probably does not want
131
    // trailing spaces in file names.
132
    String val = file.trim();
133
    fileName = OptionConverter.stripDuplicateBackslashes(val);
134
  }
135
136
  /**
137
      Returns the value of the <b>Append</b> option.
138
   */
139
  public boolean getAppend() {
140
    return fileAppend;
141
  }
142
143
  /** Returns the value of the <b>File</b> option. */
144
  public String getFile() {
145
    return fileName;
146
  }
147
148
  /**
149
     If the value of <b>File</b> is not <code>null</code>, then {@link
150
     #setFile} is called with the values of <b>File</b>  and
151
     <b>Append</b> properties.
152
153
     @since 0.8.1 */
154
  public void activateOptions() {
155
    if (fileName != null) {
156
      try {
157
        setFile(fileName, fileAppend, bufferedIO, bufferSize);
158
        super.activateOptions();
159
      } catch (java.io.IOException e) {
160
        getLogger().error(
161
          "setFile(" + fileName + "," + fileAppend + ") call failed.", e);
162
      }
163
    } else {
164
      getLogger().error("File option not set for appender [{}].", name);
165
      getLogger().warn("Are you using FileAppender instead of ConsoleAppender?");
166
    }
167
  }
168
169
  /**
170
   * Closes the previously opened file.
171
   * 
172
   * @deprecated Use the super class' {@link #closeWriter} method instead.
173
   */
174
  protected void closeFile() {
175
    closeWriter();
176
  }
177
178
  /**
179
     Get the value of the <b>BufferedIO</b> option.
180
181
     <p>BufferedIO will significantly increase performance on heavily
182
     loaded systems.
183
184
  */
185
  public boolean getBufferedIO() {
186
    return this.bufferedIO;
187
  }
188
189
  /**
190
     Get the size of the IO buffer.
191
  */
192
  public int getBufferSize() {
193
    return this.bufferSize;
194
  }
195
196
  /**
197
     The <b>Append</b> option takes a boolean value. It is set to
198
     <code>true</code> by default. If true, then <code>File</code>
199
     will be opened in append mode by {@link #setFile setFile} (see
200
     above). Otherwise, {@link #setFile setFile} will open
201
     <code>File</code> in truncate mode.
202
203
     <p>Note: Actual opening of the file is made when {@link
204
     #activateOptions} is called, not when the options are set.
205
   */
206
  public void setAppend(boolean flag) {
207
    fileAppend = flag;
208
  }
209
210
  /**
211
     The <b>BufferedIO</b> option takes a boolean value. It is set to
212
     <code>false</code> by default. If true, then <code>File</code>
213
     will be opened and the resulting {@link java.io.Writer} wrapped
214
     around a {@link BufferedWriter}.
215
216
     BufferedIO will significantly increase performance on heavily
217
     loaded systems.
218
219
  */
220
  public void setBufferedIO(boolean bufferedIO) {
221
    this.bufferedIO = bufferedIO;
222
  }
223
224
  /**
225
     Set the size of the IO buffer.
226
  */
227
  public void setBufferSize(int bufferSize) {
228
    this.bufferSize = bufferSize;
229
  }
230
231
  /**
232
    <p>Sets and <i>opens</i> the file where the log output will
233
    go. The specified file must be writable.
234
235
    <p>If there was already an opened file, then the previous file
236
    is closed first.
237
238
    <p><b>Do not use this method directly. To configure a FileAppender
239
    or one of its subclasses, set its properties one by one and then
240
    call activateOptions.</b>
241
242
    @param filename The path to the log file.
243
    @param append   If true will append to fileName. Otherwise will
244
        truncate fileName.
245
    @param bufferedIO
246
    @param bufferSize
247
    
248
    @throws IOException
249
        
250
   */
251
  public void setFile(
252
    String filename, boolean append, boolean bufferedIO, int bufferSize)
253
    throws IOException {
254
    getLogger().debug("setFile called: {}, {}", fileName, append?"true":"false");
255
256
    FileOutputStream ostream;
257
    try {
258
        //
259
        //   attempt to create file
260
        //
261
        ostream = new FileOutputStream(filename, append);
262
    } catch(FileNotFoundException ex) {
263
        //
264
        //   if parent directory does not exist then
265
        //      attempt to create it and try to create file
266
        //      see bug 9150
267
        //
268
        File parentDir = new File(new File(filename).getParent());
269
        if(!parentDir.exists() && parentDir.mkdirs()) {
270
            ostream = new FileOutputStream(filename, append);
271
        } else {
272
            throw ex;
273
        }
274
    }
275
    Writer writer = createWriter(ostream);
276
277
    if (bufferedIO) {
278
      writer = new BufferedWriter(writer, bufferSize);
279
    }
280
281
    this.fileAppend = append;
282
    this.bufferedIO = bufferedIO;
283
    this.fileName = filename;
284
    this.bufferSize = bufferSize;
285
286
    setWriter(writer);
287
    getLogger().debug("setFile ended");
288
  }
289
290
}
(-)src/java/org/apache/log4j/HTMLLayout.java (-4 / +8 lines)
Lines 38-43 Link Here
38
 * are specified using a conversion pattern. See 
38
 * are specified using a conversion pattern. See 
39
 * {@link org.apache.log4j.PatternLayout} for documentation on the available
39
 * {@link org.apache.log4j.PatternLayout} for documentation on the available
40
 * patterns. 
40
 * patterns. 
41
42
   <p>This class is thread safe;  it may be called by multiple threads
43
   simultaneously to format messages.
44
41
 * 
45
 * 
42
 * @author Ceki G&uuml;lc&uuml;
46
 * @author Ceki G&uuml;lc&uuml;
43
 * @author Steve Mactaggart
47
 * @author Steve Mactaggart
Lines 103-109 Link Here
103
  
107
  
104
  
108
  
105
  // counter keeping track of the rows output
109
  // counter keeping track of the rows output
106
  private long counter = 0;
110
  private int counter = 0;
107
  
111
  
108
  /**
112
  /**
109
   * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
113
   * Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
Lines 369-377 Link Here
369
   */
373
   */
370
  public String format(LoggingEvent event) {
374
  public String format(LoggingEvent event) {
371
    
375
    
372
    boolean odd = true;
376
    boolean odd;
373
    if(((counter++) & 1) == 0) {
377
    synchronized (this) {
374
      odd = false;
378
      odd = ((counter++) & 1) != 0;
375
    }
379
    }
376
    
380
    
377
    String level = event.getLevel().toString().toLowerCase();
381
    String level = event.getLevel().toString().toLowerCase();
(-)src/java/org/apache/log4j/AppenderSkeleton.java (-4 / +4 lines)
Lines 54-60 Link Here
54
   * 
54
   * 
55
   * @deprecated as of 1.3
55
   * @deprecated as of 1.3
56
   */
56
   */
57
  protected org.apache.log4j.spi.ErrorHandler errorHandler = new org.apache.log4j.helpers.OnlyOnceErrorHandler();
57
  protected org.apache.log4j.spi.ErrorHandler errorHandler = org.apache.log4j.helpers.OnlyOnceErrorHandler.INSTANCE;
58
58
59
  /**
59
  /**
60
   * The first filter in the filter chain. Set to <code>null</code> initially.
60
   * The first filter in the filter chain. Set to <code>null</code> initially.
Lines 165-177 Link Here
165
165
166
  /**
166
  /**
167
   * Return the hardcoded <code>OnlyOnceErrorHandler</code> for this Appender.
167
   * Return the hardcoded <code>OnlyOnceErrorHandler</code> for this Appender.
168
   * <code>ErrorHandler</code>'s are no longer utilized as of version 1.3.
168
   * <code>ErrorHandler</code>s are no longer utilized as of version 1.3.
169
   *
169
   *
170
   * @since 0.9.0
170
   * @since 0.9.0
171
   * @deprecated As of 1.3
171
   * @deprecated As of 1.3
172
   */
172
   */
173
  public org.apache.log4j.spi.ErrorHandler getErrorHandler() {
173
  public org.apache.log4j.spi.ErrorHandler getErrorHandler() {
174
    return this.errorHandler;
174
    return org.apache.log4j.helpers.OnlyOnceErrorHandler.INSTANCE;
175
  }
175
  }
176
176
177
  /**
177
  /**
Lines 199-205 Link Here
199
  }
199
  }
200
200
201
  /**
201
  /**
202
   * Returns the name of this FileAppender.
202
   * Returns the name of this appender.
203
   */
203
   */
204
  public final String getName() {
204
  public final String getName() {
205
    return this.name;
205
    return this.name;
(-)src/java/org/apache/log4j/PatternLayout.java (-15 / +8 lines)
Lines 405-410 Link Here
405
   Philip E. Margolis' highly recommended book "C -- a Software
405
   Philip E. Margolis' highly recommended book "C -- a Software
406
   Engineering Approach", ISBN 0-387-97389-3.
406
   Engineering Approach", ISBN 0-387-97389-3.
407
407
408
   <p>This class is thread safe;  it may be called by multiple threads
409
   simultaneously to format messages.
410
408
   @author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
411
   @author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
409
   @author Ceki G&uuml;lc&uuml;
412
   @author Ceki G&uuml;lc&uuml;
410
413
Lines 455-465 Link Here
455
  private FormattingInfo[] patternFields;
458
  private FormattingInfo[] patternFields;
456
459
457
  /**
460
  /**
458
   * String buffer used in formatting.
459
   */
460
  private StringBuffer buf = new StringBuffer();
461
462
  /**
463
   * True if any element in pattern formats information from exceptions.
461
   * True if any element in pattern formats information from exceptions.
464
   */
462
   */
465
  private boolean handlesExceptions;
463
  private boolean handlesExceptions;
Lines 550-570 Link Here
550
  }
548
  }
551
549
552
  /**
550
  /**
553
   *  Formats a logging event to a writer.
551
   * Formats an event.
554
   * @param event logging event to be formatted.
552
   */
555
  */
553
  public String format(LoggingEvent event) {
556
  public String format(final LoggingEvent event) {
554
    StringBuffer buf = new StringBuffer(80);
557
    buf.setLength(0);
558
559
    for (int i = 0; i < patternConverters.length; i++) {
555
    for (int i = 0; i < patternConverters.length; i++) {
560
      int startField = buf.length();
556
      int startField = buf.length();
561
      patternConverters[i].format(event, buf);
557
      patternConverters[i].format(event, buf);
562
      patternFields[i].format(startField, buf);
558
      patternFields[i].format(startField, buf);
563
    }
559
    }
564
560
    return buf.toString();
565
    String retval = buf.toString();
566
    buf.setLength(0);
567
    return retval;
568
  }
561
  }
569
562
570
  /**
563
  /**
(-)src/java/org/apache/log4j/spi/LocationInfo.java (-2 / +2 lines)
Lines 106-114 Link Here
106
    }
106
    }
107
    
107
    
108
    if(PlatformInfo.hasStackTraceElement()) {
108
    if(PlatformInfo.hasStackTraceElement()) {
109
      StackTraceElementExtractor.extract(this, t, fqnOfInvokingClass);
109
      // StackTraceElementExtractor.extract(this, t, fqnOfInvokingClass);
110
    } else {
110
    } else {
111
      LegacyExtractor.extract(this, t, fqnOfInvokingClass);  
111
      // LegacyExtractor.extract(this, t, fqnOfInvokingClass);  
112
    }
112
    }
113
  }
113
  }
114
114
(-)src/java/org/apache/log4j/spi/location/LegacyExtractor.java (-2 lines)
Lines 22-30 Link Here
22
22
23
import java.io.PrintWriter;
23
import java.io.PrintWriter;
24
import java.io.StringWriter;
24
import java.io.StringWriter;
25
import org.apache.log4j.spi.LocationInfo;
26
25
27
28
/**
26
/**
29
 * Extract location information from a throwable. The techniques used here
27
 * Extract location information from a throwable. The techniques used here
30
 * work on all JDK platforms including those prior to JDK 1.4.
28
 * work on all JDK platforms including those prior to JDK 1.4.
(-)src/java/org/apache/log4j/spi/location/StackTraceElementExtractor.java (-1 lines)
Lines 15-21 Link Here
15
 */
15
 */
16
16
17
package org.apache.log4j.spi.location;
17
package org.apache.log4j.spi.location;
18
import org.apache.log4j.spi.LocationInfo;
19
18
20
import java.lang.reflect.Method;
19
import java.lang.reflect.Method;
21
20
(-)src/java/org/apache/log4j/helpers/SyslogWriter.java (-1 / +1 lines)
Lines 36-42 Link Here
36
   @since 0.7.3
36
   @since 0.7.3
37
*/
37
*/
38
public class SyslogWriter extends Writer {
38
public class SyslogWriter extends Writer {
39
  final int SYSLOG_PORT = 514;
39
  final static int SYSLOG_PORT = 514;
40
  String syslogHost;
40
  String syslogHost;
41
  private InetAddress address;
41
  private InetAddress address;
42
  private DatagramSocket ds;
42
  private DatagramSocket ds;
(-)src/java/org/apache/log4j/helpers/LogLog.java (-1 / +8 lines)
Lines 64-70 Link Here
64
    <p>Note that the search for all option names is case sensitive.  */
64
    <p>Note that the search for all option names is case sensitive.  */
65
  public static final String CORE_DEBUG_KEY = "log4j.coreDebug";
65
  public static final String CORE_DEBUG_KEY = "log4j.coreDebug";
66
66
67
  protected static boolean debugEnabled = false;
67
  private static boolean debugEnabled = false;
68
68
69
  private static final String PREFIX = "log4j: ";
69
  private static final String PREFIX = "log4j: ";
70
  private static final String ERR_PREFIX = "log4j:ERROR ";
70
  private static final String ERR_PREFIX = "log4j:ERROR ";
Lines 87-92 Link Here
87
  }
87
  }
88
88
89
  /**
89
  /**
90
    Returns true if debug is enabled.
91
   */
92
  public static boolean isDebugEnabled() {
93
    return debugEnabled;
94
  }
95
  
96
  /**
90
     This method is used to output log4j internal debug
97
     This method is used to output log4j internal debug
91
     statements. Output goes to <code>System.out</code>.
98
     statements. Output goes to <code>System.out</code>.
92
  */
99
  */
(-)src/java/org/apache/log4j/helpers/OnlyOnceErrorHandler.java (+7 lines)
Lines 19-24 Link Here
19
import org.apache.log4j.Appender;
19
import org.apache.log4j.Appender;
20
import org.apache.log4j.Logger;
20
import org.apache.log4j.Logger;
21
import org.apache.log4j.spi.LoggingEvent;
21
import org.apache.log4j.spi.LoggingEvent;
22
import org.apache.log4j.spi.ErrorHandler;
22
23
23
/**
24
/**
24
   <code>ErrorHandler</code> and its implementations are no longer
25
   <code>ErrorHandler</code> and its implementations are no longer
Lines 32-37 Link Here
32
   @deprecated As of 1.3
33
   @deprecated As of 1.3
33
 */
34
 */
34
public class OnlyOnceErrorHandler implements org.apache.log4j.spi.ErrorHandler {
35
public class OnlyOnceErrorHandler implements org.apache.log4j.spi.ErrorHandler {
36
37
  /** 
38
   * Default instance of this class.
39
   */
40
  public static final ErrorHandler INSTANCE = new OnlyOnceErrorHandler();
41
35
  public void setLogger(Logger logger) {}
42
  public void setLogger(Logger logger) {}
36
  public void activateOptions() {}
43
  public void activateOptions() {}
37
  public void error(String message, Exception e, int errorCode) {}
44
  public void error(String message, Exception e, int errorCode) {}
(-)src/java/org/apache/log4j/joran/JoranConfigurator.java (-1 lines)
Lines 71-77 Link Here
71
public class JoranConfigurator extends ConfiguratorBase {
71
public class JoranConfigurator extends ConfiguratorBase {
72
  Interpreter joranInterpreter;
72
  Interpreter joranInterpreter;
73
  LoggerRepository repository;
73
  LoggerRepository repository;
74
  boolean listAppnderAttached = false;
75
74
76
  public JoranConfigurator() {
75
  public JoranConfigurator() {
77
  }
76
  }
(-)src/java/org/apache/log4j/WriterAppender.java (-1 lines)
Lines 24-30 Link Here
24
import java.io.OutputStreamWriter;
24
import java.io.OutputStreamWriter;
25
import java.io.Writer;
25
import java.io.Writer;
26
import org.apache.log4j.helpers.QuietWriter;
26
import org.apache.log4j.helpers.QuietWriter;
27
import org.apache.log4j.helpers.LogLog;
28
27
29
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
28
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
30
//              Ben Sandee
29
//              Ben Sandee
(-)src/java/org/apache/log4j/pattern/DatePatternConverter.java (-2 / +2 lines)
Lines 110-116 Link Here
110
  /**
110
  /**
111
   * {@inheritDoc}
111
   * {@inheritDoc}
112
   */
112
   */
113
  public void format(final LoggingEvent event, final StringBuffer output) {
113
  public synchronized void format(final LoggingEvent event, final StringBuffer output) {
114
    df.format(event.getTimeStamp(), output);
114
    df.format(event.getTimeStamp(), output);
115
  }
115
  }
116
116
Lines 130-136 Link Here
130
   * @param date date
130
   * @param date date
131
   * @param toAppendTo buffer to which formatted date is appended.
131
   * @param toAppendTo buffer to which formatted date is appended.
132
   */
132
   */
133
  public void format(final Date date, final StringBuffer toAppendTo) {
133
  public synchronized void format(final Date date, final StringBuffer toAppendTo) {
134
    df.format(date.getTime(), toAppendTo);
134
    df.format(date.getTime(), toAppendTo);
135
  }
135
  }
136
}
136
}
(-)src/java/org/apache/log4j/pattern/PatternConverter.java (+5 lines)
Lines 26-31 Link Here
26
   individual PatternConverters. Each of which is responsible for
26
   individual PatternConverters. Each of which is responsible for
27
   converting an object in a converter specific manner.
27
   converting an object in a converter specific manner.
28
28
29
   <p>A PatternConverter should be written to be thread-safe.
30
   This allows multiple threads to safely use the same pattern converter.
31
29
   @author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
32
   @author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
30
   @author Ceki G&uuml;lc&uuml;
33
   @author Ceki G&uuml;lc&uuml;
31
   @author Chris Nokes
34
   @author Chris Nokes
Lines 56-61 Link Here
56
59
57
  /**
60
  /**
58
   * Formats an object into a string buffer.
61
   * Formats an object into a string buffer.
62
   * This method may be called simultaneously by multiple threads.
63
   *
59
   * @param obj event to format, may not be null.
64
   * @param obj event to format, may not be null.
60
   * @param toAppendTo string buffer to which the formatted event will be appended.  May not be null.
65
   * @param toAppendTo string buffer to which the formatted event will be appended.  May not be null.
61
   */
66
   */
(-)src/java/org/apache/log4j/FileAppender.java (-14 / +8 lines)
Lines 39-44 Link Here
39
 * @author Ceki G&uuml;lc&uuml;
39
 * @author Ceki G&uuml;lc&uuml;
40
 * */
40
 * */
41
public class FileAppender extends WriterAppender {
41
public class FileAppender extends WriterAppender {
42
43
  public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
44
42
  /** 
45
  /** 
43
   * Controls whether to append to or truncate an existing file. 
46
   * Controls whether to append to or truncate an existing file. 
44
   * The default value for this variable is 
47
   * The default value for this variable is 
Lines 55-65 Link Here
55
58
56
  /**
59
  /**
57
     Do we do bufferedIO? */
60
     Do we do bufferedIO? */
58
  protected boolean bufferedIO = false;
61
  protected boolean bufferedIO = true;
59
62
60
  /**
63
  /**
61
     The size of the IO buffer. Default is 8K. */
64
     The size of the IO buffer. Default is 8K. */
62
  protected int bufferSize = 8 * 1024;
65
  protected int bufferSize = DEFAULT_BUFFER_SIZE;
63
66
64
  /**
67
  /**
65
     The default constructor does not do anything.
68
     The default constructor does not do anything.
Lines 176-182 Link Here
176
  /**
179
  /**
177
     Get the value of the <b>BufferedIO</b> option.
180
     Get the value of the <b>BufferedIO</b> option.
178
181
179
     <p>BufferedIO will significatnly increase performance on heavily
182
     <p>BufferedIO will significantly increase performance on heavily
180
     loaded systems.
183
     loaded systems.
181
184
182
  */
185
  */
Lines 211-226 Link Here
211
     will be opened and the resulting {@link java.io.Writer} wrapped
214
     will be opened and the resulting {@link java.io.Writer} wrapped
212
     around a {@link BufferedWriter}.
215
     around a {@link BufferedWriter}.
213
216
214
     BufferedIO will significatnly increase performance on heavily
217
     BufferedIO will significantly increase performance on heavily
215
     loaded systems.
218
     loaded systems.
216
219
217
  */
220
  */
218
  public void setBufferedIO(boolean bufferedIO) {
221
  public void setBufferedIO(boolean bufferedIO) {
219
    this.bufferedIO = bufferedIO;
222
    this.bufferedIO = bufferedIO;
220
221
    if (bufferedIO) {
222
      immediateFlush = false;
223
    }
224
  }
223
  }
225
224
226
  /**
225
  /**
Lines 255-268 Link Here
255
    throws IOException {
254
    throws IOException {
256
    getLogger().debug("setFile called: {}, {}", fileName, append?"true":"false");
255
    getLogger().debug("setFile called: {}, {}", fileName, append?"true":"false");
257
256
258
    // It does not make sense to have immediate flush and bufferedIO.
259
    if (bufferedIO) {
260
      setImmediateFlush(false);
261
    }
262
263
    closeWriter();
257
    closeWriter();
264
258
265
    FileOutputStream ostream = null;
259
    FileOutputStream ostream;
266
    try {
260
    try {
267
        //
261
        //
268
        //   attempt to create file
262
        //   attempt to create file
(-)src/java/org/apache/log4j/plugins/Receiver.java (-8 lines)
Lines 59-72 Link Here
59
public abstract class Receiver extends PluginSkeleton implements Thresholdable {
59
public abstract class Receiver extends PluginSkeleton implements Thresholdable {
60
	protected Level thresholdLevel;
60
	protected Level thresholdLevel;
61
  
61
  
62
  /*
63
   * An instance specific logger which must be accessed through the getLogger()
64
   * method. 
65
   */
66
  private Logger logger;
67
  
68
  
69
  
70
  /**
62
  /**
71
    Sets the receiver theshold to the given level.
63
    Sets the receiver theshold to the given level.
72
    
64
    
(-)src/java/org/apache/log4j/net/SyslogAppender.java (-1 lines)
Lines 128-134 Link Here
128
128
129
  //SyslogTracerPrintWriter stp;
129
  //SyslogTracerPrintWriter stp;
130
  private SyslogWriter sw;
130
  private SyslogWriter sw;
131
  private final Calendar calendar = Calendar.getInstance();
132
  private long now = -1;
131
  private long now = -1;
133
  private Date date = new Date();
132
  private Date date = new Date();
134
  private StringBuffer timestamp = new StringBuffer();
133
  private StringBuffer timestamp = new StringBuffer();
(-)src/java/org/apache/log4j/net/SocketNode.java (-2 / +1 lines)
Lines 53-59 Link Here
53
  private boolean paused;
53
  private boolean paused;
54
  private Socket socket;
54
  private Socket socket;
55
  private Receiver receiver;
55
  private Receiver receiver;
56
  private SocketNodeEventListener listener;
57
  private List listenerList = Collections.synchronizedList(new ArrayList());
56
  private List listenerList = Collections.synchronizedList(new ArrayList());
58
57
59
  /**
58
  /**
Lines 186-192 Link Here
186
    }
185
    }
187
186
188
    // send event to listener, if configured
187
    // send event to listener, if configured
189
    if (listener != null || listenerList.size()>0) {
188
    if (listenerList.size()>0) {
190
      fireSocketClosedEvent(listenerException);
189
      fireSocketClosedEvent(listenerException);
191
    }
190
    }
192
  }
191
  }
(-)src/java/org/apache/log4j/xml/XMLLayout.java (-1 / +4 lines)
Lines 59-64 Link Here
59
 * for output generated by log4j versions prior to log4j 1.2 (final release) and
59
 * for output generated by log4j versions prior to log4j 1.2 (final release) and
60
 * "1.2" for relase 1.2 and later.
60
 * "1.2" for relase 1.2 and later.
61
 *
61
 *
62
   <p>This class is thread safe;  it may be called by multiple threads
63
   simultaneously to format messages.
64
62
 * Contributors:   Mathias Bogaert
65
 * Contributors:   Mathias Bogaert
63
 * 
66
 * 
64
 * @author Ceki G&uuml;lc&uuml;
67
 * @author Ceki G&uuml;lc&uuml;
Lines 207-213 Link Here
207
        String propName = propIter.next().toString();
210
        String propName = propIter.next().toString();
208
        buf.append("    <log4j:data name=\"" + propName);
211
        buf.append("    <log4j:data name=\"" + propName);
209
212
210
        String propValue = event.getProperty(propName).toString();
213
        String propValue = event.getProperty(propName);
211
        buf.append("\" value=\"" + propValue);
214
        buf.append("\" value=\"" + propValue);
212
        buf.append("\"/>\r\n");
215
        buf.append("\"/>\r\n");
213
      }
216
      }
(-)src/java/org/apache/log4j/config/PropertySetter.java (-1 lines)
Lines 60-66 Link Here
60
  public static final int NOT_FOUND = 0;
60
  public static final int NOT_FOUND = 0;
61
  public static final int AS_PROPERTY = 1;
61
  public static final int AS_PROPERTY = 1;
62
  public static final int AS_COLLECTION = 2;
62
  public static final int AS_COLLECTION = 2;
63
  Logger logger;
64
  protected Object obj;
63
  protected Object obj;
65
  protected Class objClass;
64
  protected Class objClass;
66
  protected PropertyDescriptor[] props;
65
  protected PropertyDescriptor[] props;
(-)src/java/org/apache/log4j/RollingFileAppender.java (-8 / +1 lines)
Lines 41-53 Link Here
41
public class RollingFileAppender implements Appender, OptionHandler {
41
public class RollingFileAppender implements Appender, OptionHandler {
42
42
43
  /**
43
  /**
44
   * It is assumed and enforced that errorHandler is never null.
45
   * 
46
   * @deprecated as of 1.3
47
   */
48
  private final org.apache.log4j.spi.ErrorHandler errorHandler = new org.apache.log4j.helpers.OnlyOnceErrorHandler();
49
50
  /**
51
     The default maximum file size is 10MB.
44
     The default maximum file size is 10MB.
52
  */
45
  */
53
  private long maxFileSize = 10 * 1024 * 1024;
46
  private long maxFileSize = 10 * 1024 * 1024;
Lines 398-404 Link Here
398
     * @deprecated As of 1.3
391
     * @deprecated As of 1.3
399
     */
392
     */
400
    public final org.apache.log4j.spi.ErrorHandler getErrorHandler() {
393
    public final org.apache.log4j.spi.ErrorHandler getErrorHandler() {
401
      return this.errorHandler;
394
      return org.apache.log4j.helpers.OnlyOnceErrorHandler.INSTANCE;
402
    }
395
    }
403
396
404
    /**
397
    /**
(-)src/java/org/apache/log4j/SimpleLayout.java (-1 / +3 lines)
Lines 29-34 Link Here
29
           DEBUG - Hello world
29
           DEBUG - Hello world
30
   </pre>
30
   </pre>
31
31
32
   <p>This class is thread safe;  it may be called by multiple threads
33
   simultaneously to format messages.
34
32
   <p>
35
   <p>
33
   @author Ceki G&uuml;lc&uuml;
36
   @author Ceki G&uuml;lc&uuml;
34
   @since version 0.7.0
37
   @since version 0.7.0
Lines 36-42 Link Here
36
   <p>{@link PatternLayout} offers a much more powerful alternative.
39
   <p>{@link PatternLayout} offers a much more powerful alternative.
37
*/
40
*/
38
public class SimpleLayout extends Layout {
41
public class SimpleLayout extends Layout {
39
  StringBuffer sbuf = new StringBuffer(128);
40
42
41
  public SimpleLayout() {
43
  public SimpleLayout() {
42
  }
44
  }
(-)src/java/org/apache/log4j/scheduler/Scheduler.java (-3 / +3 lines)
Lines 82-88 Link Here
82
      // if the job is the first on the list, then notify the scheduler thread
82
      // if the job is the first on the list, then notify the scheduler thread
83
      // to schedule a new job
83
      // to schedule a new job
84
      if(i == 0) {
84
      if(i == 0) {
85
        this.notify();
85
        this.notifyAll();
86
      }
86
      }
87
      return true;
87
      return true;
88
    } else {
88
    } else {
Lines 154-164 Link Here
154
    jobList.add(i, newSJE);
154
    jobList.add(i, newSJE);
155
    // if the jobList was empty, then notify the scheduler thread
155
    // if the jobList was empty, then notify the scheduler thread
156
    if(i == 0) {
156
    if(i == 0) {
157
      this.notify();
157
      this.notifyAll();
158
    }
158
    }
159
  }
159
  }
160
  
160
  
161
  public void shutdown() {
161
  public synchronized void shutdown() {
162
    shutdown = true;
162
    shutdown = true;
163
  }
163
  }
164
  
164
  
(-)tests/src/java/org/apache/log4j/DeadlockTest.java (-5 / +7 lines)
Lines 22-29 Link Here
22
/**
22
/**
23
 * Test case for bug http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24159
23
 * Test case for bug http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24159
24
 *
24
 *
25
 * Actually this one is impossible to fix.
26
 *
27
 * @author Elias Ross
25
 * @author Elias Ross
28
 * @author Ceki Gulcu
26
 * @author Ceki Gulcu
29
 */
27
 */
Lines 31-44 Link Here
31
  static long RUNLENGTH = 10000;
29
  static long RUNLENGTH = 10000;
32
  Logger logger = Logger.getLogger("DeadlockTest");
30
  Logger logger = Logger.getLogger("DeadlockTest");
33
31
34
  public DeadlockTest() {
32
  public DeadlockTest(String name) {
35
      super("DeadlockTest");
33
      super(name);
36
  }
34
  }
37
  
35
  
38
  protected void setUp() throws Exception {
36
  protected void setUp() throws Exception {
39
    super.setUp();
37
    super.setUp();
40
    System.out.println("in setup");
38
    System.out.println("in setup");
41
    BasicConfigurator.configure();
39
40
    Logger root = Logger.getRootLogger();
41
    root.addAppender(
42
      new org.apache.log4j.concurrent.ConsoleAppender(
43
        new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
42
  }
44
  }
43
45
44
  protected void tearDown() throws Exception {
46
  protected void tearDown() throws Exception {
(-)tests/build.xml (+8 lines)
Lines 798-803 Link Here
798
    </junit>
798
    </junit>
799
  </target>
799
  </target>
800
800
801
  <target name="DeadlockTest" > <!-- depends="build"-->
802
    <junit printsummary="yes" fork="yes" haltonfailure="yes">
803
      <sysproperty key="runLen" value="100"/>     
804
      <classpath refid="tests.classpath"/>
805
      <formatter type="plain" usefile="false"/>
806
      <test name="org.apache.log4j.DeadlockTest" />
807
    </junit>
808
  </target>
801
809
802
  <!-- ============================================================= --> 
810
  <!-- ============================================================= --> 
803
  <!--                      DB tests                                 -->
811
  <!--                      DB tests                                 -->

Return to bug 24159