/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.log4j.receivers.net; import org.apache.log4j.Logger; import org.apache.log4j.component.helpers.Constants; import org.apache.log4j.component.plugins.Pauseable; import org.apache.log4j.component.plugins.Receiver; import org.apache.log4j.component.spi.ComponentBase; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.LoggingEvent; import java.io.BufferedInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; // Contributors: Moses Hohman <mmhohman@rainbow.uchicago.edu> /** Read {@link LoggingEvent} objects sent from a remote client using Sockets (TCP). These logging events are logged according to local policy, as if they were generated locally. <p>For example, the socket node might decide to log events to a local file and also resent them to a second socket node. Implementation lifted from org.apache.log4j.net.SocketNode in log4j 1.3 and renamed to prevent collision with log4j 1.2 implementation. @author Ceki Gülcü @author Paul Smith (psmith@apache.org) */ public class SocketNode13 extends ComponentBase implements Runnable, Pauseable { /** * Paused state. */ private boolean paused; /** * Closed state. */ private boolean closed; /** * Socket. */ private Socket socket; /** * Receiver. */ private Receiver receiver; /** * List of listeners. */ private List listenerList = Collections.synchronizedList(new ArrayList()); /** Constructor for socket and logger repository. @param s socket @param hierarchy logger repository */ public SocketNode13(final Socket s, final LoggerRepository hierarchy) { super(); this.socket = s; this.repository = hierarchy; } /** Constructor for socket and receiver. @param s socket @param r receiver */ public SocketNode13(final Socket s, final Receiver r) { super(); this.socket = s; this.receiver = r; } /** * Set the event listener on this node. * * @deprecated Now supports mutliple listeners, this method * simply invokes the removeSocketNodeEventListener() to remove * the listener, and then readds it. * @param l listener */ public void setListener(final SocketNodeEventListener l) { removeSocketNodeEventListener(l); addSocketNodeEventListener(l); } /** * Adds the listener to the list of listeners to be notified of the * respective event. * @param listener the listener to add to the list */ public void addSocketNodeEventListener( final SocketNodeEventListener listener) { listenerList.add(listener); } /** * Removes the registered Listener from this instances list of * listeners. If the listener has not been registered, then invoking * this method has no effect. * * @param listener the SocketNodeEventListener to remove */ public void removeSocketNodeEventListener( final SocketNodeEventListener listener) { listenerList.remove(listener); } /** * Deserialize events from socket until interrupted. */ public void run() { LoggingEvent event; Logger remoteLogger; Exception listenerException = null; ObjectInputStream ois = null; try { ois = new ObjectInputStream( new BufferedInputStream(socket.getInputStream())); } catch (Exception e) { ois = null; listenerException = e; getLogger().error("Exception opening ObjectInputStream to " + socket, e); } if (ois != null) { String hostName = socket.getInetAddress().getHostName(); String remoteInfo = hostName + ":" + socket.getPort(); /** * notify the listener that the socket has been * opened and this SocketNode is ready and waiting */ fireSocketOpened(remoteInfo); try { while (!isClosed()) { // read an event from the wire event = (LoggingEvent) ois.readObject(); event.setProperty(Constants.HOSTNAME_KEY, hostName); // store the known remote info in an event property event.setProperty("log4j.remoteSourceInfo", remoteInfo); // if configured with a receiver, tell it to post the event if (!isPaused() && !isClosed()) { if ((receiver != null)) { receiver.doPost(event); // else post it via the hierarchy } else { // get a logger from the hierarchy. The name of the logger // is taken to be the name contained in the event. remoteLogger = repository.getLogger(event.getLoggerName()); //event.logger = remoteLogger; // apply the logger-level filter if (event .getLevel() .isGreaterOrEqual(remoteLogger.getEffectiveLevel())) { // finally log the event as if was generated locally remoteLogger.callAppenders(event); } } } else { //we simply discard this event. } } } catch (java.io.EOFException e) { getLogger().info("Caught java.io.EOFException closing connection."); listenerException = e; } catch (java.net.SocketException e) { getLogger().info("Caught java.net.SocketException closing connection."); listenerException = e; } catch (IOException e) { getLogger().info("Caught java.io.IOException: " + e); getLogger().info("Closing connection."); listenerException = e; } catch (Exception e) { getLogger().error("Unexpected exception. Closing connection.", e); listenerException = e; } } // close the socket try { if (ois != null) { ois.close(); } } catch (Exception e) { //getLogger().info("Could not close connection.", e); } // send event to listener, if configured if (listenerList.size() > 0 && !isClosed()) { fireSocketClosedEvent(listenerException); } } /** * Notifies all registered listeners regarding the closing of the Socket. * @param listenerException listener exception */ private void fireSocketClosedEvent(final Exception listenerException) { synchronized (listenerList) { for (Iterator iter = listenerList.iterator(); iter.hasNext();) { SocketNodeEventListener snel = (SocketNodeEventListener) iter.next(); if (snel != null) { snel.socketClosedEvent(listenerException); } } } } /** * Notifies all registered listeners regarding the opening of a Socket. * @param remoteInfo remote info */ private void fireSocketOpened(final String remoteInfo) { synchronized (listenerList) { for (Iterator iter = listenerList.iterator(); iter.hasNext();) { SocketNodeEventListener snel = (SocketNodeEventListener) iter.next(); if (snel != null) { snel.socketOpened(remoteInfo); } } } } /** * Sets if node is paused. * @param b new value */ public void setPaused(final boolean b) { this.paused = b; } /** * Get if node is paused. * @return true if pause. */ public boolean isPaused() { return this.paused; } /** * Close the node and underlying socket */ public void close() throws IOException { getLogger().debug("closing socket"); this.closed = true; socket.close(); fireSocketClosedEvent(null); } /** * Get if node is closed. * @return true if closed. */ public boolean isClosed() { return this.closed; } }