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