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 }