View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j;
19  
20  import junit.framework.TestCase;
21  import junit.framework.TestSuite;
22  import junit.framework.Test;
23  
24  import java.util.Vector;
25  
26  import org.apache.log4j.*;
27  import org.apache.log4j.spi.LoggingEvent;
28  import org.apache.log4j.varia.NullAppender;
29  
30  /***
31     A superficial but general test of log4j.
32   */
33  public class AsyncAppenderTestCase extends TestCase {
34  
35    public AsyncAppenderTestCase(String name) {
36      super(name);
37    }
38  
39    public void setUp() {
40    }
41  
42    public void tearDown() {
43      LogManager.shutdown();
44    }
45  
46    // this test checks whether it is possible to write to a closed AsyncAppender
47    public void closeTest() throws Exception {    
48      Logger root = Logger.getRootLogger();
49      Layout layout = new SimpleLayout();
50      VectorAppender vectorAppender = new VectorAppender();
51      AsyncAppender asyncAppender = new AsyncAppender();
52      asyncAppender.setName("async-CloseTest");
53      asyncAppender.addAppender(vectorAppender);
54      root.addAppender(asyncAppender); 
55  
56      root.debug("m1");
57      asyncAppender.close();
58      root.debug("m2");
59      
60      Vector v = vectorAppender.getVector();
61      assertEquals(v.size(), 1);
62    }
63  
64    // this test checks whether appenders embedded within an AsyncAppender are also 
65    // closed 
66    public void test2() {
67      Logger root = Logger.getRootLogger();
68      Layout layout = new SimpleLayout();
69      VectorAppender vectorAppender = new VectorAppender();
70      AsyncAppender asyncAppender = new AsyncAppender();
71      asyncAppender.setName("async-test2");
72      asyncAppender.addAppender(vectorAppender);
73      root.addAppender(asyncAppender); 
74  
75      root.debug("m1");
76      asyncAppender.close();
77      root.debug("m2");
78      
79      Vector v = vectorAppender.getVector();
80      assertEquals(v.size(), 1);
81      assertTrue(vectorAppender.isClosed());
82    }
83  
84    // this test checks whether appenders embedded within an AsyncAppender are also 
85    // closed 
86    public void test3() {
87      int LEN = 200;
88      Logger root = Logger.getRootLogger();
89      Layout layout = new SimpleLayout();
90      VectorAppender vectorAppender = new VectorAppender();
91      AsyncAppender asyncAppender = new AsyncAppender();
92      asyncAppender.setName("async-test3");
93      asyncAppender.addAppender(vectorAppender);
94      root.addAppender(asyncAppender); 
95  
96      for(int i = 0; i < LEN; i++) {
97        root.debug("message"+i);
98      }
99      
100     System.out.println("Done loop.");
101     System.out.flush();
102     asyncAppender.close();
103     root.debug("m2");
104     
105     Vector v = vectorAppender.getVector();
106     assertEquals(v.size(), LEN);
107     assertTrue(vectorAppender.isClosed());
108   }
109 
110     private static class NullPointerAppender extends AppenderSkeleton {
111           public NullPointerAppender() {
112           }
113 
114 
115           /***
116              This method is called by the {@link org.apache.log4j.AppenderSkeleton#doAppend}
117              method.
118 
119           */
120           public void append(org.apache.log4j.spi.LoggingEvent event) {
121               throw new NullPointerException();
122           }
123 
124           public void close() {
125           }
126 
127           public boolean requiresLayout() {
128             return false;
129           }
130     }
131 
132 
133     /***
134      * Tests that a bad appender will switch async back to sync.
135      * See bug 23021
136      * @since 1.2.12
137      * @throws Exception thrown if Thread.sleep is interrupted
138      */
139     public void testBadAppender() throws Exception {
140         Appender nullPointerAppender = new NullPointerAppender();
141         AsyncAppender asyncAppender = new AsyncAppender();
142         asyncAppender.addAppender(nullPointerAppender);
143         asyncAppender.setBufferSize(5);
144         asyncAppender.activateOptions();
145         Logger root = Logger.getRootLogger();
146         root.addAppender(nullPointerAppender);
147         try {
148            root.info("Message");
149            Thread.sleep(10);
150            root.info("Message");
151            fail("Should have thrown exception");
152         } catch(NullPointerException ex) {
153 
154         }
155     }
156 
157     /***
158      * Tests location processing when buffer is full and locationInfo=true.
159      * See bug 41186.
160      */
161     public void testLocationInfoTrue() {
162         BlockableVectorAppender blockableAppender = new BlockableVectorAppender();
163         AsyncAppender async = new AsyncAppender();
164         async.addAppender(blockableAppender);
165         async.setBufferSize(5);
166         async.setLocationInfo(true);
167         async.setBlocking(false);
168         async.activateOptions();
169         Logger rootLogger = Logger.getRootLogger();
170         rootLogger.addAppender(async);
171         Greeter greeter = new Greeter(rootLogger, 100);
172         synchronized(blockableAppender.getMonitor()) {
173             greeter.run();
174             rootLogger.error("That's all folks.");
175         }
176         async.close();
177         Vector events = blockableAppender.getVector();
178         LoggingEvent initialEvent = (LoggingEvent) events.get(0);
179         LoggingEvent discardEvent = (LoggingEvent) events.get(events.size() - 1);
180         PatternLayout layout = new PatternLayout();
181         layout.setConversionPattern("%C:%L %m%n");
182         layout.activateOptions();
183         String initialStr = layout.format(initialEvent);
184         assertEquals(AsyncAppenderTestCase.class.getName(),
185                 initialStr.substring(0, AsyncAppenderTestCase.class.getName().length()));
186         String discardStr = layout.format(discardEvent);
187         assertEquals("?:? ", discardStr.substring(0, 4));
188     }
189 
190 
191     /***
192      * Tests location processing when buffer is full and locationInfo=false.
193      * See bug 41186.
194      */
195     public void testLocationInfoFalse() {
196         BlockableVectorAppender blockableAppender = new BlockableVectorAppender();
197         AsyncAppender async = new AsyncAppender();
198         async.addAppender(blockableAppender);
199         async.setBufferSize(5);
200         async.setLocationInfo(false);
201         async.setBlocking(false);
202         async.activateOptions();
203         Logger rootLogger = Logger.getRootLogger();
204         rootLogger.addAppender(async);
205         Greeter greeter = new Greeter(rootLogger, 100);
206         synchronized(blockableAppender.getMonitor()) {
207             greeter.run();
208             rootLogger.error("That's all folks.");
209         }
210         async.close();
211         Vector events = blockableAppender.getVector();
212         LoggingEvent initialEvent = (LoggingEvent) events.get(0);
213         LoggingEvent discardEvent = (LoggingEvent) events.get(events.size() - 1);
214         PatternLayout layout = new PatternLayout();
215         layout.setConversionPattern("%C:%L %m%n");
216         layout.activateOptions();
217         String initialStr = layout.format(initialEvent);
218         assertEquals("?:? ", initialStr.substring(0, 4));
219         String discardStr = layout.format(discardEvent);
220         assertEquals("?:? ", discardStr.substring(0, 4));
221     }
222 
223     /***
224      *  Logging request runnable.
225      */
226     private static final class Greeter implements Runnable {
227       /***
228        * Logger.
229        */
230       private final Logger logger;
231 
232       /***
233        * Repetitions.
234        */
235       private final int repetitions;
236 
237       /***
238        * Create new instance.
239        * @param logger logger, may not be null.
240        * @param repetitions repetitions.
241        */
242       public Greeter(final Logger logger, final int repetitions) {
243         if (logger == null) {
244           throw new IllegalArgumentException("logger");
245         }
246 
247         this.logger = logger;
248         this.repetitions = repetitions;
249       }
250 
251       /***
252        * {@inheritDoc}
253        */
254       public void run() {
255         try {
256           for (int i = 0; i < repetitions; i++) {
257             logger.info("Hello, World");
258             Thread.sleep(1);
259           }
260         } catch (InterruptedException ex) {
261           Thread.currentThread().interrupt();
262         }
263       }
264     }
265 
266 
267 
268     /***
269      * Vector appender that can be explicitly blocked.
270      */
271     private static final class BlockableVectorAppender extends VectorAppender {
272       /***
273        * Monitor object used to block appender.
274        */
275       private final Object monitor = new Object();
276 
277       /***
278        * Thread of last call to append.
279        */
280       private Thread dispatcher;
281 
282       /***
283        * Create new instance.
284        */
285       public BlockableVectorAppender() {
286         super();
287       }
288 
289       /***
290        * {@inheritDoc}
291        */
292       public void append(final LoggingEvent event) {
293         synchronized (monitor) {
294           dispatcher = Thread.currentThread();
295           super.append(event);
296             //
297             //   if fatal, echo messages for testLoggingInDispatcher
298             //
299             if (event.getLevel() == Level.FATAL) {
300                 Logger logger = Logger.getLogger(event.getLoggerName());
301                 logger.error(event.getMessage().toString());
302                 logger.warn(event.getMessage().toString());
303                 logger.info(event.getMessage().toString());
304                 logger.debug(event.getMessage().toString());
305             }
306         }
307       }
308 
309       /***
310        * Get monitor object.
311        * @return monitor.
312        */
313       public Object getMonitor() {
314         return monitor;
315       }
316 
317       /***
318        * Get thread of previous call to append.
319        * @return thread, may be null.
320        */
321       public Thread getDispatcher() {
322         synchronized (monitor) {
323           return dispatcher;
324         }
325       }
326     }
327 
328 
329 }