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.lf5;
    19
    20  import org.apache.log4j.lf5.util.Resource;
    21  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
    22  import org.apache.log4j.AppenderSkeleton;
    23  import org.apache.log4j.spi.LocationInfo;
    24  import org.apache.log4j.spi.LoggingEvent;
    25
    26  import java.awt.*;
    27
    28  /***
    29   * <code>LF5Appender</code> logs events to a swing based logging
    30   * console. The swing console supports turning categories on and off,
    31   * multiple detail level views, as well as full text searching and many
    32   * other capabilties.
    33   *
    34   * @author Brent Sprecher
    35   */
    36
    37  // Contributed by ThoughtWorks Inc.
    38
    39  public class LF5Appender extends AppenderSkeleton {
    40    //--------------------------------------------------------------------------
    41    // Constants:
    42    //--------------------------------------------------------------------------
    43
    44    //--------------------------------------------------------------------------
    45    // Protected Variables:
    46    //--------------------------------------------------------------------------
    47
    48    protected LogBrokerMonitor _logMonitor;
    49    protected static LogBrokerMonitor _defaultLogMonitor;
    50    protected static AppenderFinalizer _finalizer;
    51
    52    //--------------------------------------------------------------------------
    53    // Private Variables:
    54    //--------------------------------------------------------------------------
    55
    56    //--------------------------------------------------------------------------
    57    // Constructors:
    58    //--------------------------------------------------------------------------
    59
    60    /***
    61     * Constructs a <code>LF5Appender</code> using the default instance of
    62     * the <code>LogBrokerMonitor</code>. This constructor should <bold>always
    63     * </bold> be  preferred over the
    64     * <code>LF5Appender(LogBrokerMonitor monitor)</code>
    65     * constructor, unless you need to spawn additional log monitoring
    66     * windows.
    67     */
    68    public LF5Appender() {
    69      this(getDefaultInstance());
    70    }
    71
    72    /***
    73     * Constructs a <code>LF5Appender<code> using an instance of
    74     * a <code>LogBrokerMonitor<code> supplied by the user. This
    75     * constructor should only be used when you need to spawn
    76     * additional log monitoring windows.
    77     *
    78     * @param monitor An instance of a <code>LogBrokerMonitor<code>
    79     * created by the user.
    80     */
    81    public LF5Appender(LogBrokerMonitor monitor) {
    82
    83      if (monitor != null) {
    84        _logMonitor = monitor;
    85      }
    86    }
    87
    88    //--------------------------------------------------------------------------
    89    // Public Methods:
    90    //--------------------------------------------------------------------------
    91
    92    /***
    93     * Appends a <code>LoggingEvent</code> record to the
    94     * <code>LF5Appender</code>.
    95     * @param event The <code>LoggingEvent</code>
    96     * to be appended.
    97     */
    98    public void append(LoggingEvent event) {
    99      // Retrieve the information from the log4j LoggingEvent.
    100     String category = event.getLoggerName();
    101     String logMessage = event.getRenderedMessage();
    102     String nestedDiagnosticContext = event.getNDC();
    103     String threadDescription = event.getThreadName();
    104     String level = event.getLevel().toString();
    105     long time = event.timeStamp;
    106     LocationInfo locationInfo = event.getLocationInformation();
    107
    108     // Add the logging event information to a LogRecord
    109     Log4JLogRecord record = new Log4JLogRecord();
    110
    111     record.setCategory(category);
    112     record.setMessage(logMessage);
    113     record.setLocation(locationInfo.fullInfo);
    114     record.setMillis(time);
    115     record.setThreadDescription(threadDescription);
    116
    117     if (nestedDiagnosticContext != null) {
    118       record.setNDC(nestedDiagnosticContext);
    119     } else {
    120       record.setNDC("");
    121     }
    122
    123     if (event.getThrowableInformation() != null) {
    124       record.setThrownStackTrace(event.getThrowableInformation());
    125     }
    126
    127     try {
    128       record.setLevel(LogLevel.valueOf(level));
    129     } catch (LogLevelFormatException e) {
    130       // If the priority level doesn't match one of the predefined
    131       // log levels, then set the level to warning.
    132       record.setLevel(LogLevel.WARN);
    133     }
    134
    135     if (_logMonitor != null) {
    136       _logMonitor.addMessage(record);
    137     }
    138   }
    139
    140   /***
    141    * This method is an empty implementation of the close() method inherited
    142    * from the <code>org.apache.log4j.Appender</code> interface.
    143    */
    144   public void close() {
    145   }
    146
    147   /***
    148    * Returns a value that indicates whether this appender requires a
    149    * <code>Layout</code>. This method always returns false.
    150    * No layout is required for the <code>LF5Appender</code>.
    151    */
    152   public boolean requiresLayout() {
    153     return false;
    154   }
    155
    156   /***
    157    * This method is used to set the property that controls whether
    158    * the <code>LogBrokerMonitor</code> is hidden or closed when a user
    159    * exits
    160    * the monitor. By default, the <code>LogBrokerMonitor</code> will hide
    161    * itself when the log window is exited, and the swing thread will
    162    * continue to run in the background. If this property is
    163    * set to true, the <code>LogBrokerMonitor</code> will call System.exit(0)
    164    * and will shut down swing thread and the virtual machine.
    165    *
    166    * @param callSystemExitOnClose A boolean value indicating whether
    167    * to call System.exit(0) when closing the log window.
    168    */
    169   public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
    170     _logMonitor.setCallSystemExitOnClose(callSystemExitOnClose);
    171   }
    172
    173   /***
    174    * The equals method compares two LF5Appenders and determines whether
    175    * they are equal. Two <code>Appenders</code> will be considered equal
    176    * if, and only if, they both contain references to the same <code>
    177    * LogBrokerMonitor</code>.
    178    *
    179    * @param compareTo A boolean value indicating whether
    180    * the two LF5Appenders are equal.
    181    */
    182   public boolean equals(LF5Appender compareTo) {
    183     // If both reference the same LogBrokerMonitor, they are equal.
    184     return _logMonitor == compareTo.getLogBrokerMonitor();
    185   }
    186
    187   public LogBrokerMonitor getLogBrokerMonitor() {
    188     return _logMonitor;
    189   }
    190
    191   public static void main(String[] args) {
    192     new LF5Appender();
    193   }
    194
    195   public void setMaxNumberOfRecords(int maxNumberOfRecords) {
    196     _defaultLogMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
    197   }
    198   //--------------------------------------------------------------------------
    199   // Protected Methods:
    200   //--------------------------------------------------------------------------
    201
    202   /***
    203    * @return The default instance of the <code>LogBrokerMonitor</code>.
    204    */
    205   protected static synchronized LogBrokerMonitor getDefaultInstance() {
    206     if (_defaultLogMonitor == null) {
    207       try {
    208         _defaultLogMonitor =
    209             new LogBrokerMonitor(LogLevel.getLog4JLevels());
    210         _finalizer = new AppenderFinalizer(_defaultLogMonitor);
    211
    212         _defaultLogMonitor.setFrameSize(getDefaultMonitorWidth(),
    213             getDefaultMonitorHeight());
    214         _defaultLogMonitor.setFontSize(12);
    215         _defaultLogMonitor.show();
    216
    217       } catch (SecurityException e) {
    218         _defaultLogMonitor = null;
    219       }
    220     }
    221
    222     return _defaultLogMonitor;
    223   }
    224
    225   /***
    226    * @return the screen width from Toolkit.getScreenSize()
    227    * if possible, otherwise returns 800
    228    * @see java.awt.Toolkit
    229    */
    230   protected static int getScreenWidth() {
    231     try {
    232       return Toolkit.getDefaultToolkit().getScreenSize().width;
    233     } catch (Throwable t) {
    234       return 800;
    235     }
    236   }
    237
    238   /***
    239    * @return the screen height from Toolkit.getScreenSize()
    240    * if possible, otherwise returns 600
    241    * @see java.awt.Toolkit
    242    */
    243   protected static int getScreenHeight() {
    244     try {
    245       return Toolkit.getDefaultToolkit().getScreenSize().height;
    246     } catch (Throwable t) {
    247       return 600;
    248     }
    249   }
    250
    251   protected static int getDefaultMonitorWidth() {
    252     return (3 * getScreenWidth()) / 4;
    253   }
    254
    255   protected static int getDefaultMonitorHeight() {
    256     return (3 * getScreenHeight()) / 4;
    257   }
    258   //--------------------------------------------------------------------------
    259   // Private Methods:
    260   //--------------------------------------------------------------------------
    261
    262
    263   //--------------------------------------------------------------------------
    264   // Nested Top-Level Classes or Interfaces:
    265   //--------------------------------------------------------------------------
    266
    267 }