blob: 72b7c25f575eef0528bf7ab3a74517e25de08b87 [file] [log] [blame]
/*
* 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.core.net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.test.AvailablePortFinder;
import org.apache.logging.log4j.util.Strings;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
//@Ignore("Currently needs better port choosing support")
public class SocketReconnectTest {
private static final int SOCKET_PORT1 = AvailablePortFinder.getNextAvailable();
private static final int SOCKET_PORT2 = AvailablePortFinder.getNextAvailable();
private static final String CONFIG = "log4j-socket.xml";
private static final String SHUTDOWN = "Shutdown" + Strings.LINE_SEPARATOR +
"................................................................" + Strings.LINE_SEPARATOR +
"................................................................" + Strings.LINE_SEPARATOR +
"................................................................" + Strings.LINE_SEPARATOR +
"................................................................" + Strings.LINE_SEPARATOR;
public static LocalHostResolver resolver = new LocalHostResolver();
private static LoggerContext loggerContext;
private static final List<String> list = new ArrayList<>();
private static int[] ports;
private static TestSocketServer server1;
private static TestSocketServer server2;
private static Logger logger;
@BeforeClass
public static void beforeClass() throws IOException, InterruptedException {
server1 = new TestSocketServer(0);
server2 = new TestSocketServer(0);
server1.start();
server2.start();
Thread.sleep(100);
ports = new int[] { server1.getPort(), server2.getPort()};
resolver.ports = ports;
TcpSocketManager.setHostResolver(resolver);
loggerContext = Configurator.initialize("SocketReconnectTest", SocketReconnectTest.class.getClassLoader(),
CONFIG);
logger = LogManager.getLogger(SocketReconnectTest.class);
server1.shutdown();
server1.join();
server2.shutdown();
server2.join();
server1 = null;
server2 = null;
Thread.sleep(100);
list.clear();
}
@AfterClass
public static void afterClass() {
Configurator.shutdown(loggerContext);
}
@After
public void after() throws InterruptedException {
if (server1 != null) {
server1.shutdown();
server1.join();
}
if (server2 != null) {
server2.shutdown();
server2.join();
}
server1 = null;
server2 = null;
Thread.sleep(300);
}
@Test
public void testReconnect() throws Exception {
list.clear();
resolver.ports = new int[] {ports[0]};
server1 = new TestSocketServer(ports[0]);
server1.start();
Thread.sleep(200);
String message = "Log #1";
String msg = null;
for (int i = 0; i < 5; ++i) {
logger.error(message);
Thread.sleep(100);
if (list.size() > 0) {
msg = list.get(0);
if (msg != null) {
break;
}
}
}
assertNotNull("No message", msg);
assertEquals(message, msg);
logger.error(SHUTDOWN);
server1.join();
list.clear();
message = "Log #2";
boolean exceptionCaught = false;
for (int i = 0; i < 100; ++i) {
try {
logger.error(message);
} catch (final AppenderLoggingException e) {
exceptionCaught = true;
break;
// System.err.println("Caught expected exception");
}
}
assertTrue("No Exception thrown", exceptionCaught);
message = "Log #3";
server1 = new TestSocketServer(ports[0]);
server1.start();
Thread.sleep(300);
msg = null;
for (int i = 0; i < 5; ++i) {
logger.error(message);
Thread.sleep(100);
if (list.size() > 0) {
msg = list.get(0);
if (msg != null) {
break;
}
}
}
assertNotNull("No message", msg);
assertEquals(message, msg);
logger.error(SHUTDOWN);
server1.join();
}
@Test
public void testFailover() throws Exception {
list.clear();
server1 = new TestSocketServer(ports[0]);
server2 = new TestSocketServer(ports[1]);
resolver.ports = ports;
server1.start();
server2.start();
Thread.sleep(100);
String message = "Log #1";
String msg = null;
for (int i = 0; i < 5; ++i) {
logger.error(message);
Thread.sleep(100);
if (list.size() > 0) {
msg = list.get(0);
if (msg != null) {
break;
}
}
}
assertNotNull("No message", msg);
assertEquals(message, msg);
server1.shutdown();
server1.join();
list.clear();
message = "Log #2";
for (int i = 0; i < 5; ++i) {
logger.error(message);
Thread.sleep(100);
if (list.size() > 0) {
msg = list.get(0);
if (msg != null) {
break;
}
}
}
assertNotNull("No message", msg);
assertEquals(message, msg);
server2.shutdown();
server2.join();
}
private static class TestSocketServer extends Thread {
private volatile boolean shutdown = false;
private volatile boolean started = false;
private volatile Socket client;
private final int port;
private ServerSocket server;
public TestSocketServer(int port) throws IOException {
this.port = port;
server = new ServerSocket(port);
}
public int getPort() {
return port == 0 ? server.getLocalPort() : port;
}
public void shutdown() {
if (!shutdown) {
shutdown = true;
if (server != null && server.isBound()) {
try {
if (client != null) {
Socket serverClient = client;
client = null;
serverClient.shutdownInput();
serverClient.shutdownOutput();
serverClient.setSoLinger(true, 0);
serverClient.close();
}
ServerSocket serverSocket = server;
server = null;
serverSocket.close();
} catch (Exception ex) {
System.out.println("Unable to send shutdown message");
ex.printStackTrace();
}
}
return;
}
}
@Override
public void run() {
client = null;
try {
client = server.accept();
started = true;
while (!shutdown) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
final String line = reader.readLine();
if (line == null || line.equals("Shutdown")) {
shutdown = true;
} else {
list.add(line);
}
}
} catch (final SocketException ex) {
if (!shutdown) {
ex.printStackTrace();
}
} catch (final Exception ex) {
ex.printStackTrace();
} finally {
if (client != null && !client.isClosed()) {
try {
client.setSoLinger(true, 0);
client.shutdownOutput();
client.close();
} catch (final Exception ex) {
System.out.println("Unable to close socket: " + ex.getMessage());
}
}
if (server != null && !server.isClosed()) {
try {
server.close();
} catch (final Exception ex) {
System.out.println("Unable to close server socket: " + ex.getMessage());
}
}
}
}
}
private static class LocalHostResolver extends TcpSocketManager.HostResolver {
public volatile int[] ports;
@Override
public List<InetSocketAddress> resolveHost(String host, int port) throws UnknownHostException {
int[] socketPorts = ports;
List<InetSocketAddress> socketAddresses = new ArrayList<>(ports.length);
InetAddress addr = InetAddress.getLocalHost();
for (int i = 0; i < socketPorts.length; ++i){
socketAddresses.add(new InetSocketAddress(addr, socketPorts[i]));
}
return socketAddresses;
}
}
}