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 }