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.varia;
    19
    20  import java.io.DataInputStream;
    21  import java.io.DataOutputStream;
    22  import java.io.IOException;
    23  import java.io.InterruptedIOException;
    24  import java.net.ServerSocket;
    25  import java.net.Socket;
    26
    27  import org.apache.log4j.RollingFileAppender;
    28  import org.apache.log4j.helpers.LogLog;
    29
    30  /**
    31     This appender listens on a socket on the port specified by the
    32     <b>Port</b> property for a "RollOver" message. When such a message
    33     is received, the underlying log file is rolled over and an
    34     acknowledgment message is sent back to the process initiating the
    35     roll over.
    36
    37     <p>This method of triggering roll over has the advantage of being
    38     operating system independent, fast and reliable.
    39
    40     <p>A simple application {@link Roller} is provided to initiate the
    41     roll over.
    42
    43     <p>Note that the initiator is not authenticated. Anyone can trigger
    44     a rollover. In production environments, it is recommended that you
    45     add some form of protection to prevent undesired rollovers.
    46
    47
    48     @author Ceki G&uuml;lc&uuml;
    49     @since version 0.9.0 */
    50  public class ExternallyRolledFileAppender extends RollingFileAppender {
    51
    52    /**
    53       The string constant sent to initiate a roll over.   Current value of
    54       this string constant is <b>RollOver</b>.
    55    */
    56    static final public String ROLL_OVER = "RollOver";
    57
    58    /**
    59       The string constant sent to acknowledge a roll over.   Current value of
    60        this string constant is <b>OK</b>.
    61    */
    62    static final public String OK = "OK";
    63
    64    int port = 0;
    65    HUP hup;
    66
    67    /**
    68       The default constructor does nothing but calls its super-class
    69       constructor.  */
    70    public
    71    ExternallyRolledFileAppender() {
    72    }
    73
    74    /**
    75       The <b>Port</b> [roperty is used for setting the port for
    76       listening to external roll over messages.
    77    */
    78    public
    79    void setPort(int port) {
    80      this.port = port;
    81    }
    82
    83    /**
    84       Returns value of the <b>Port</b> option.
    85     */
    86    public
    87    int getPort() {
    88      return port;
    89    }
    90
    91    /**
    92       Start listening on the port specified by a preceding call to
    93       {@link #setPort}.  */
    94    public
    95    void activateOptions() {
    96      super.activateOptions();
    97      if(port != 0) {
    98        if(hup != null) {
    99  	hup.interrupt();
    100       }
    101       hup = new HUP(this, port);
    102       hup.setDaemon(true);
    103       hup.start();
    104     }
    105   }
    106 }
    107
    108
    109 class HUP extends Thread {
    110
    111   int port;
    112   ExternallyRolledFileAppender er;
    113
    114   HUP(ExternallyRolledFileAppender er, int port) {
    115     this.er = er;
    116     this.port = port;
    117   }
    118
    119   public
    120   void run() {
    121     while(!isInterrupted()) {
    122       try {
    123 	ServerSocket serverSocket = new ServerSocket(port);
    124 	while(true) {
    125 	  Socket socket = serverSocket.accept();
    126 	  LogLog.debug("Connected to client at " + socket.getInetAddress());
    127 	  new Thread(new HUPNode(socket, er), "ExternallyRolledFileAppender-HUP").start();
    128 	}
    129       } catch(InterruptedIOException e) {
    130         Thread.currentThread().interrupt();
    131 	    e.printStackTrace();
    132       } catch(IOException e) {
    133 	    e.printStackTrace();
    134       } catch(RuntimeException e) {
    135 	    e.printStackTrace();
    136       }
    137     }
    138   }
    139 }
    140
    141 class HUPNode implements Runnable {
    142
    143   Socket socket;
    144   DataInputStream dis;
    145   DataOutputStream dos;
    146   ExternallyRolledFileAppender er;
    147
    148   public
    149   HUPNode(Socket socket, ExternallyRolledFileAppender er) {
    150     this.socket = socket;
    151     this.er = er;
    152     try {
    153       dis = new DataInputStream(socket.getInputStream());
    154       dos = new DataOutputStream(socket.getOutputStream());
    155     } catch(InterruptedIOException e) {
    156       Thread.currentThread().interrupt();
    157       e.printStackTrace();
    158     } catch(IOException e) {
    159       e.printStackTrace();
    160     } catch(RuntimeException e) {
    161       e.printStackTrace();
    162     }
    163   }
    164
    165   public void run() {
    166     try {
    167       String line = dis.readUTF();
    168       LogLog.debug("Got external roll over signal.");
    169       if(ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
    170 	synchronized(er) {
    171 	  er.rollOver();
    172 	}
    173 	dos.writeUTF(ExternallyRolledFileAppender.OK);
    174       }
    175       else {
    176 	dos.writeUTF("Expecting [RollOver] string.");
    177       }
    178       dos.close();
    179     } catch(InterruptedIOException e) {
    180       Thread.currentThread().interrupt();
    181       LogLog.error("Unexpected exception. Exiting HUPNode.", e);
    182     } catch(IOException e) {
    183       LogLog.error("Unexpected exception. Exiting HUPNode.", e);
    184     } catch(RuntimeException e) {
    185       LogLog.error("Unexpected exception. Exiting HUPNode.", e);
    186     }
    187   }
    188 }
    189