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  package org.apache.logging.log4j.core.net;
18  
19  import java.io.BufferedReader;
20  import java.io.ByteArrayInputStream;
21  import java.io.EOFException;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.IOException;
26  import java.io.InputStreamReader;
27  import java.io.ObjectInputStream;
28  import java.io.OptionalDataException;
29  import java.net.DatagramPacket;
30  import java.net.DatagramSocket;
31  import java.net.MalformedURLException;
32  import java.net.URI;
33  import java.net.URL;
34  import java.util.Map;
35  import java.util.concurrent.ConcurrentHashMap;
36  import java.util.concurrent.ConcurrentMap;
37  
38  import org.apache.logging.log4j.LogManager;
39  import org.apache.logging.log4j.Logger;
40  import org.apache.logging.log4j.core.AbstractServer;
41  import org.apache.logging.log4j.core.LogEvent;
42  import org.apache.logging.log4j.core.config.Configuration;
43  import org.apache.logging.log4j.core.config.ConfigurationFactory;
44  import org.apache.logging.log4j.core.config.XMLConfiguration;
45  import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
46  
47  /**
48   * Listens for events over a socket connection.
49   */
50  public class UDPSocketServer extends AbstractServer implements Runnable {
51  
52      private static Logger logger;
53  
54      private static final int MAX_PORT = 65534;
55  
56      private volatile boolean isActive = true;
57  
58      private final DatagramSocket server;
59  
60      // max size so we only have to deal with one packet
61      private int maxBufferSize = 1024 * 65 + 1024;
62  
63      /**
64       * Constructor.
65       *
66       * @param port
67       *            to listen on.
68       * @throws IOException
69       *             If an error occurs.
70       */
71      public UDPSocketServer(final int port) throws IOException {
72          server = new DatagramSocket(port);
73          if (logger == null) {
74              logger = LogManager.getLogger(this);
75              // logger = LogManager.getLogger(getClass().getName() + '.' + port);
76          }
77      }
78  
79      /**
80       * Main startup for the server.
81       *
82       * @param args
83       *            The command line arguments.
84       * @throws Exception
85       *             if an error occurs.
86       */
87      public static void main(final String[] args) throws Exception {
88          if (args.length < 1 || args.length > 2) {
89              System.err.println("Incorrect number of arguments");
90              printUsage();
91              return;
92          }
93          final int port = Integer.parseInt(args[0]);
94          if (port <= 0 || port >= MAX_PORT) {
95              System.err.println("Invalid port number");
96              printUsage();
97              return;
98          }
99          if (args.length == 2 && args[1].length() > 0) {
100             ConfigurationFactory.setConfigurationFactory(new ServerConfigurationFactory(args[1]));
101         }
102         logger = LogManager.getLogger(UDPSocketServer.class.getName());
103         final UDPSocketServer sserver = new UDPSocketServer(port);
104         final Thread server = new Thread(sserver);
105         server.start();
106         final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
107         while (true) {
108             final String line = reader.readLine();
109             if (line.equalsIgnoreCase("Quit") || line.equalsIgnoreCase("Stop") || line.equalsIgnoreCase("Exit")) {
110                 sserver.shutdown();
111                 server.join();
112                 break;
113             }
114         }
115     }
116 
117     private static void printUsage() {
118         System.out.println("Usage: ServerSocket port configFilePath");
119     }
120 
121     /**
122      * Shutdown the server.
123      */
124     public void shutdown() {
125         this.isActive = false;
126         Thread.currentThread().interrupt();
127     }
128 
129     /**
130      * Accept incoming events and processes them.
131      */
132     @Override
133     public void run() {
134         while (isActive) {
135             try {
136                 byte[] buf = new byte[maxBufferSize];
137                 DatagramPacket packet = new DatagramPacket(buf, buf.length);
138                 server.receive(packet);
139                 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength()));
140                 final LogEvent event = (LogEvent) ois.readObject();
141                 if (event != null) {
142                     log(event);
143                 }
144             } catch (final OptionalDataException opt) {
145                 logger.error("OptionalDataException eof=" + opt.eof + " length=" + opt.length, opt);
146             } catch (final ClassNotFoundException cnfe) {
147                 logger.error("Unable to locate LogEvent class", cnfe);
148             } catch (final EOFException eofe) {
149                 logger.info("EOF encountered");
150             } catch (final IOException ioe) {
151                 logger.error("Exception encountered on accept. Ignoring. Stack Trace :", ioe);
152             }
153         }
154     }
155 
156     /**
157      * Factory that creates a Configuration for the server.
158      */
159     private static class ServerConfigurationFactory extends XMLConfigurationFactory {
160 
161         private final String path;
162 
163         public ServerConfigurationFactory(final String path) {
164             this.path = path;
165         }
166 
167         @Override
168         public Configuration getConfiguration(final String name, final URI configLocation) {
169             if (path != null && path.length() > 0) {
170                 File file = null;
171                 ConfigurationSource source = null;
172                 try {
173                     file = new File(path);
174                     final FileInputStream is = new FileInputStream(file);
175                     source = new ConfigurationSource(is, file);
176                 } catch (final FileNotFoundException ex) {
177                     // Ignore this error
178                 }
179                 if (source == null) {
180                     try {
181                         final URL url = new URL(path);
182                         source = new ConfigurationSource(url.openStream(), path);
183                     } catch (final MalformedURLException mue) {
184                         // Ignore this error
185                     } catch (final IOException ioe) {
186                         // Ignore this error
187                     }
188                 }
189 
190                 try {
191                     if (source != null) {
192                         return new XMLConfiguration(source);
193                     }
194                 } catch (final Exception ex) {
195                     // Ignore this error.
196                 }
197                 System.err.println("Unable to process configuration at " + path + ", using default.");
198             }
199             return super.getConfiguration(name, configLocation);
200         }
201     }
202 }