Coverage Report

Created: 2026-06-15 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/socketappenderskeleton.cpp
Line
Count
Source
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
18
#define __STDC_CONSTANT_MACROS
19
#include <log4cxx/net/socketappenderskeleton.h>
20
#include <log4cxx/helpers/loglog.h>
21
#include <log4cxx/helpers/charsetencoder.h>
22
#include <log4cxx/helpers/optionconverter.h>
23
#include <log4cxx/helpers/stringhelper.h>
24
#include <log4cxx/spi/loggingevent.h>
25
#include <log4cxx/helpers/threadutility.h>
26
#include <log4cxx/helpers/transcoder.h>
27
#include <log4cxx/helpers/bytearrayoutputstream.h>
28
#include <log4cxx/helpers/outputstreamwriter.h>
29
#include <log4cxx/helpers/socketoutputstream.h>
30
#include <log4cxx/helpers/threadutility.h>
31
#include <log4cxx/private/socketappenderskeleton_priv.h>
32
#include <functional>
33
#include <chrono>
34
35
using namespace LOG4CXX_NS;
36
using namespace LOG4CXX_NS::helpers;
37
using namespace LOG4CXX_NS::net;
38
39
0
#define _priv static_cast<SocketAppenderSkeletonPriv*>(m_priv.get())
40
41
SocketAppenderSkeleton::SocketAppenderSkeleton(int defaultPort, int reconnectionDelay)
42
0
  : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(defaultPort, reconnectionDelay))
43
0
{
44
0
}
45
46
#if LOG4CXX_ABI_VERSION <= 15
47
SocketAppenderSkeleton::SocketAppenderSkeleton(helpers::InetAddressPtr address, int port, int reconnectionDelay)
48
#else
49
SocketAppenderSkeleton::SocketAppenderSkeleton(const helpers::InetAddressPtr& address, int port, int reconnectionDelay)
50
#endif
51
0
  : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(address, port, reconnectionDelay))
52
0
{
53
0
}
54
55
SocketAppenderSkeleton::SocketAppenderSkeleton(const LogString& host, int port, int reconnectionDelay)
56
0
  : AppenderSkeleton(std::make_unique<SocketAppenderSkeletonPriv>(host, port, reconnectionDelay))
57
0
{
58
0
}
59
60
SocketAppenderSkeleton::SocketAppenderSkeleton(std::unique_ptr<SocketAppenderSkeletonPriv> priv)
61
0
  :  AppenderSkeleton (std::move(priv))
62
0
{
63
0
}
64
65
SocketAppenderSkeleton::~SocketAppenderSkeleton()
66
0
{
67
0
}
68
69
void SocketAppenderSkeleton::activateOptions( LOG4CXX_ACTIVATE_OPTIONS_FORMAL_PARAMETERS )
70
0
{
71
0
  _priv->connect();
72
0
}
73
74
void SocketAppenderSkeleton::close()
75
0
{
76
0
  if (_priv->setClosed())
77
0
    _priv->close();
78
0
}
79
80
void SocketAppenderSkeleton::SocketAppenderSkeletonPriv::connect()
81
0
{
82
0
  if (this->address == 0)
83
0
  {
84
0
    LogLog::error(LogString(LOG4CXX_STR("No remote host is set for Appender named \"")) +
85
0
      this->name + LOG4CXX_STR("\"."));
86
0
  }
87
0
  else
88
0
  {
89
0
    this->close();
90
91
0
    try
92
0
    {
93
0
      if (LogLog::isDebugEnabled())
94
0
      {
95
0
        LogString msg(LOG4CXX_STR("Connecting to [")
96
0
          + this->address->toString() + LOG4CXX_STR(":"));
97
0
        StringHelper::toString(this->port, msg);
98
0
        msg += LOG4CXX_STR("].");
99
0
        LogLog::debug(msg);
100
0
      }
101
0
      this->setOutputSink(Socket::create(this->address, this->port, this->socketSubclass));
102
0
    }
103
0
    catch (SocketException& e)
104
0
    {
105
0
      LogString msg = LOG4CXX_STR("Could not connect to [")
106
0
        + this->address->toString() + LOG4CXX_STR(":");
107
0
      StringHelper::toString(this->port, msg);
108
0
      msg += LOG4CXX_STR("].");
109
110
0
      this->fireConnector(); // fire the connector thread
111
0
      LogLog::warn(msg, e);
112
0
    }
113
0
  }
114
0
}
115
116
void SocketAppenderSkeleton::setOption(const LogString& option, const LogString& value)
117
0
{
118
0
  if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("REMOTEHOST"), LOG4CXX_STR("remotehost")))
119
0
  {
120
0
    setRemoteHost(value);
121
0
  }
122
0
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PORT"), LOG4CXX_STR("port")))
123
0
  {
124
0
    setPort(OptionConverter::toInt(value, getDefaultPort()));
125
0
  }
126
0
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
127
0
  {
128
0
    setLocationInfo(OptionConverter::toBoolean(value, false));
129
0
  }
130
0
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("RECONNECTIONDELAY"), LOG4CXX_STR("reconnectiondelay")))
131
0
  {
132
0
    setReconnectionDelay(OptionConverter::toInt(value, getDefaultDelay()));
133
0
  }
134
#if 15 < LOG4CXX_ABI_VERSION
135
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SOCKETSUBCLASS"), LOG4CXX_STR("socketsubclass")))
136
  {
137
    setSocketSubclass(value);
138
  }
139
#endif
140
0
  else
141
0
  {
142
0
    AppenderSkeleton::setOption(option, value);
143
0
  }
144
0
}
145
146
void SocketAppenderSkeleton::SocketAppenderSkeletonPriv::fireConnector()
147
0
{
148
0
  std::lock_guard<std::recursive_mutex> lock(this->mutex);
149
0
  if (this->taskName.empty())
150
0
  {
151
0
    this->taskName = this->name + LOG4CXX_STR(":")
152
0
      + this->address->toString() + LOG4CXX_STR(":");
153
0
    StringHelper::toString(this->port, this->taskName);
154
0
  }
155
0
  auto taskManager = ThreadUtility::instancePtr();
156
0
  if (!taskManager->value().hasPeriodicTask(this->taskName))
157
0
  {
158
0
    if (LogLog::isDebugEnabled())
159
0
    {
160
0
      LogString msg(LOG4CXX_STR("Waiting "));
161
0
      StringHelper::toString(this->reconnectionDelay, msg);
162
0
      msg += LOG4CXX_STR(" ms before retrying [")
163
0
        + this->address->toString() + LOG4CXX_STR(":");
164
0
      StringHelper::toString(this->port, msg);
165
0
      msg += LOG4CXX_STR("].");
166
0
      LogLog::debug(msg);
167
0
    }
168
0
    taskManager->value().addPeriodicTask(this->taskName
169
0
      , std::bind(&SocketAppenderSkeleton::SocketAppenderSkeletonPriv::retryConnect, this)
170
0
      , std::chrono::milliseconds(this->reconnectionDelay)
171
0
      );
172
0
  }
173
0
  this->taskManager = taskManager;
174
0
}
175
176
#if LOG4CXX_ABI_VERSION <= 15
177
void SocketAppenderSkeleton::fireConnector()
178
0
{
179
0
  _priv->fireConnector();
180
0
}
181
#endif
182
183
void SocketAppenderSkeleton::SocketAppenderSkeletonPriv::retryConnect()
184
0
{
185
0
  if (this->closed)
186
0
  {
187
0
    if (auto pManager = this->taskManager.lock())
188
0
      pManager->value().removePeriodicTask(this->taskName);
189
0
  }
190
0
  else
191
0
  {
192
0
    try
193
0
    {
194
0
      if (LogLog::isDebugEnabled())
195
0
      {
196
0
        LogString msg(LOG4CXX_STR("Attempting connection to [")
197
0
          + this->address->toString() + LOG4CXX_STR(":"));
198
0
        StringHelper::toString(this->port, msg);
199
0
        msg += LOG4CXX_STR("].");
200
0
        LogLog::debug(msg);
201
0
      }
202
0
      this->setOutputSink(Socket::create(this->address, this->port, this->socketSubclass));
203
0
      if (LogLog::isDebugEnabled())
204
0
      {
205
0
        LogString msg(LOG4CXX_STR("Connection established to [")
206
0
          + this->address->toString() + LOG4CXX_STR(":"));
207
0
        StringHelper::toString(this->port, msg);
208
0
        msg += LOG4CXX_STR("].");
209
0
        LogLog::debug(msg);
210
0
      }
211
0
      if (auto pManager = this->taskManager.lock())
212
0
        pManager->value().removePeriodicTask(this->taskName);
213
0
      return;
214
0
    }
215
0
    catch (ConnectException& e)
216
0
    {
217
0
      LogLog::warn(LOG4CXX_STR("Remote host ")
218
0
        + this->address->toString()
219
0
        + LOG4CXX_STR(" refused connection."), e);
220
0
    }
221
0
    catch (IOException& e)
222
0
    {
223
0
      LogString msg(LOG4CXX_STR("Could not connect to [")
224
0
        + this->address->toString() + LOG4CXX_STR(":"));
225
0
      StringHelper::toString(this->port, msg);
226
0
      msg += LOG4CXX_STR("].");
227
0
      LogLog::warn(msg, e);
228
0
    }
229
230
0
    if (this->reconnectionDelay > 0)
231
0
    {
232
0
      if (LogLog::isDebugEnabled())
233
0
      {
234
0
        LogString msg(LOG4CXX_STR("Waiting "));
235
0
        StringHelper::toString(this->reconnectionDelay, msg);
236
0
        msg += LOG4CXX_STR(" ms before retrying [")
237
0
          + this->address->toString() + LOG4CXX_STR(":");
238
0
        StringHelper::toString(this->port, msg);
239
0
        msg += LOG4CXX_STR("].");
240
0
        LogLog::debug(msg);
241
0
      }
242
0
    }
243
0
  }
244
0
}
245
246
void SocketAppenderSkeleton::SocketAppenderSkeletonPriv::setOutputSink(const SocketPtr& socket)
247
0
{
248
0
  OutputStreamPtr os = std::make_shared<SocketOutputStream>(socket);
249
0
  auto charset = CharsetEncoder::getUTF8Encoder();
250
0
  this->outputSink = std::make_shared<OutputStreamWriter>(os, charset);
251
0
}
252
253
void SocketAppenderSkeleton::SocketAppenderSkeletonPriv::close()
254
0
{
255
0
  if (this->taskName.empty())
256
0
    ;
257
0
  else if (auto pManager = this->taskManager.lock())
258
0
    pManager->value().removePeriodicTask(this->taskName);
259
0
  if (this->outputSink)
260
0
  {
261
0
    try
262
0
    {
263
0
      this->outputSink->close();
264
0
      this->outputSink.reset();
265
0
    }
266
0
    catch (std::exception&)
267
0
    {
268
0
    }
269
0
  }
270
0
}
271
272
void SocketAppenderSkeleton::setRemoteHost(const LogString& host)
273
0
{
274
0
  _priv->address = helpers::InetAddress::getByName(host);
275
0
  _priv->remoteHost.assign(host);
276
0
}
277
278
const LogString& SocketAppenderSkeleton::getRemoteHost() const
279
0
{
280
0
  return _priv->remoteHost;
281
0
}
282
283
void SocketAppenderSkeleton::setPort(int port1)
284
0
{
285
0
  _priv->port = port1;
286
0
}
287
288
int SocketAppenderSkeleton::getPort() const
289
0
{
290
0
  return _priv->port;
291
0
}
292
293
void SocketAppenderSkeleton::setLocationInfo(bool locationInfo1)
294
0
{
295
0
  _priv->locationInfo = locationInfo1;
296
0
}
297
298
bool SocketAppenderSkeleton::getLocationInfo() const
299
0
{
300
0
  return _priv->locationInfo;
301
0
}
302
303
void SocketAppenderSkeleton::setReconnectionDelay(int reconnectionDelay1)
304
0
{
305
0
  _priv->reconnectionDelay = reconnectionDelay1;
306
0
  if (_priv->taskName.empty())
307
0
    return;
308
0
  auto pManager = _priv->taskManager.lock();
309
0
  if (pManager && pManager->value().hasPeriodicTask(_priv->taskName))
310
0
  {
311
0
    pManager->value().removePeriodicTask(_priv->taskName);
312
0
    pManager->value().addPeriodicTask(_priv->taskName
313
0
      , std::bind(&SocketAppenderSkeleton::SocketAppenderSkeletonPriv::retryConnect, _priv)
314
0
      , std::chrono::milliseconds(_priv->reconnectionDelay)
315
0
      );
316
0
  }
317
0
}
318
319
int SocketAppenderSkeleton::getReconnectionDelay() const
320
0
{
321
0
  return _priv->reconnectionDelay;
322
0
}
323
324
#if 15 < LOG4CXX_ABI_VERSION
325
void SocketAppenderSkeleton::setSocketSubclass(const LogString& newValue)
326
{
327
  _priv->socketSubclass = newValue;
328
}
329
330
const LogString& SocketAppenderSkeleton::getSocketSubclass() const
331
{
332
  return _priv->socketSubclass;
333
}
334
#endif