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