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