1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 #if defined(_MSC_VER)
18 #pragma warning ( disable: 4231 4251 4275 4786 )
19 #endif
20
21 #define __STDC_CONSTANT_MACROS
22 #include <log4cxx/net/socketappenderskeleton.h>
23 #include <log4cxx/helpers/loglog.h>
24 #include <log4cxx/helpers/optionconverter.h>
25 #include <log4cxx/helpers/stringhelper.h>
26 #include <log4cxx/spi/loggingevent.h>
27 #include <log4cxx/helpers/synchronized.h>
28 #include <log4cxx/helpers/transcoder.h>
29 #include <log4cxx/helpers/bytearrayoutputstream.h>
30
31 using namespace log4cxx;
32 using namespace log4cxx::helpers;
33 using namespace log4cxx::net;
34
SocketAppenderSkeleton(int defaultPort,int reconnectionDelay1)35 SocketAppenderSkeleton::SocketAppenderSkeleton(int defaultPort, int reconnectionDelay1)
36 : remoteHost(),
37 address(),
38 port(defaultPort),
39 reconnectionDelay(reconnectionDelay1),
40 locationInfo(false),
41 thread()
42 {
43 }
44
SocketAppenderSkeleton(InetAddressPtr address1,int port1,int delay)45 SocketAppenderSkeleton::SocketAppenderSkeleton(InetAddressPtr address1, int port1, int delay)
46 :
47 remoteHost(),
48 address(address1),
49 port(port1),
50 reconnectionDelay(delay),
51 locationInfo(false),
52 thread()
53 {
54 remoteHost = this->address->getHostName();
55 }
56
SocketAppenderSkeleton(const LogString & host,int port1,int delay)57 SocketAppenderSkeleton::SocketAppenderSkeleton(const LogString& host, int port1, int delay)
58 : remoteHost(host),
59 address(InetAddress::getByName(host)),
60 port(port1),
61 reconnectionDelay(delay),
62 locationInfo(false),
63 thread()
64 {
65 }
66
~SocketAppenderSkeleton()67 SocketAppenderSkeleton::~SocketAppenderSkeleton()
68 {
69 finalize();
70
71 try
72 {
73 thread.join();
74 }
75 catch (ThreadException& ex)
76 {
77 LogLog::error(LOG4CXX_STR("Error closing socket appender connection thread"), ex);
78 }
79 }
80
activateOptions(Pool & p)81 void SocketAppenderSkeleton::activateOptions(Pool& p)
82 {
83 AppenderSkeleton::activateOptions(p);
84 connect(p);
85 }
86
close()87 void SocketAppenderSkeleton::close()
88 {
89 LOCK_W sync(mutex);
90
91 if (closed)
92 {
93 return;
94 }
95
96 closed = true;
97 cleanUp(pool);
98 thread.interrupt();
99 }
100
connect(Pool & p)101 void SocketAppenderSkeleton::connect(Pool& p)
102 {
103 if (address == 0)
104 {
105 LogLog::error(LogString(LOG4CXX_STR("No remote host is set for Appender named \"")) +
106 name + LOG4CXX_STR("\"."));
107 }
108 else
109 {
110 cleanUp(p);
111
112 try
113 {
114 SocketPtr socket(new Socket(address, port));
115 setSocket(socket, p);
116 }
117 catch (SocketException& e)
118 {
119 LogString msg = LOG4CXX_STR("Could not connect to remote log4cxx server at [")
120 + address->getHostName() + LOG4CXX_STR("].");
121
122 if (reconnectionDelay > 0)
123 {
124 msg += LOG4CXX_STR(" We will try again later. ");
125 }
126
127 fireConnector(); // fire the connector thread
128 LogLog::error(msg, e);
129 }
130 }
131 }
132
setOption(const LogString & option,const LogString & value)133 void SocketAppenderSkeleton::setOption(const LogString& option, const LogString& value)
134 {
135 if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REMOTEHOST"), LOG4CXX_STR("remotehost")))
136 {
137 setRemoteHost(value);
138 }
139 else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port")))
140 {
141 setPort(OptionConverter::toInt(value, getDefaultPort()));
142 }
143 else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
144 {
145 setLocationInfo(OptionConverter::toBoolean(value, false));
146 }
147 else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("RECONNECTIONDELAY"), LOG4CXX_STR("reconnectiondelay")))
148 {
149 setReconnectionDelay(OptionConverter::toInt(value, getDefaultDelay()));
150 }
151 else
152 {
153 AppenderSkeleton::setOption(option, value);
154 }
155 }
156
fireConnector()157 void SocketAppenderSkeleton::fireConnector()
158 {
159 LOCK_W sync(mutex);
160
161 if ( !thread.isAlive() )
162 {
163 LogLog::debug(LOG4CXX_STR("Connector thread not alive: starting monitor."));
164
165 try
166 {
167 thread.run(monitor, this);
168 }
169 catch ( ThreadException& te )
170 {
171 LogLog::error(LOG4CXX_STR("Monitor not started: "), te);
172 }
173 }
174 }
175
monitor(apr_thread_t *,void * data)176 void* LOG4CXX_THREAD_FUNC SocketAppenderSkeleton::monitor(apr_thread_t* /* thread */, void* data)
177 {
178 SocketAppenderSkeleton* socketAppender = (SocketAppenderSkeleton*) data;
179 SocketPtr socket;
180 bool isClosed = socketAppender->closed;
181
182 while (!isClosed)
183 {
184 try
185 {
186 Thread::sleep(socketAppender->reconnectionDelay);
187
188 if (!socketAppender->closed)
189 {
190 LogLog::debug(LogString(LOG4CXX_STR("Attempting connection to "))
191 + socketAppender->address->getHostName());
192 socket = new Socket(socketAppender->address, socketAppender->port);
193 Pool p;
194 socketAppender->setSocket(socket, p);
195 LogLog::debug(LOG4CXX_STR("Connection established. Exiting connector thread."));
196 }
197
198 return NULL;
199 }
200 catch (InterruptedException&)
201 {
202 LogLog::debug(LOG4CXX_STR("Connector interrupted. Leaving loop."));
203 return NULL;
204 }
205 catch (ConnectException&)
206 {
207 LogLog::debug(LOG4CXX_STR("Remote host ")
208 + socketAppender->address->getHostName()
209 + LOG4CXX_STR(" refused connection."));
210 }
211 catch (IOException& e)
212 {
213 LogString exmsg;
214 log4cxx::helpers::Transcoder::decode(e.what(), exmsg);
215
216 LogLog::debug(((LogString) LOG4CXX_STR("Could not connect to "))
217 + socketAppender->address->getHostName()
218 + LOG4CXX_STR(". Exception is ")
219 + exmsg);
220 }
221
222 isClosed = socketAppender->closed;
223 }
224
225 LogLog::debug(LOG4CXX_STR("Exiting Connector.run() method."));
226 return NULL;
227 }
228