You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2017/04/10 14:11:43 UTC
[11/14] logging-log4j2 git commit: Merge branch 'master' into
LOG4J2-1851
Merge branch 'master' into LOG4J2-1851
# Conflicts:
# src/changes/changes.xml
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/394c30f5
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/394c30f5
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/394c30f5
Branch: refs/heads/master
Commit: 394c30f594c9eac570a43313bf44be4bc60cded9
Parents: 6fd6dfc 1475bd9
Author: Mikael St�ldal <mi...@magine.com>
Authored: Mon Apr 10 10:59:27 2017 +0200
Committer: Mikael St�ldal <mi...@magine.com>
Committed: Mon Apr 10 10:59:27 2017 +0200
----------------------------------------------------------------------
BUILDING.md | 2 +-
README.md | 2 +
RELEASE-NOTES.md | 74 ++++++++++---------
log4j-1.2-api/pom.xml | 2 +-
log4j-api-scala_2.10/pom.xml | 2 +-
log4j-api-scala_2.11/pom.xml | 2 +-
log4j-api/pom.xml | 2 +-
.../org/apache/logging/log4j/ThreadContext.java | 5 +-
log4j-bom/pom.xml | 2 +-
log4j-core-its/pom.xml | 2 +-
log4j-core/pom.xml | 2 +-
.../apache/logging/log4j/core/config/Order.java | 2 +-
.../log4j/core/config/OrderComparator.java | 2 +-
.../builder/api/ConfigurationBuilder.java | 15 ++++
.../api/KeyValuePairComponentBuilder.java | 25 +++++++
.../builder/api/PropertyComponentBuilder.java | 25 +++++++
.../impl/DefaultConfigurationBuilder.java | 11 +++
.../DefaultKeyValuePairComponentBuilder.java | 34 +++++++++
.../impl/DefaultPropertyComponentBuilder.java | 32 ++++++++
.../core/util/FilteredObjectInputStream.java | 67 +++++++++++++++++
.../builder/ConfigurationAssemblerTest.java | 6 +-
.../builder/ConfigurationBuilderTest.java | 16 ++++
.../builder/CustomConfigurationFactory.java | 11 +++
log4j-distribution/pom.xml | 2 +-
log4j-distribution/src/assembly/bin.xml | 4 +-
log4j-flume-ng/pom.xml | 2 +-
log4j-iostreams/pom.xml | 2 +-
log4j-jcl/pom.xml | 2 +-
log4j-jmx-gui/pom.xml | 2 +-
log4j-jul/pom.xml | 2 +-
log4j-liquibase/pom.xml | 2 +-
log4j-nosql/pom.xml | 2 +-
log4j-osgi/pom.xml | 2 +-
log4j-perf/pom.xml | 2 +-
log4j-samples/configuration/pom.xml | 2 +-
log4j-samples/flume-common/pom.xml | 2 +-
log4j-samples/flume-embedded/pom.xml | 2 +-
log4j-samples/flume-remote/pom.xml | 2 +-
log4j-samples/loggerProperties/pom.xml | 2 +-
log4j-samples/pom.xml | 2 +-
log4j-samples/scala-api/pom.xml | 2 +-
.../log4j/server/AbstractSocketServer.java | 13 ++++
.../server/ObjectInputStreamLogEventBridge.java | 23 +++++-
.../logging/log4j/server/TcpSocketServer.java | 25 ++++++-
.../logging/log4j/server/UdpSocketServer.java | 18 ++++-
log4j-slf4j-impl/pom.xml | 2 +-
log4j-taglib/pom.xml | 2 +-
log4j-to-slf4j/pom.xml | 2 +-
log4j-web/pom.xml | 2 +-
pom.xml | 31 +++++---
src/changes/changes.xml | 26 ++++++-
src/site/markdown/maven-artifacts.md.vm | 2 +-
src/site/resources/images/logo.png | Bin 40517 -> 40494 bytes
.../logo/logo-electric-blue-2-2.8.2.png | Bin 0 -> 40494 bytes
.../logo/logo-electric-blue-2-2.8.2.xcf | Bin 0 -> 67168 bytes
.../resources/logo/logo-electric-blue-2.xcf | Bin 0 -> 66097 bytes
56 files changed, 437 insertions(+), 90 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
----------------------------------------------------------------------
diff --cc log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
index a8f1140,0000000..aff7eb1
mode 100644,000000..100644
--- a/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
+++ b/log4j-server/src/main/java/org/apache/logging/log4j/server/AbstractSocketServer.java
@@@ -1,209 -1,0 +1,222 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.server;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
++import java.util.Collections;
++import java.util.List;
+import java.util.Objects;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.validators.PositiveInteger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEventListener;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
+import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
+import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
+import org.apache.logging.log4j.core.util.InetAddressConverter;
+import org.apache.logging.log4j.core.util.Log4jThread;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * Abstract socket server for TCP and UDP implementations.
+ *
+ * @param <T>
+ * The kind of input stream read
+ *
+ * TODO Make a LifeCycle
+ */
+public abstract class AbstractSocketServer<T extends InputStream> extends LogEventListener implements Runnable {
+
+ protected static class CommandLineArguments extends BasicCommandLineArguments {
+
+ @Parameter(names = { "--config", "-c" }, description = "Log4j configuration file location (path or URL).")
+ private String configLocation;
+
+ @Parameter(names = { "--interactive",
+ "-i" }, description = "Accepts commands on standard input (\"exit\" is the only command).")
+ private boolean interactive;
+
+ @Parameter(names = { "--port",
+ "-p" }, validateWith = PositiveInteger.class, description = "Server socket port.")
+ private int port;
+
+ @Parameter(names = { "--localbindaddress",
+ "-a" }, converter = InetAddressConverter.class, description = "Server socket local bind address.")
+ private InetAddress localBindAddress;
+
++ @Parameter(names = {"--classes", "-C"}, description = "Additional classes to allow deserialization")
++ private List<String> allowedClasses;
++
+ String getConfigLocation() {
+ return configLocation;
+ }
+
+ int getPort() {
+ return port;
+ }
+
+ protected boolean isInteractive() {
+ return interactive;
+ }
+
+ void setConfigLocation(final String configLocation) {
+ this.configLocation = configLocation;
+ }
+
+ void setInteractive(final boolean interactive) {
+ this.interactive = interactive;
+ }
+
+ void setPort(final int port) {
+ this.port = port;
+ }
+
+ InetAddress getLocalBindAddress() {
+ return localBindAddress;
+ }
+
+ void setLocalBindAddress(final InetAddress localBindAddress) {
+ this.localBindAddress = localBindAddress;
+ }
++
++ List<String> getAllowedClasses() {
++ return allowedClasses == null ? Collections.<String>emptyList() : allowedClasses;
++ }
++
++ void setAllowedClasses(final List<String> allowedClasses) {
++ this.allowedClasses = allowedClasses;
++ }
+ }
+
+ /**
+ * Factory that creates a Configuration for the server.
+ */
+ protected static class ServerConfigurationFactory extends XmlConfigurationFactory {
+
+ private final String path;
+
+ public ServerConfigurationFactory(final String path) {
+ this.path = path;
+ }
+
+ @Override
+ public Configuration getConfiguration(final LoggerContext loggerContext, final String name,
+ final URI configLocation) {
+ if (Strings.isNotEmpty(path)) {
+ File file = null;
+ ConfigurationSource source = null;
+ try {
+ file = new File(path);
+ final FileInputStream is = new FileInputStream(file);
+ source = new ConfigurationSource(is, file);
+ } catch (final FileNotFoundException ignored) {
+ // Ignore this error
+ }
+ if (source == null) {
+ try {
+ final URL url = new URL(path);
+ source = new ConfigurationSource(url.openStream(), url);
+ } catch (final IOException ignored) {
+ // Ignore this error
+ }
+ }
+
+ try {
+ if (source != null) {
+ return new XmlConfiguration(loggerContext, source);
+ }
+ } catch (final Exception ignored) {
+ // Ignore this error.
+ }
+ System.err.println("Unable to process configuration at " + path + ", using default.");
+ }
+ return super.getConfiguration(loggerContext, name, configLocation);
+ }
+ }
+
+ protected static final int MAX_PORT = 65534;
+
+ private volatile boolean active = true;
+
+ protected final LogEventBridge<T> logEventInput;
+
+ protected final Logger logger;
+
+ /**
+ * Creates a new socket server.
+ *
+ * @param port
+ * listen to this port
+ * @param logEventInput
+ * Use this input to read log events.
+ */
+ public AbstractSocketServer(final int port, final LogEventBridge<T> logEventInput) {
+ this.logger = LogManager.getLogger(this.getClass().getName() + '.' + port);
+ this.logEventInput = Objects.requireNonNull(logEventInput, "LogEventInput");
+ }
+
+ protected boolean isActive() {
+ return this.active;
+ }
+
+ protected void setActive(final boolean isActive) {
+ this.active = isActive;
+ }
+
+ /**
+ * Start this server in a new thread.
+ *
+ * @return the new thread that running this server.
+ */
+ public Thread startNewThread() {
+ final Thread thread = new Log4jThread(this);
+ thread.start();
+ return thread;
+ }
+
+ public abstract void shutdown() throws Exception;
+
+ public void awaitTermination(final Thread serverThread) throws Exception {
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+ while (true) {
+ final String line = reader.readLine();
+ if (line == null
+ || line.equalsIgnoreCase("quit")
+ || line.equalsIgnoreCase("stop")
+ || line.equalsIgnoreCase("exit")) {
+ this.shutdown();
+ serverThread.join();
+ break;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
----------------------------------------------------------------------
diff --cc log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
index 9f22b22,0000000..ddd2e26
mode 100644,000000..100644
--- a/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
+++ b/log4j-server/src/main/java/org/apache/logging/log4j/server/ObjectInputStreamLogEventBridge.java
@@@ -1,45 -1,0 +1,64 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
++import java.util.Collections;
++import java.util.List;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LogEventListener;
++import org.apache.logging.log4j.core.util.FilteredObjectInputStream;
+
+/**
+ * Reads and logs serialized {@link LogEvent} objects from an {@link ObjectInputStream}.
+ */
+public class ObjectInputStreamLogEventBridge extends AbstractLogEventBridge<ObjectInputStream> {
+
++ private final List<String> allowedClasses;
++
++ public ObjectInputStreamLogEventBridge() {
++ this(Collections.<String>emptyList());
++ }
++
++ /**
++ * Constructs an ObjectInputStreamLogEventBridge with additional allowed classes to deserialize.
++ *
++ * @param allowedClasses class names to also allow for deserialization
++ * @since 2.8.2
++ */
++ public ObjectInputStreamLogEventBridge(final List<String> allowedClasses) {
++ this.allowedClasses = allowedClasses;
++ }
++
+ @Override
+ public void logEvents(final ObjectInputStream inputStream, final LogEventListener logEventListener)
- throws IOException {
++ throws IOException {
+ try {
+ logEventListener.log((LogEvent) inputStream.readObject());
+ } catch (final ClassNotFoundException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public ObjectInputStream wrapStream(final InputStream inputStream) throws IOException {
- return new ObjectInputStream(inputStream);
++ return new FilteredObjectInputStream(inputStream, allowedClasses);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
----------------------------------------------------------------------
diff --cc log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
index 7856969,0000000..9a5521c
mode 100644,000000..100644
--- a/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
+++ b/log4j-server/src/main/java/org/apache/logging/log4j/server/TcpSocketServer.java
@@@ -1,314 -1,0 +1,333 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.server;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.OptionalDataException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
++import java.util.Collections;
++import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.validators.PositiveInteger;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
+import org.apache.logging.log4j.core.util.Closer;
+import org.apache.logging.log4j.core.util.Log4jThread;
+import org.apache.logging.log4j.message.EntryMessage;
+
+/**
+ * Listens for Log4j events on a TCP server socket and passes them on to Log4j.
+ *
+ * @param <T>
+ * The kind of input stream read
+ * @see #main(String[])
+ */
+public class TcpSocketServer<T extends InputStream> extends AbstractSocketServer<T> {
+
+ protected static class CommandLineArguments extends AbstractSocketServer.CommandLineArguments {
+
+ @Parameter(names = { "--backlog",
+ "-b" }, validateWith = PositiveInteger.class, description = "Server socket backlog.")
+ // Same default as ServerSocket
+ private int backlog = 50;
+
+ int getBacklog() {
+ return backlog;
+ }
+
+ void setBacklog(final int backlog) {
+ this.backlog = backlog;
+ }
+
+ }
+
+ /**
+ * Thread that processes the events.
+ */
+ private class SocketHandler extends Log4jThread {
+
+ private final T inputStream;
+
+ private volatile boolean shutdown = false;
+
+ public SocketHandler(final Socket socket) throws IOException {
+ this.inputStream = logEventInput.wrapStream(socket.getInputStream());
+ }
+
+ @Override
+ public void run() {
+ final EntryMessage entry = logger.traceEntry();
+ boolean closed = false;
+ try {
+ try {
+ while (!shutdown) {
+ logEventInput.logEvents(inputStream, TcpSocketServer.this);
+ }
+ } catch (final EOFException e) {
+ closed = true;
+ } catch (final OptionalDataException e) {
+ logger.error("OptionalDataException eof=" + e.eof + " length=" + e.length, e);
+ } catch (final IOException e) {
+ logger.error("IOException encountered while reading from socket", e);
+ }
+ if (!closed) {
+ Closer.closeSilently(inputStream);
+ }
+ } finally {
+ handlers.remove(Long.valueOf(getId()));
+ }
+ logger.traceExit(entry);
+ }
+
+ public void shutdown() {
+ this.shutdown = true;
+ interrupt();
+ }
+ }
+
+ /**
+ * Creates a socket server that reads JSON log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static TcpSocketServer<InputStream> createJsonSocketServer(final int port) throws IOException {
+ LOGGER.entry("createJsonSocketServer", port);
+ final TcpSocketServer<InputStream> socketServer = new TcpSocketServer<>(port, new JsonInputStreamLogEventBridge());
+ return LOGGER.exit(socketServer);
+ }
+
+ /**
+ * Creates a socket server that reads serialized log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port) throws IOException {
+ LOGGER.entry(port);
+ final TcpSocketServer<ObjectInputStream> socketServer = new TcpSocketServer<>(port, new ObjectInputStreamLogEventBridge());
+ return LOGGER.exit(socketServer);
+ }
+
+ /**
+ * Creates a socket server that reads serialized log events.
+ *
+ * @param port the port to listen
+ * @param localBindAddress The server socket's local bin address
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ * @since 2.7
+ */
+ public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port, final int backlog,
+ final InetAddress localBindAddress) throws IOException {
++ return createSerializedSocketServer(port, backlog, localBindAddress, Collections.<String>emptyList());
++ }
++
++ /**
++ * Creates a socket server that reads serialized log events.
++ *
++ * @param port the port to listen
++ * @param localBindAddress The server socket's local bin address
++ * @param allowedClasses additional class names to allow for deserialization
++ * @return a new a socket server
++ * @throws IOException
++ * if an I/O error occurs when opening the socket.
++ * @since 2.8.2
++ */
++ public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(
++ final int port, final int backlog, final InetAddress localBindAddress, final List<String> allowedClasses
++ ) throws IOException {
+ LOGGER.entry(port);
+ final TcpSocketServer<ObjectInputStream> socketServer = new TcpSocketServer<>(port, backlog, localBindAddress,
- new ObjectInputStreamLogEventBridge());
++ new ObjectInputStreamLogEventBridge(allowedClasses));
+ return LOGGER.exit(socketServer);
+ }
+
+ /**
+ * Creates a socket server that reads XML log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static TcpSocketServer<InputStream> createXmlSocketServer(final int port) throws IOException {
+ LOGGER.entry(port);
+ final TcpSocketServer<InputStream> socketServer = new TcpSocketServer<>(port, new XmlInputStreamLogEventBridge());
+ return LOGGER.exit(socketServer);
+ }
+
+ /**
+ * Main startup for the server. Run with "--help" for to print command line help on the console.
+ *
+ * @param args
+ * The command line arguments.
+ * @throws Exception
+ * if an error occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ final CommandLineArguments cla = BasicCommandLineArguments.parseCommandLine(args, TcpSocketServer.class, new CommandLineArguments());
+ if (cla.isHelp()) {
+ return;
+ }
+ if (cla.getConfigLocation() != null) {
+ ConfigurationFactory.setConfigurationFactory(new ServerConfigurationFactory(cla.getConfigLocation()));
+ }
- final TcpSocketServer<ObjectInputStream> socketServer = TcpSocketServer
- .createSerializedSocketServer(cla.getPort(), cla.getBacklog(), cla.getLocalBindAddress());
++ final TcpSocketServer<ObjectInputStream> socketServer = TcpSocketServer.createSerializedSocketServer(
++ cla.getPort(), cla.getBacklog(), cla.getLocalBindAddress(), cla.getAllowedClasses());
+ final Thread serverThread = socketServer.startNewThread();
+ if (cla.isInteractive()) {
+ socketServer.awaitTermination(serverThread);
+ }
+ }
+
+ private final ConcurrentMap<Long, SocketHandler> handlers = new ConcurrentHashMap<>();
+
+ private final ServerSocket serverSocket;
+
+ /**
+ * Constructor.
+ *
+ * @param port
+ * The server socket port.
+ * @param backlog
+ * The server socket backlog.
+ * @param localBindAddress TODO
+ * @param logEventInput
+ * the log even input
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ * @since 2.7
+ */
+ @SuppressWarnings("resource")
+ public TcpSocketServer(final int port, final int backlog, final InetAddress localBindAddress, final LogEventBridge<T> logEventInput) throws IOException {
+ this(port, logEventInput, new ServerSocket(port, backlog, localBindAddress));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param port
+ * to listen.
+ * @param logEventInput
+ * the log even input
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public TcpSocketServer(final int port, final LogEventBridge<T> logEventInput) throws IOException {
+ this(port, logEventInput, extracted(port));
+ }
+
+ private static ServerSocket extracted(final int port) throws IOException {
+ return new ServerSocket(port);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param port
+ * to listen.
+ * @param logEventInput
+ * the log even input
+ * @param serverSocket
+ * the socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public TcpSocketServer(final int port, final LogEventBridge<T> logEventInput, final ServerSocket serverSocket)
+ throws IOException {
+ super(port, logEventInput);
+ this.serverSocket = serverSocket;
+ }
+
+ /**
+ * Accept incoming events and processes them.
+ */
+ @Override
+ public void run() {
+ final EntryMessage entry = logger.traceEntry();
+ while (isActive()) {
+ if (serverSocket.isClosed()) {
+ return;
+ }
+ try {
+ // Accept incoming connections.
+ logger.debug("Listening for a connection {}...", serverSocket);
+ final Socket clientSocket = serverSocket.accept();
+ logger.debug("Acepted connection on {}...", serverSocket);
+ logger.debug("Socket accepted: {}", clientSocket);
+ clientSocket.setSoLinger(true, 0);
+
+ // accept() will block until a client connects to the server.
+ // If execution reaches this point, then it means that a client
+ // socket has been accepted.
+
+ final SocketHandler handler = new SocketHandler(clientSocket);
+ handlers.put(Long.valueOf(handler.getId()), handler);
+ handler.start();
+ } catch (final IOException e) {
+ if (serverSocket.isClosed()) {
+ // OK we're done.
+ logger.traceExit(entry);
+ return;
+ }
+ logger.error("Exception encountered on accept. Ignoring. Stack trace :", e);
+ }
+ }
+ for (final Map.Entry<Long, SocketHandler> handlerEntry : handlers.entrySet()) {
+ final SocketHandler handler = handlerEntry.getValue();
+ handler.shutdown();
+ try {
+ handler.join();
+ } catch (final InterruptedException ignored) {
+ // Ignore the exception
+ }
+ }
+ logger.traceExit(entry);
+ }
+
+ /**
+ * Shutdown the server.
+ *
+ * @throws IOException if the server socket could not be closed
+ */
+ @Override
+ public void shutdown() throws IOException {
+ final EntryMessage entry = logger.traceEntry();
+ setActive(false);
+ Thread.currentThread().interrupt();
+ serverSocket.close();
+ logger.traceExit(entry);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
----------------------------------------------------------------------
diff --cc log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
index a2bac17,0000000..12a8450
mode 100644,000000..100644
--- a/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
+++ b/log4j-server/src/main/java/org/apache/logging/log4j/server/UdpSocketServer.java
@@@ -1,169 -1,0 +1,185 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.server;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.OptionalDataException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
++import java.util.List;
+
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.BasicCommandLineArguments;
+
+/**
+ * Listens for Log4j events on a datagram socket and passes them on to Log4j.
+ *
+ * @param <T>
+ * The kind of input stream read
+ * @see #main(String[])
+ */
+public class UdpSocketServer<T extends InputStream> extends AbstractSocketServer<T> {
+
+ /**
+ * Creates a socket server that reads JSON log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static UdpSocketServer<InputStream> createJsonSocketServer(final int port) throws IOException {
+ return new UdpSocketServer<>(port, new JsonInputStreamLogEventBridge());
+ }
+
+ /**
+ * Creates a socket server that reads serialized log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static UdpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port) throws IOException {
+ return new UdpSocketServer<>(port, new ObjectInputStreamLogEventBridge());
+ }
+
+ /**
++ * Creates a socket server that reads serialized log events.
++ *
++ * @param port the port to listen
++ * @param allowedClasses additional classes to allow for deserialization
++ * @return a new a socket server
++ * @throws IOException if an I/O error occurs when opening the socket.
++ * @since 2.8.2
++ */
++ public static UdpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port,
++ final List<String> allowedClasses)
++ throws IOException {
++ return new UdpSocketServer<>(port, new ObjectInputStreamLogEventBridge(allowedClasses));
++ }
++
++ /**
+ * Creates a socket server that reads XML log events.
+ *
+ * @param port
+ * the port to listen
+ * @return a new a socket server
+ * @throws IOException
+ * if an I/O error occurs when opening the socket.
+ */
+ public static UdpSocketServer<InputStream> createXmlSocketServer(final int port) throws IOException {
+ return new UdpSocketServer<>(port, new XmlInputStreamLogEventBridge());
+ }
+
+ /**
+ * Main startup for the server. Run with "--help" for to print command line help on the console.
+ *
+ * @param args
+ * The command line arguments.
+ * @throws Exception
+ * if an error occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ final CommandLineArguments cla = BasicCommandLineArguments.parseCommandLine(args, UdpSocketServer.class, new CommandLineArguments());
+ if (cla.isHelp()) {
+ return;
+ }
+ if (cla.getConfigLocation() != null) {
+ ConfigurationFactory.setConfigurationFactory(new ServerConfigurationFactory(cla.getConfigLocation()));
+ }
+ final UdpSocketServer<ObjectInputStream> socketServer = UdpSocketServer
- .createSerializedSocketServer(cla.getPort());
++ .createSerializedSocketServer(cla.getPort(), cla.getAllowedClasses());
+ final Thread serverThread = socketServer.startNewThread();
+ if (cla.isInteractive()) {
+ socketServer.awaitTermination(serverThread);
+ }
+ }
+
+ private final DatagramSocket datagramSocket;
+
+ // max size so we only have to deal with one packet
+ private final int maxBufferSize = 1024 * 65 + 1024;
+
+ /**
+ * Constructor.
+ *
+ * @param port
+ * to listen on.
+ * @param logEventInput
+ * @throws IOException
+ * If an error occurs.
+ */
+ public UdpSocketServer(final int port, final LogEventBridge<T> logEventInput) throws IOException {
+ super(port, logEventInput);
+ this.datagramSocket = new DatagramSocket(port);
+ }
+
+ /**
+ * Accept incoming events and processes them.
+ */
+ @Override
+ public void run() {
+ while (isActive()) {
+ if (datagramSocket.isClosed()) {
+ // OK we're done.
+ return;
+ }
+ try {
+ final byte[] buf = new byte[maxBufferSize];
+ final DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ datagramSocket.receive(packet);
+ final ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength());
+ logEventInput.logEvents(logEventInput.wrapStream(bais), this);
+ } catch (final OptionalDataException e) {
+ if (datagramSocket.isClosed()) {
+ // OK we're done.
+ return;
+ }
+ logger.error("OptionalDataException eof=" + e.eof + " length=" + e.length, e);
+ } catch (final EOFException e) {
+ if (datagramSocket.isClosed()) {
+ // OK we're done.
+ return;
+ }
+ logger.info("EOF encountered");
+ } catch (final IOException e) {
+ if (datagramSocket.isClosed()) {
+ // OK we're done.
+ return;
+ }
+ logger.error("Exception encountered on accept. Ignoring. Stack Trace :", e);
+ }
+ }
+ }
+
+ /**
+ * Shutdown the server.
+ */
+ @Override
+ public void shutdown() {
+ this.setActive(false);
+ Thread.currentThread().interrupt();
+ datagramSocket.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/394c30f5/pom.xml
----------------------------------------------------------------------