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 */ 017package org.apache.logging.log4j.core.net; 018 019import java.io.BufferedReader; 020import java.io.ByteArrayInputStream; 021import java.io.EOFException; 022import java.io.File; 023import java.io.FileInputStream; 024import java.io.FileNotFoundException; 025import java.io.IOException; 026import java.io.InputStreamReader; 027import java.io.ObjectInputStream; 028import java.io.OptionalDataException; 029import java.net.DatagramPacket; 030import java.net.DatagramSocket; 031import java.net.MalformedURLException; 032import java.net.URI; 033import java.net.URL; 034 035import org.apache.logging.log4j.LogManager; 036import org.apache.logging.log4j.Logger; 037import org.apache.logging.log4j.core.AbstractServer; 038import org.apache.logging.log4j.core.LogEvent; 039import org.apache.logging.log4j.core.config.Configuration; 040import org.apache.logging.log4j.core.config.ConfigurationFactory; 041import org.apache.logging.log4j.core.config.XMLConfiguration; 042import org.apache.logging.log4j.core.config.XMLConfigurationFactory; 043 044/** 045 * Listens for events over a socket connection. 046 */ 047public class UDPSocketServer extends AbstractServer implements Runnable { 048 049 private final Logger logger; 050 051 private static final int MAX_PORT = 65534; 052 053 private volatile boolean isActive = true; 054 055 private final DatagramSocket server; 056 057 // max size so we only have to deal with one packet 058 private final int maxBufferSize = 1024 * 65 + 1024; 059 060 /** 061 * Constructor. 062 * 063 * @param port 064 * to listen on. 065 * @throws IOException 066 * If an error occurs. 067 */ 068 public UDPSocketServer(final int port) throws IOException { 069 this.server = new DatagramSocket(port); 070 this.logger = LogManager.getLogger(this.getClass().getName() + '.' + port); 071 } 072 073 /** 074 * Main startup for the server. 075 * 076 * @param args 077 * The command line arguments. 078 * @throws Exception 079 * if an error occurs. 080 */ 081 public static void main(final String[] args) throws Exception { 082 if (args.length < 1 || args.length > 2) { 083 System.err.println("Incorrect number of arguments"); 084 printUsage(); 085 return; 086 } 087 final int port = Integer.parseInt(args[0]); 088 if (port <= 0 || port >= MAX_PORT) { 089 System.err.println("Invalid port number"); 090 printUsage(); 091 return; 092 } 093 if (args.length == 2 && args[1].length() > 0) { 094 ConfigurationFactory.setConfigurationFactory(new ServerConfigurationFactory(args[1])); 095 } 096 final UDPSocketServer sserver = new UDPSocketServer(port); 097 final Thread server = new Thread(sserver); 098 server.start(); 099 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}