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