001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.net; 018 019 import java.io.BufferedReader; 020 import java.io.ByteArrayInputStream; 021 import java.io.EOFException; 022 import java.io.File; 023 import java.io.FileInputStream; 024 import java.io.FileNotFoundException; 025 import java.io.IOException; 026 import java.io.InputStreamReader; 027 import java.io.ObjectInputStream; 028 import java.io.OptionalDataException; 029 import java.net.DatagramPacket; 030 import java.net.DatagramSocket; 031 import java.net.MalformedURLException; 032 import java.net.URI; 033 import java.net.URL; 034 import java.util.Map; 035 import java.util.concurrent.ConcurrentHashMap; 036 import java.util.concurrent.ConcurrentMap; 037 038 import org.apache.logging.log4j.LogManager; 039 import org.apache.logging.log4j.Logger; 040 import org.apache.logging.log4j.core.AbstractServer; 041 import org.apache.logging.log4j.core.LogEvent; 042 import org.apache.logging.log4j.core.config.Configuration; 043 import org.apache.logging.log4j.core.config.ConfigurationFactory; 044 import org.apache.logging.log4j.core.config.XMLConfiguration; 045 import org.apache.logging.log4j.core.config.XMLConfigurationFactory; 046 047 /** 048 * Listens for events over a socket connection. 049 */ 050 public class UDPSocketServer extends AbstractServer implements Runnable { 051 052 private static Logger logger; 053 054 private static final int MAX_PORT = 65534; 055 056 private volatile boolean isActive = true; 057 058 private final DatagramSocket server; 059 060 // max size so we only have to deal with one packet 061 private int maxBufferSize = 1024 * 65 + 1024; 062 063 /** 064 * Constructor. 065 * 066 * @param port 067 * to listen on. 068 * @throws IOException 069 * If an error occurs. 070 */ 071 public UDPSocketServer(final int port) throws IOException { 072 server = new DatagramSocket(port); 073 if (logger == null) { 074 logger = LogManager.getLogger(this); 075 // logger = LogManager.getLogger(getClass().getName() + '.' + port); 076 } 077 } 078 079 /** 080 * Main startup for the server. 081 * 082 * @param args 083 * The command line arguments. 084 * @throws Exception 085 * if an error occurs. 086 */ 087 public static void main(final String[] args) throws Exception { 088 if (args.length < 1 || args.length > 2) { 089 System.err.println("Incorrect number of arguments"); 090 printUsage(); 091 return; 092 } 093 final int port = Integer.parseInt(args[0]); 094 if (port <= 0 || port >= MAX_PORT) { 095 System.err.println("Invalid port number"); 096 printUsage(); 097 return; 098 } 099 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 }