1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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ülcü
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