1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.net;
18
19 import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
20 import org.apache.logging.log4j.core.appender.ManagerFactory;
21 import org.apache.logging.log4j.core.appender.OutputStreamManager;
22
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.net.ConnectException;
26 import java.net.InetAddress;
27 import java.net.Socket;
28 import java.net.UnknownHostException;
29
30
31
32
33 public class TCPSocketManager extends AbstractSocketManager {
34
35
36
37 public static final int DEFAULT_RECONNECTION_DELAY = 30000;
38
39
40
41 private static final int DEFAULT_PORT = 4560;
42
43 private static final TCPSocketManagerFactory factory = new TCPSocketManagerFactory();
44
45 private final int reconnectionDelay;
46
47 private Reconnector connector = null;
48
49 private Socket socket;
50
51 private final boolean retry;
52
53
54
55
56
57
58
59
60
61
62
63 public TCPSocketManager(String name, OutputStream os, Socket sock, InetAddress addr, String host, int port,
64 int delay) {
65 super(name, os, addr, host, port);
66 this.reconnectionDelay = delay;
67 this.socket = sock;
68 retry = delay > 0;
69 }
70
71
72
73
74
75
76
77
78 public static TCPSocketManager getSocketManager(String host, int port, int delay) {
79 if (host == null || host.length() == 0) {
80 throw new IllegalArgumentException("A host name is required");
81 }
82 if (port <= 0) {
83 port = DEFAULT_PORT;
84 }
85 if (delay == 0) {
86 delay = DEFAULT_RECONNECTION_DELAY;
87 }
88 return (TCPSocketManager) getManager("TCP:" + host + ":" + port, new FactoryData(host, port, delay), factory);
89 }
90
91 @Override
92 protected synchronized void write(byte[] bytes, int offset, int length) {
93 try {
94 getOutputStream().write(bytes, offset, length);
95 socket.setSendBufferSize(length);
96 } catch (IOException ex) {
97 if (retry && connector == null) {
98 connector = new Reconnector(this);
99 connector.setDaemon(true);
100 connector.setPriority(Thread.MIN_PRIORITY);
101 connector.start();
102 }
103 String msg = "Error writing to " + getName();
104 throw new AppenderRuntimeException(msg, ex);
105 }
106 }
107
108 @Override
109 protected synchronized void close() {
110 super.close();
111 if (connector != null) {
112 connector.shutdown();
113 connector.interrupt();
114 connector = null;
115 }
116 }
117
118
119
120
121 private class Reconnector extends Thread {
122
123 private boolean shutdown = false;
124
125 private final Object owner;
126
127 public Reconnector(OutputStreamManager owner) {
128 this.owner = owner;
129 }
130
131 public void shutdown() {
132 shutdown = true;
133 }
134
135 @Override
136 public void run() {
137 while (!shutdown) {
138 try {
139 sleep(reconnectionDelay);
140 Socket sock = new Socket(address, port);
141 OutputStream newOS = sock.getOutputStream();
142 synchronized (owner) {
143 try {
144 getOutputStream().close();
145 } catch (IOException ioe) {
146
147 }
148
149 setOutputStream(newOS);
150 socket = sock;
151 connector = null;
152 }
153 LOGGER.debug("Connection to " + host + ":" + port + " reestablished.");
154 } catch (InterruptedException ie) {
155 LOGGER.debug("Reconnection interrupted.");
156 } catch (ConnectException ex) {
157 LOGGER.debug(host + ":" + port + " refused connection");
158 } catch (IOException ioe) {
159 LOGGER.debug("Unable to reconnect to " + host + ":" + port);
160 }
161 }
162 }
163 }
164
165
166
167
168 private static class FactoryData {
169 private String host;
170 private int port;
171 private int delay;
172
173 public FactoryData(String host, int port, int delay) {
174 this.host = host;
175 this.port = port;
176 this.delay = delay;
177 }
178 }
179
180
181
182
183 private static class TCPSocketManagerFactory implements ManagerFactory<TCPSocketManager, FactoryData> {
184
185 public TCPSocketManager createManager(String name, FactoryData data) {
186 try {
187 InetAddress address = InetAddress.getByName(data.host);
188 Socket socket = new Socket(data.host, data.port);
189 OutputStream os = socket.getOutputStream();
190 return new TCPSocketManager(name, os, socket, address, data.host, data.port, data.delay);
191 } catch (UnknownHostException ex) {
192 LOGGER.error("Could not find address of " + data.host, ex);
193 } catch (IOException ex) {
194 LOGGER.error("TCPSocketManager (" + name + ") " + ex);
195 }
196 return null;
197 }
198 }
199 }