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  package org.apache.logging.log4j.core.jmx;
    18
    19  import java.io.IOException;
    20  import java.util.List;
    21  import java.util.concurrent.Executor;
    22  import java.util.concurrent.atomic.AtomicLong;
    23
    24  import javax.management.MBeanNotificationInfo;
    25  import javax.management.Notification;
    26  import javax.management.NotificationBroadcasterSupport;
    27  import javax.management.ObjectName;
    28
    29  import org.apache.logging.log4j.Level;
    30  import org.apache.logging.log4j.status.StatusData;
    31  import org.apache.logging.log4j.status.StatusListener;
    32  import org.apache.logging.log4j.status.StatusLogger;
    33
    34  /**
    35   * Implementation of the {@code StatusLoggerAdminMBean} interface.
    36   */
    37  public class StatusLoggerAdmin extends NotificationBroadcasterSupport implements StatusListener, StatusLoggerAdminMBean {
    38
    39      private final AtomicLong sequenceNo = new AtomicLong();
    40      private final ObjectName objectName;
    41      private final String contextName;
    42      private Level level = Level.WARN;
    43
    44      /**
    45       * Constructs a new {@code StatusLoggerAdmin} with the {@code Executor} to
    46       * be used for sending {@code Notification}s asynchronously to listeners.
    47       *
    48       * @param contextName name of the LoggerContext under which to register this
    49       *            StatusLoggerAdmin. Note that the StatusLogger may be
    50       *            registered multiple times, once for each LoggerContext. In web
    51       *            containers, each web application has its own LoggerContext and
    52       *            by associating the StatusLogger with the LoggerContext, all
    53       *            associated MBeans can be unloaded when the web application is
    54       *            undeployed.
    55       * @param executor used to send notifications asynchronously
    56       */
    57      public StatusLoggerAdmin(final String contextName, final Executor executor) {
    58          super(executor, createNotificationInfo());
    59          this.contextName = contextName;
    60          try {
    61              final String mbeanName = String.format(PATTERN, Server.escape(contextName));
    62              objectName = new ObjectName(mbeanName);
    63          } catch (final Exception e) {
    64              throw new IllegalStateException(e);
    65          }
    66          removeListeners(contextName);
    67          StatusLogger.getLogger().registerListener(this);
    68      }
    69
    70      /**
    71       * Add listener to StatusLogger for this context, or replace it if it already exists.
    72       *
    73       * @param ctxName
    74       */
    75      private void removeListeners(final String ctxName) {
    76          final StatusLogger logger = StatusLogger.getLogger();
    77          final Iterable<StatusListener> listeners = logger.getListeners();
    78          // Remove any StatusLoggerAdmin listeners already registered for this context
    79          for (final StatusListener statusListener : listeners) {
    80              if (statusListener instanceof StatusLoggerAdmin) {
    81                  final StatusLoggerAdmin adminListener = (StatusLoggerAdmin) statusListener;
    82                  if (ctxName != null && ctxName.equals(adminListener.contextName)) {
    83                      logger.removeListener(adminListener);
    84                  }
    85              }
    86          }
    87      }
    88
    89      private static MBeanNotificationInfo createNotificationInfo() {
    90          final String[] notifTypes = new String[] {
    91                  NOTIF_TYPE_DATA,
    92                  NOTIF_TYPE_MESSAGE };
    93          final String name = Notification.class.getName();
    94          final String description = "StatusLogger has logged an event";
    95          return new MBeanNotificationInfo(notifTypes, name, description);
    96      }
    97
    98      @Override
    99      public String[] getStatusDataHistory() {
    100         final List<StatusData> data = getStatusData();
    101         final String[] result = new String[data.size()];
    102         for (int i = 0; i < result.length; i++) {
    103             result[i] = data.get(i).getFormattedStatus();
    104         }
    105         return result;
    106     }
    107
    108     @Override
    109     public List<StatusData> getStatusData() {
    110         return StatusLogger.getLogger().getStatusData();
    111     }
    112
    113     @Override
    114     public String getLevel() {
    115         return this.level.name();
    116     }
    117
    118     @Override
    119     public Level getStatusLevel() {
    120         return this.level;
    121     }
    122
    123     @Override
    124     public void setLevel(final String level) {
    125         this.level = Level.toLevel(level, Level.ERROR);
    126     }
    127
    128     @Override
    129     public String getContextName() {
    130         return contextName;
    131     }
    132
    133     /*
    134      * (non-Javadoc)
    135      *
    136      * @see
    137      * org.apache.logging.log4j.status.StatusListener#log(org.apache.logging
    138      * .log4j.status.StatusData)
    139      */
    140     @Override
    141     public void log(final StatusData data) {
    142         final Notification notifMsg = new Notification(NOTIF_TYPE_MESSAGE, getObjectName(), nextSeqNo(), nowMillis(),
    143                 data.getFormattedStatus());
    144         sendNotification(notifMsg);
    145
    146         final Notification notifData = new Notification(NOTIF_TYPE_DATA, getObjectName(), nextSeqNo(), nowMillis());
    147         notifData.setUserData(data);
    148         sendNotification(notifData);
    149     }
    150
    151     /**
    152      * Returns the {@code ObjectName} of this mbean.
    153      *
    154      * @return the {@code ObjectName}
    155      * @see StatusLoggerAdminMBean#PATTERN
    156      */
    157     @Override
    158     public ObjectName getObjectName() {
    159         return objectName;
    160     }
    161
    162     private long nextSeqNo() {
    163         return sequenceNo.getAndIncrement();
    164     }
    165
    166     private long nowMillis() {
    167         return System.currentTimeMillis();
    168     }
    169
    170     @Override
    171     public void close() throws IOException {
    172         // nothing to close here
    173     }
    174 }