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.net;
    19
    20  import org.apache.log4j.Logger;
    21  import org.apache.log4j.helpers.Constants;
    22  import org.apache.log4j.plugins.Receiver;
    23  import org.apache.log4j.spi.ComponentBase;
    24  import org.apache.log4j.spi.Decoder;
    25  import org.apache.log4j.spi.LoggerRepository;
    26  import org.apache.log4j.spi.LoggingEvent;
    27
    28  import java.io.IOException;
    29  import java.io.InputStream;
    30  import java.net.Socket;
    31  import java.util.List;
    32
    33
    34  /**
    35   * Read {@link LoggingEvent} objects sent from a remote client using XML over
    36   * Sockets (TCP). These logging events are logged according to local
    37   * policy, as if they were generated locally.
    38   * <p>
    39   * <p>For example, the socket node might decide to log events to a
    40   * local file and also resent them to a second socket node.
    41   *
    42   * @author Scott Deboy &lt;sdeboy@apache.org&gt;;
    43   * @since 0.8.4
    44   */
    45  public class XMLSocketNode extends ComponentBase implements Runnable {
    46      Socket socket;
    47      Receiver receiver;
    48      Decoder decoder;
    49      SocketNodeEventListener listener;
    50
    51      /**
    52       * Constructor for socket and logger repository.
    53       */
    54      public XMLSocketNode(
    55          String decoder, Socket socket, LoggerRepository hierarchy) {
    56          this.repository = hierarchy;
    57          try {
    58              Class c = Class.forName(decoder);
    59              Object o = c.newInstance();
    60
    61              if (o instanceof Decoder) {
    62                  this.decoder = (Decoder) o;
    63              }
    64          } catch (ClassNotFoundException cnfe) {
    65              getLogger().warn("Unable to find decoder", cnfe);
    66          } catch (IllegalAccessException | InstantiationException iae) {
    67              getLogger().warn("Unable to construct decoder", iae);
    68          }
    69
    70          this.socket = socket;
    71      }
    72
    73      /**
    74       * Constructor for socket and reciever.
    75       */
    76      public XMLSocketNode(String decoder, Socket socket, Receiver receiver) {
    77          try {
    78              Class c = Class.forName(decoder);
    79              Object o = c.newInstance();
    80
    81              if (o instanceof Decoder) {
    82                  this.decoder = (Decoder) o;
    83              }
    84          } catch (ClassNotFoundException cnfe) {
    85              getLogger().warn("Unable to find decoder", cnfe);
    86          } catch (IllegalAccessException | InstantiationException iae) {
    87              getLogger().warn("Unable to construct decoder", iae);
    88          }
    89
    90          this.socket = socket;
    91          this.receiver = receiver;
    92      }
    93
    94      /**
    95       * Set the event listener on this node.
    96       */
    97      public void setListener(SocketNodeEventListener _listener) {
    98          listener = _listener;
    99      }
    100
    101     public void run() {
    102         Logger remoteLogger;
    103         Exception listenerException = null;
    104         InputStream is;
    105
    106         if ((this.receiver == null) || (this.decoder == null)) {
    107             listenerException =
    108                 new Exception(
    109                     "No receiver or decoder provided.  Cannot process xml socket events");
    110             getLogger().error(
    111                 "Exception constructing XML Socket Receiver", listenerException);
    112         }
    113
    114         try {
    115             is = socket.getInputStream();
    116         } catch (Exception e) {
    117             is = null;
    118             listenerException = e;
    119             getLogger().error("Exception opening InputStream to " + socket, e);
    120         }
    121
    122         if (is != null) {
    123             String hostName = socket.getInetAddress().getHostName();
    124             String remoteInfo = hostName + ":" + socket.getPort();
    125
    126             try {
    127                 //read data from the socket
    128                 //it's up to the individual decoder to handle incomplete event data
    129                 while (true) {
    130                     byte[] b = new byte[1024];
    131                     int length = is.read(b);
    132                     if (length == -1) {
    133                         getLogger().info(
    134                             "no bytes read from stream - closing connection.");
    135                         break;
    136                     }
    137                     List<LoggingEvent> v = decoder.decodeEvents(new String(b, 0, length));
    138
    139                     if (v != null) {
    140
    141                         for (Object aV : v) {
    142                             LoggingEvent e = (LoggingEvent) aV;
    143                             e.setProperty(Constants.HOSTNAME_KEY, hostName);
    144
    145                             // store the known remote info in an event property
    146                             e.setProperty("log4j.remoteSourceInfo", remoteInfo);
    147
    148                             // if configured with a receiver, tell it to post the event
    149                             if (receiver != null) {
    150                                 receiver.doPost(e);
    151
    152                                 // else post it via the hierarchy
    153                             } else {
    154                                 // get a logger from the hierarchy. The name of the logger
    155                                 // is taken to be the name contained in the event.
    156                                 remoteLogger = repository.getLogger(e.getLoggerName());
    157
    158                                 //event.logger = remoteLogger;
    159                                 // apply the logger-level filter
    160                                 if (
    161                                     e.getLevel().isGreaterOrEqual(
    162                                         remoteLogger.getEffectiveLevel())) {
    163                                     // finally log the event as if was generated locally
    164                                     remoteLogger.callAppenders(e);
    165                                 }
    166                             }
    167                         }
    168                     }
    169                 }
    170             } catch (java.io.EOFException e) {
    171                 getLogger().info("Caught java.io.EOFException closing connection.");
    172                 listenerException = e;
    173             } catch (java.net.SocketException e) {
    174                 getLogger().info(
    175                     "Caught java.net.SocketException closing connection.");
    176                 listenerException = e;
    177             } catch (IOException e) {
    178                 getLogger().info("Caught java.io.IOException: " + e);
    179                 getLogger().info("Closing connection.");
    180                 listenerException = e;
    181             } catch (Exception e) {
    182                 getLogger().error("Unexpected exception. Closing connection.", e);
    183                 listenerException = e;
    184             }
    185         }
    186
    187         // close the socket
    188         try {
    189             if (is != null) {
    190                 is.close();
    191             }
    192         } catch (Exception e) {
    193             //logger.info("Could not close connection.", e);
    194         }
    195
    196         // send event to listener, if configured
    197         if (listener != null) {
    198             listener.socketClosedEvent(listenerException);
    199         }
    200     }
    201 }