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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.log4j.net;
21 import java.net.InetAddress;
22 import java.net.ServerSocket;
23 import java.net.Socket;
24 import java.util.Hashtable;
26 import org.apache.log4j.Hierarchy;
27 import org.apache.log4j.Level;
28 import org.apache.log4j.LogManager;
29 import org.apache.log4j.Logger;
30 import org.apache.log4j.PropertyConfigurator;
31 import org.apache.log4j.spi.LoggerRepository;
32 import org.apache.log4j.spi.RootLogger;
36 A {@link SocketNode} based server that uses a different hierarchy
40 <b>Usage:</b> java org.apache.log4j.net.SocketServer port configFile configDir
42 where <b>port</b> is a part number where the server listens,
43 <b>configFile</b> is a configuration file fed to the {@link PropertyConfigurator} and
44 <b>configDir</b> is a path to a directory containing configuration files, possibly one for each client host.
47 <p>The <code>configFile</code> is used to configure the log4j
48 default hierarchy that the <code>SocketServer</code> will use to
49 report on its actions.
51 <p>When a new connection is opened from a previously unknown
52 host, say <code>foo.bar.net</code>, then the
53 <code>SocketServer</code> will search for a configuration file
54 called <code>foo.bar.net.lcf</code> under the directory
55 <code>configDir</code> that was passed as the third argument. If
56 the file can be found, then a new hierarchy is instantiated and
57 configured using the configuration file
58 <code>foo.bar.net.lcf</code>. If and when the host
59 <code>foo.bar.net</code> opens another connection to the server,
60 then the previously configured hierarchy is used.
62 <p>In case there is no file called <code>foo.bar.net.lcf</code>
63 under the directory <code>configDir</code>, then the
64 <em>generic</em> hierarchy is used. The generic hierarchy is
65 configured using a configuration file called
66 <code>generic.lcf</code> under the <code>configDir</code>
67 directory. If no such file exists, then the generic hierarchy will be
68 identical to the log4j default hierarchy.
70 <p>Having different client hosts log using different hierarchies
71 ensures the total independence of the clients with respect to
72 their logging settings.
74 <p>Currently, the hierarchy that will be used for a given request
75 depends on the IP address of the client host. For example, two
76 separate applications running on the same host and logging to the
77 same server will share the same hierarchy. This is perfectly safe
78 except that it might not provide the right amount of independence
79 between applications. The <code>SocketServer</code> is intended
80 as an example to be enhanced in order to implement more elaborate
84 @author Ceki Gülcü
88 public class SocketServer {
90 static String GENERIC = "generic";
91 static String CONFIG_FILE_EXT = ".lcf";
93 static Logger cat = Logger.getLogger(SocketServer.class);
94 static SocketServer server;
97 // key=inetAddress, value=hierarchy
98 Hashtable hierarchyMap;
99 LoggerRepository genericHierarchy;
104 void main(String argv[]) {
105 if(argv.length == 3) {
106 init(argv[0], argv[1], argv[2]);
108 usage("Wrong number of arguments.");
112 cat.info("Listening on port " + port);
113 ServerSocket serverSocket = new ServerSocket(port);
115 cat.info("Waiting to accept a new client.");
116 Socket socket = serverSocket.accept();
117 InetAddress inetAddress = socket.getInetAddress();
118 cat.info("Connected to client at " + inetAddress);
120 LoggerRepository h = (LoggerRepository) server.hierarchyMap.get(inetAddress);
122 h = server.configureHierarchy(inetAddress);
125 cat.info("Starting new socket node.");
126 new Thread(new SocketNode(socket, h)).start();
136 void usage(String msg) {
137 System.err.println(msg);
139 "Usage: java " +SocketServer.class.getName() + " port configFile directory");
144 void init(String portStr, String configFile, String dirStr) {
146 port = Integer.parseInt(portStr);
148 catch(java.lang.NumberFormatException e) {
150 usage("Could not interpret port number ["+ portStr +"].");
153 PropertyConfigurator.configure(configFile);
155 File dir = new File(dirStr);
156 if(!dir.isDirectory()) {
157 usage("["+dirStr+"] is not a directory.");
159 server = new SocketServer(dir);
164 SocketServer(File directory) {
165 this.dir = directory;
166 hierarchyMap = new Hashtable(11);
169 // This method assumes that there is no hiearchy for inetAddress
170 // yet. It will configure one and return it.
171 LoggerRepository configureHierarchy(InetAddress inetAddress) {
172 cat.info("Locating configuration file for "+inetAddress);
173 // We assume that the toSting method of InetAddress returns is in
174 // the format hostname/d1.d2.d3.d4 e.g. torino/192.168.1.1
175 String s = inetAddress.toString();
176 int i = s.indexOf("/");
178 cat.warn("Could not parse the inetAddress ["+inetAddress+
179 "]. Using default hierarchy.");
180 return genericHierarchy();
182 String key = s.substring(0, i);
184 File configFile = new File(dir, key+CONFIG_FILE_EXT);
185 if(configFile.exists()) {
186 Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
187 hierarchyMap.put(inetAddress, h);
189 new PropertyConfigurator().doConfigure(configFile.getAbsolutePath(), h);
193 cat.warn("Could not find config file ["+configFile+"].");
194 return genericHierarchy();
199 LoggerRepository genericHierarchy() {
200 if(genericHierarchy == null) {
201 File f = new File(dir, GENERIC+CONFIG_FILE_EXT);
203 genericHierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
204 new PropertyConfigurator().doConfigure(f.getAbsolutePath(), genericHierarchy);
206 cat.warn("Could not find config file ["+f+
207 "]. Will use the default hierarchy.");
208 genericHierarchy = LogManager.getLoggerRepository();
211 return genericHierarchy;