Author: rgoers
Date: Mon Mar 25 00:56:25 2013
New Revision: 1460497
URL: http://svn.apache.org/r1460497
Log:
LOG4J2-177, LOG4J2-181 - Fix NPE in DatagramSocketManager and write header
whenever the OutputStream is set in OutputStreamManager.
Added:
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/BasicLayout.java
Modified:
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/DatagramOutputStream.java
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java
logging/log4j/log4j2/trunk/core/src/test/resources/log4j-socket.xml
logging/log4j/log4j2/trunk/src/changes/changes.xml
Modified:
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java?rev=1460497&r1=1460496&r2=1460497&view=diff
==============================================================================
---
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
(original)
+++
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
Mon Mar 25 00:56:25 2013
@@ -28,6 +28,7 @@ public class OutputStreamManager extends
private OutputStream os;
private byte[] footer = null;
+ private byte[] header = null;
protected OutputStreamManager(final OutputStream os, final String
streamName) {
super(streamName);
@@ -54,6 +55,7 @@ public class OutputStreamManager extends
*/
public synchronized void setHeader(final byte[] header) {
if (header != null) {
+ this.header = header;
try {
this.os.write(header, 0, header.length);
} catch (final IOException ioe) {
@@ -97,6 +99,13 @@ public class OutputStreamManager extends
protected void setOutputStream(final OutputStream os) {
this.os = os;
+ if (header != null) {
+ try {
+ this.os.write(header, 0, header.length);
+ } catch (final IOException ioe) {
+ LOGGER.error("Unable to write header", ioe);
+ }
+ }
}
/**
Modified:
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/DatagramOutputStream.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/DatagramOutputStream.java?rev=1460497&r1=1460496&r2=1460497&view=diff
==============================================================================
---
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/DatagramOutputStream.java
(original)
+++
logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/net/DatagramOutputStream.java
Mon Mar 25 00:56:25 2013
@@ -89,7 +89,7 @@ public class DatagramOutputStream extend
@Override
public synchronized void flush() throws IOException {
- if (this.ds != null && this.address != null) {
+ if (this.data != null && this.ds != null && this.address != null) {
final DatagramPacket packet = new DatagramPacket(data,
data.length, address, port);
ds.send(packet);
}
Modified:
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java?rev=1460497&r1=1460496&r2=1460497&view=diff
==============================================================================
---
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java
(original)
+++
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java
Mon Mar 25 00:56:25 2013
@@ -29,14 +29,15 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
public class SocketReconnectTest {
private static final int SOCKET_PORT = 5514;
@@ -50,120 +51,125 @@ public class SocketReconnectTest {
@Test
public void testReconnect() throws Exception {
- TestSocketServer testServer = null;
- ExecutorService executor = null;
- Future<InputStream> futureIn;
- final InputStream in;
-
- try {
- executor = Executors.newSingleThreadExecutor();
- System.err.println("Initializing server");
- testServer = new TestSocketServer();
- futureIn = executor.submit(testServer);
- Thread.sleep(300);
-
- //System.err.println("Initializing logger");
- final Logger logger =
LogManager.getLogger(SocketReconnectTest.class);
- String message = "Log #1";
- logger.error(message);
+ List<String> list = new ArrayList<String>();
+ TestSocketServer server = new TestSocketServer(list);
+ server.start();
+ Thread.sleep(300);
+
+ //System.err.println("Initializing logger");
+ final Logger logger = LogManager.getLogger(SocketReconnectTest.class);
+
+ String message = "Log #1";
+ logger.error(message);
+ String expectedHeader = "Header";
+
+ String msg = null;
+ String header = null;
+ for (int i = 0; i < 5; ++i) {
+ Thread.sleep(100);
+ if (list.size() > 1) {
+ header = list.get(0);
+ msg = list.get(1);
+ break;
+ }
+ }
+ assertNotNull("No header", header);
+ assertEquals(expectedHeader, header);
+ assertNotNull("No message", msg);
+ assertEquals(message, msg);
- BufferedReader reader = new BufferedReader(new
InputStreamReader(futureIn.get()));
- assertEquals(message, reader.readLine());
+ server.shutdown();
+ server.join();
- closeQuietly(testServer);
- executor.shutdown();
- try {
- // Wait a while for existing tasks to terminate
- if (!executor.awaitTermination(100, TimeUnit.MILLISECONDS)) {
- executor.shutdownNow();
- if (!executor.awaitTermination(100,
TimeUnit.MILLISECONDS)) {
- System.err.println("Pool did not terminate");
- }
- }
- } catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- executor.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
- }
+ list.clear();
- message = "Log #2";
- logger.error(message);
+ message = "Log #2";
+ boolean exceptionCaught = false;
- message = "Log #3";
+ for (int i = 0; i < 5; ++i) {
try {
logger.error(message);
} catch (final AppenderRuntimeException e) {
+ exceptionCaught = true;
+ break;
// System.err.println("Caught expected exception");
}
+ }
+ assertTrue("No Exception thrown", exceptionCaught);
+ message = "Log #3";
- //System.err.println("Re-initializing server");
- executor = Executors.newSingleThreadExecutor();
- testServer = new TestSocketServer();
- futureIn = executor.submit(testServer);
- Thread.sleep(500);
- try {
- logger.error(message);
- reader = new BufferedReader(new
InputStreamReader(futureIn.get()));
- assertEquals(message, reader.readLine());
- } catch (final AppenderRuntimeException e) {
- e.printStackTrace();
- fail("Unexpected Exception");
+ server = new TestSocketServer(list);
+ server.start();
+ Thread.sleep(300);
+
+ msg = null;
+ header = null;
+ logger.error(message);
+ for (int i = 0; i < 5; ++i) {
+ Thread.sleep(100);
+ if (list.size() > 1) {
+ header = list.get(0);
+ msg = list.get(1);
+ break;
}
- //System.err.println("Sleeping to demonstrate repeated
re-connections");
- //Thread.sleep(5000);
- } finally {
- closeQuietly(testServer);
- closeQuietly(executor);
}
+ assertNotNull("No header", header);
+ assertEquals(expectedHeader, header);
+ assertNotNull("No message", msg);
+ assertEquals(message, msg);
+ server.shutdown();
+ server.join();
}
- private static class TestSocketServer implements Callable<InputStream> {
- private ServerSocket server;
+ private static class TestSocketServer extends Thread {
+ private volatile boolean shutdown = false;
+ private List<String> list;
private Socket client;
- public InputStream call() throws Exception {
- server = new ServerSocket(SOCKET_PORT);
- client = server.accept();
- return client.getInputStream();
- }
-
- public void close() {
- closeQuietly(client);
- closeQuietly(server);
- }
-
- private void closeQuietly(final ServerSocket socket) {
- if (null != socket) {
- try {
- socket.close();
- } catch (final IOException ignore) {
- }
- }
+ public TestSocketServer(List<String> list) {
+ this.list = list;
}
- private void closeQuietly(final Socket socket) {
- if (null != socket) {
- try {
- socket.close();
- } catch (final IOException ignore) {
+ public void run() {
+ ServerSocket server = null;
+ client = null;
+ try {
+ server = new ServerSocket(SOCKET_PORT);
+ client = server.accept();
+ while (!shutdown) {
+ BufferedReader reader = new BufferedReader(new
InputStreamReader(client.getInputStream()));
+ list.add(reader.readLine());
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ } finally {
+ if (client != null) {
+ try {
+ client.close();
+ } catch (Exception ex) {
+ System.out.println("Unable to close socket " +
ex.getMessage());
+ }
+ }
+ if (server != null) {
+ try {
+ server.close();
+ } catch (Exception ex) {
+ System.out.println("Unable to close server socket " +
ex.getMessage());
+ }
}
}
}
- }
- private static void closeQuietly(final ExecutorService executor) {
- if (null != executor) {
- executor.shutdownNow();
- }
- }
-
- private static void closeQuietly(final TestSocketServer testServer) {
- if (null != testServer) {
- testServer.close();
+ public void shutdown() {
+ shutdown = true;
+ try {
+ client.shutdownInput();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
}
}
}
Added:
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/BasicLayout.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/BasicLayout.java?rev=1460497&view=auto
==============================================================================
---
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/BasicLayout.java
(added)
+++
logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/test/layout/BasicLayout.java
Mon Mar 25 00:56:25 2013
@@ -0,0 +1,61 @@
+/*
+ * 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.test.layout;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.Charsets;
+import org.apache.logging.log4j.core.helpers.Constants;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout;
+
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+@Plugin(name = "BasicLayout", type = "Core", elementType = "layout",
printObject = true)
+public class BasicLayout extends AbstractStringLayout {
+
+ private static final String HEADER = "Header" + Constants.LINE_SEP;
+
+ public byte[] getHeader() {
+ return HEADER.getBytes(getCharset());
+ }
+
+ public BasicLayout(final Charset charset) {
+ super(charset);
+ }
+
+ public String toSerializable(LogEvent event) {
+ return event.getMessage().getFormattedMessage() + Constants.LINE_SEP;
+ }
+
+ public Map<String, String> getContentFormat() {
+ return new HashMap<String, String>();
+ }
+
+ /**
+ */
+ @PluginFactory
+ public static BasicLayout createLayout() {
+ final Charset charset = Charsets.getSupportedCharset("UTF-8");
+ return new BasicLayout(charset);
+ }
+}
Modified: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-socket.xml
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-socket.xml?rev=1460497&r1=1460496&r2=1460497&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-socket.xml
(original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-socket.xml Mon Mar
25 00:56:25 2013
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
-<configuration status="debug" name="MyApp">
+<configuration status="warn" name="MyApp"
packages="org.apache.logging.log4j.test">
<appenders>
<Socket name="socket" host="localhost" port="5514"
protocol="TCP" suppressExceptions="false"
- reconnectionDelay="250">
- <PatternLayout pattern="%msg%n"/>
+ reconnectionDelay="100">
+ <BasicLayout />
</Socket>
</appenders>
<loggers>
Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1460497&r1=1460496&r2=1460497&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Mon Mar 25 00:56:25 2013
@@ -23,6 +23,12 @@
<body>
<release version="2.0-beta5" date="@TBD@" description="Bug fixes and
enhancements">
+ <action issue="LOG4J2-181" dev="rgoers" type="fix">
+ OutputStreamManager now adds the layout header whenever the
OutputStream is set.
+ </action>
+ <action issue="LOG4J2-177" dev="rgoers" type="fix" due-to="Remko Popma">
+ Fix NullPointerException in DatagramOutputStream when flush is called
from multiple threads.
+ </action>
<action dev="rgoers" type="add">
Added FlumePersistentManager which writes to BerkeleyDB and then
writes to Flume asynchronously.
</action>