KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log4j > net > TelnetAppender


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.log4j.net;
18
19 import java.io.*;
20 import java.net.*;
21 import java.util.*;
22 import org.apache.log4j.Layout;
23 import org.apache.log4j.spi.LoggingEvent;
24 import org.apache.log4j.AppenderSkeleton;
25 import org.apache.log4j.helpers.LogLog;
26
27 /**
28   <p>The TelnetAppender is a log4j appender that specializes in
29   writing to a read-only socket. The output is provided in a
30   telnet-friendly way so that a log can be monitored over TCP/IP.
31   Clients using telnet connect to the socket and receive log data.
32   This is handy for remote monitoring, especially when monitoring a
33   servlet.
34
35   <p>Here is a list of the available configuration options:
36
37   <table border=1>
38    <tr>
39    <th>Name</th>
40    <th>Requirement</th>
41    <th>Description</th>
42    <th>Sample Value</th>
43    </tr>
44
45    <tr>
46    <td>Port</td>
47    <td>optional</td>
48    <td>This parameter determines the port to use for announcing log events. The default port is 23 (telnet).</td>
49    <td>5875</td>
50    </table>
51
52    @author <a HREF="mailto:jay@v-wave.com">Jay Funnell</a>
53 */

54
55 public class TelnetAppender extends AppenderSkeleton {
56
57   private SocketHandler sh;
58   private int port = 23;
59
60   /**
61       This appender requires a layout to format the text to the
62       attached client(s). */

63   public boolean requiresLayout() {
64     return true;
65   }
66
67   /** all of the options have been set, create the socket handler and
68       wait for connections. */

69   public void activateOptions() {
70     try {
71       sh = new SocketHandler(port);
72       sh.start();
73     }
74     catch(Exception JavaDoc e) {
75       e.printStackTrace();
76     }
77   }
78
79   public
80   int getPort() {
81     return port;
82   }
83
84   public
85   void setPort(int port) {
86     this.port = port;
87   }
88
89
90   /** shuts down the appender. */
91   public void close() {
92     sh.finalize();
93   }
94
95   /** Handles a log event. For this appender, that means writing the
96     message to each connected client. */

97   protected void append(LoggingEvent event) {
98     sh.send(this.layout.format(event));
99     if(layout.ignoresThrowable()) {
100       String JavaDoc[] s = event.getThrowableStrRep();
101       if (s != null) {
102     int len = s.length;
103     for(int i = 0; i < len; i++) {
104       sh.send(s[i]);
105       sh.send(Layout.LINE_SEP);
106     }
107       }
108     }
109   }
110
111   //---------------------------------------------------------- SocketHandler:
112

113   /** The SocketHandler class is used to accept connections from
114       clients. It is threaded so that clients can connect/disconnect
115       asynchronously. */

116   protected class SocketHandler extends Thread JavaDoc {
117
118     private boolean done = false;
119     private Vector writers = new Vector();
120     private Vector connections = new Vector();
121     private ServerSocket serverSocket;
122     private int MAX_CONNECTIONS = 20;
123
124     /** make sure we close all network connections when this handler is destroyed. */
125     public void finalize() {
126       for(Enumeration e = connections.elements();e.hasMoreElements();) {
127         try {
128           ((Socket)e.nextElement()).close();
129         } catch(Exception JavaDoc ex) {
130         }
131       }
132       try {
133         serverSocket.close();
134       } catch(Exception JavaDoc ex) {
135       }
136       done = true;
137     }
138
139     /** sends a message to each of the clients in telnet-friendly output. */
140     public void send(String JavaDoc message) {
141       Enumeration ce = connections.elements();
142       for(Enumeration e = writers.elements();e.hasMoreElements();) {
143         Socket sock = (Socket)ce.nextElement();
144         PrintWriter writer = (PrintWriter)e.nextElement();
145         writer.print(message);
146         if(writer.checkError()) {
147           // The client has closed the connection, remove it from our list:
148
connections.remove(sock);
149           writers.remove(writer);
150         }
151       }
152     }
153
154     /**
155     Continually accepts client connections. Client connections
156         are refused when MAX_CONNECTIONS is reached.
157     */

158     public void run() {
159       while(!done) {
160         try {
161           Socket newClient = serverSocket.accept();
162           PrintWriter pw = new PrintWriter(newClient.getOutputStream());
163           if(connections.size() < MAX_CONNECTIONS) {
164             connections.addElement(newClient);
165             writers.addElement(pw);
166             pw.print("TelnetAppender v1.0 (" + connections.size()
167              + " active connections)\r\n\r\n");
168             pw.flush();
169           } else {
170             pw.print("Too many connections.\r\n");
171             pw.flush();
172             newClient.close();
173           }
174         } catch(Exception JavaDoc e) {
175           LogLog.error("Encountered error while in SocketHandler loop.", e);
176         }
177       }
178     }
179
180     public SocketHandler(int port) throws IOException {
181       serverSocket = new ServerSocket(port);
182     }
183
184   }
185 }
186
Popular Tags