Coverage Report

Created: 2026-05-30 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/syslogappender.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
#include <log4cxx/net/syslogappender.h>
19
#include <log4cxx/helpers/loglog.h>
20
#include <log4cxx/helpers/stringhelper.h>
21
#include <log4cxx/helpers/datagramsocket.h>
22
#include <log4cxx/spi/loggingevent.h>
23
#include <log4cxx/level.h>
24
#include <log4cxx/helpers/transcoder.h>
25
#include <log4cxx/helpers/optionconverter.h>
26
#if !defined(LOG4CXX)
27
  #define LOG4CXX 1
28
#endif
29
#include <apr_strings.h>
30
#include <log4cxx/private/syslogappender_priv.h>
31
32
0
#define LOG_UNDEF -1
33
34
using namespace LOG4CXX_NS;
35
using namespace LOG4CXX_NS::helpers;
36
using namespace LOG4CXX_NS::net;
37
38
IMPLEMENT_LOG4CXX_OBJECT(SyslogAppender)
39
40
0
#define _priv static_cast<SyslogAppenderPriv*>(m_priv.get())
41
42
SyslogAppender::SyslogAppender()
43
0
  : AppenderSkeleton (std::make_unique<SyslogAppenderPriv>())
44
0
{
45
0
  this->initSyslogFacilityStr();
46
47
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender()
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender()
48
49
SyslogAppender::SyslogAppender(const LayoutPtr& layout1,
50
  int syslogFacility1)
51
0
  : AppenderSkeleton (std::make_unique<SyslogAppenderPriv>(layout1, syslogFacility1))
52
0
{
53
0
  this->initSyslogFacilityStr();
54
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, int)
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, int)
55
56
SyslogAppender::SyslogAppender(const LayoutPtr& layout1,
57
  const LogString& syslogHost1, int syslogFacility1)
58
0
  : AppenderSkeleton (std::make_unique<SyslogAppenderPriv>(layout1, syslogHost1, syslogFacility1))
59
0
{
60
0
  this->initSyslogFacilityStr();
61
0
  setSyslogHost(syslogHost1);
62
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, int)
Unexecuted instantiation: log4cxx::net::SyslogAppender::SyslogAppender(std::__1::shared_ptr<log4cxx::Layout> const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, int)
63
64
SyslogAppender::~SyslogAppender()
65
0
{
66
0
  _priv->setClosed();
67
0
}
68
69
/** Release any resources held by this SyslogAppender.*/
70
void SyslogAppender::close()
71
0
{
72
0
  _priv->setClosed();
73
74
0
  if (_priv->sw)
75
0
  {
76
0
    _priv->sw = nullptr;
77
0
  }
78
0
}
79
80
void SyslogAppender::initSyslogFacilityStr()
81
0
{
82
0
  _priv->facilityStr = getFacilityString(_priv->syslogFacility);
83
84
0
  if (_priv->facilityStr.empty())
85
0
  {
86
0
    LogString msg(LOG4CXX_STR("\""));
87
0
    StringHelper::toString(_priv->syslogFacility, msg);
88
0
    msg.append(LOG4CXX_STR("\" is an unknown syslog facility. Defaulting to \"USER\"."));
89
0
    LogLog::warn(msg);
90
0
    _priv->syslogFacility = LOG_USER;
91
0
    _priv->facilityStr = LOG4CXX_STR("user:");
92
0
  }
93
0
  else
94
0
  {
95
0
    _priv->facilityStr += LOG4CXX_STR(":");
96
0
  }
97
0
}
98
99
/**
100
Returns the specified syslog facility as a lower-case String,
101
e.g. "kern", "user", etc.
102
*/
103
LogString SyslogAppender::getFacilityString(
104
  int syslogFacility)
105
0
{
106
0
  switch (syslogFacility)
107
0
  {
108
0
    case LOG_KERN:
109
0
      return LOG4CXX_STR("kern");
110
111
0
    case LOG_USER:
112
0
      return LOG4CXX_STR("user");
113
114
0
    case LOG_MAIL:
115
0
      return LOG4CXX_STR("mail");
116
117
0
    case LOG_DAEMON:
118
0
      return LOG4CXX_STR("daemon");
119
120
0
    case LOG_AUTH:
121
0
      return LOG4CXX_STR("auth");
122
123
0
    case LOG_SYSLOG:
124
0
      return LOG4CXX_STR("syslog");
125
126
0
    case LOG_LPR:
127
0
      return LOG4CXX_STR("lpr");
128
129
0
    case LOG_NEWS:
130
0
      return LOG4CXX_STR("news");
131
132
0
    case LOG_UUCP:
133
0
      return LOG4CXX_STR("uucp");
134
135
0
    case LOG_CRON:
136
0
      return LOG4CXX_STR("cron");
137
0
#ifdef LOG_AUTHPRIV
138
139
0
    case LOG_AUTHPRIV:
140
0
      return LOG4CXX_STR("authpriv");
141
0
#endif
142
0
#ifdef LOG_FTP
143
144
0
    case LOG_FTP:
145
0
      return LOG4CXX_STR("ftp");
146
0
#endif
147
148
0
    case LOG_LOCAL0:
149
0
      return LOG4CXX_STR("local0");
150
151
0
    case LOG_LOCAL1:
152
0
      return LOG4CXX_STR("local1");
153
154
0
    case LOG_LOCAL2:
155
0
      return LOG4CXX_STR("local2");
156
157
0
    case LOG_LOCAL3:
158
0
      return LOG4CXX_STR("local3");
159
160
0
    case LOG_LOCAL4:
161
0
      return LOG4CXX_STR("local4");
162
163
0
    case LOG_LOCAL5:
164
0
      return LOG4CXX_STR("local5");
165
166
0
    case LOG_LOCAL6:
167
0
      return LOG4CXX_STR("local6");
168
169
0
    case LOG_LOCAL7:
170
0
      return LOG4CXX_STR("local7");
171
172
0
    default:
173
0
      return LogString();
174
0
  }
175
0
}
176
177
int SyslogAppender::getFacility(
178
  const LogString& s)
179
0
{
180
0
  if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("KERN"), LOG4CXX_STR("kern")))
181
0
  {
182
0
    return LOG_KERN;
183
0
  }
184
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("USER"), LOG4CXX_STR("user")))
185
0
  {
186
0
    return LOG_USER;
187
0
  }
188
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("MAIL"), LOG4CXX_STR("mail")))
189
0
  {
190
0
    return LOG_MAIL;
191
0
  }
192
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("DAEMON"), LOG4CXX_STR("daemon")))
193
0
  {
194
0
    return LOG_DAEMON;
195
0
  }
196
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("AUTH"), LOG4CXX_STR("auth")))
197
0
  {
198
0
    return LOG_AUTH;
199
0
  }
200
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("SYSLOG"), LOG4CXX_STR("syslog")))
201
0
  {
202
0
    return LOG_SYSLOG;
203
0
  }
204
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LPR"), LOG4CXX_STR("lpr")))
205
0
  {
206
0
    return LOG_LPR;
207
0
  }
208
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("NEWS"), LOG4CXX_STR("news")))
209
0
  {
210
0
    return LOG_NEWS;
211
0
  }
212
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("UUCP"), LOG4CXX_STR("uucp")))
213
0
  {
214
0
    return LOG_UUCP;
215
0
  }
216
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("CRON"), LOG4CXX_STR("cron")))
217
0
  {
218
0
    return LOG_CRON;
219
0
  }
220
221
0
#ifdef LOG_AUTHPRIV
222
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("AUTHPRIV"), LOG4CXX_STR("authpriv")))
223
0
  {
224
0
    return LOG_AUTHPRIV;
225
0
  }
226
227
0
#endif
228
0
#ifdef LOG_FTP
229
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("FTP"), LOG4CXX_STR("ftp")))
230
0
  {
231
0
    return LOG_FTP;
232
0
  }
233
234
0
#endif
235
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL0"), LOG4CXX_STR("local0")))
236
0
  {
237
0
    return LOG_LOCAL0;
238
0
  }
239
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL1"), LOG4CXX_STR("local1")))
240
0
  {
241
0
    return LOG_LOCAL1;
242
0
  }
243
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL2"), LOG4CXX_STR("local2")))
244
0
  {
245
0
    return LOG_LOCAL2;
246
0
  }
247
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL3"), LOG4CXX_STR("local3")))
248
0
  {
249
0
    return LOG_LOCAL3;
250
0
  }
251
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL4"), LOG4CXX_STR("local4")))
252
0
  {
253
0
    return LOG_LOCAL4;
254
0
  }
255
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL5"), LOG4CXX_STR("local5")))
256
0
  {
257
0
    return LOG_LOCAL5;
258
0
  }
259
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL6"), LOG4CXX_STR("local6")))
260
0
  {
261
0
    return LOG_LOCAL6;
262
0
  }
263
0
  else if (StringHelper::equalsIgnoreCase(s, LOG4CXX_STR("LOCAL7"), LOG4CXX_STR("local7")))
264
0
  {
265
0
    return LOG_LOCAL7;
266
0
  }
267
0
  else
268
0
  {
269
0
    return LOG_UNDEF;
270
0
  }
271
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::getFacility(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cxx::net::SyslogAppender::getFacility(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
272
273
void SyslogAppender::append( LOG4CXX_APPEND_FORMAL_PARAMETERS )
274
0
{
275
0
  if  (!isAsSevereAsThreshold(event->getLevel()))
276
0
  {
277
0
    return;
278
0
  }
279
280
0
  LogString msg;
281
0
  std::string encoded;
282
0
  _priv->layout->format(msg, event);
283
284
0
  Transcoder::encode(msg, encoded);
285
286
  // Split up the message if it is over maxMessageLength in size.
287
  // According to RFC 3164, the max message length is 1024, however
288
  // newer systems(such as syslog-ng) can go up to 8k in size for their
289
  // messages.  We will append (x/y) at the end of each message
290
  // to indicate how far through the message we are
291
0
  std::vector<LogString> packets;
292
293
0
  if ( msg.size() > _priv->maxMessageLength )
294
0
  {
295
0
    LogString::iterator start = msg.begin();
296
297
0
    while ( start != msg.end() )
298
0
    {
299
0
      LogString::iterator end = start + _priv->maxMessageLength - 12;
300
301
0
      if ( end > msg.end() )
302
0
      {
303
0
        end = msg.end();
304
0
      }
305
306
0
      LogString newMsg = LogString( start, end );
307
0
      packets.push_back( newMsg );
308
0
      start = end;
309
0
    }
310
311
0
    int current = 1;
312
313
0
    for (auto& item : packets)
314
0
    {
315
0
      char buf[12];
316
0
      apr_snprintf( buf, sizeof(buf), "(%d/%d)", current, (int)packets.size() );
317
0
      LOG4CXX_DECODE_CHAR(str, buf);
318
0
      item.append( str );
319
0
      ++current;
320
0
    }
321
0
  }
322
0
  else
323
0
  {
324
0
    packets.push_back( msg );
325
0
  }
326
327
  // On the local host, we can directly use the system function 'syslog'
328
  // if it is available
329
0
#if LOG4CXX_HAVE_SYSLOG
330
331
0
  if (_priv->sw == 0)
332
0
  {
333
0
    for (auto const& item : packets)
334
0
    {
335
      // use of "%s" to avoid a security hole
336
0
      LOG4CXX_ENCODE_CHAR(itemStr, item);
337
0
      ::syslog(_priv->syslogFacility | event->getLevel()->getSyslogEquivalent(),
338
0
        "%s", itemStr.c_str());
339
0
    }
340
341
0
    return;
342
0
  }
343
344
0
#endif
345
346
  // We must not attempt to append if sw is null.
347
0
  if (_priv->sw == 0)
348
0
  {
349
0
    _priv->errorHandler->error(LOG4CXX_STR("No syslog host is set for SyslogAppedender named \"") +
350
0
      _priv->name + LOG4CXX_STR("\"."));
351
0
    return;
352
0
  }
353
354
0
  for (auto const& item : packets)
355
0
  {
356
0
    LogString sbuf(1, 0x3C /* '<' */);
357
0
    StringHelper::toString((_priv->syslogFacility | event->getLevel()->getSyslogEquivalent()), sbuf);
358
0
    sbuf.append(1, (logchar) 0x3E /* '>' */);
359
360
0
    if (_priv->facilityPrinting)
361
0
    {
362
0
      sbuf.append(_priv->facilityStr);
363
0
    }
364
365
0
    sbuf.append(item);
366
0
    _priv->sw->write(sbuf);
367
0
  }
368
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::append(std::__1::shared_ptr<log4cxx::spi::LoggingEvent> const&, log4cxx::helpers::Pool&)
Unexecuted instantiation: log4cxx::net::SyslogAppender::append(std::__1::shared_ptr<log4cxx::spi::LoggingEvent> const&, log4cxx::helpers::Pool&)
369
370
#if LOG4CXX_ABI_VERSION <= 15
371
void SyslogAppender::activateOptions(Pool&)
372
0
{
373
0
}
374
#endif
375
376
void SyslogAppender::setOption(const LogString& option, const LogString& value)
377
0
{
378
0
  if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SYSLOGHOST"), LOG4CXX_STR("sysloghost")))
379
0
  {
380
0
    setSyslogHost(value);
381
0
  }
382
0
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FACILITY"), LOG4CXX_STR("facility")))
383
0
  {
384
0
    setFacility(value);
385
0
  }
386
0
  else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("MAXMESSAGELENGTH"), LOG4CXX_STR("maxmessagelength")))
387
0
  {
388
0
    setMaxMessageLength(OptionConverter::toInt(value, 1024));
389
0
  }
390
0
  else
391
0
  {
392
0
    AppenderSkeleton::setOption(option, value);
393
0
  }
394
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::setOption(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cxx::net::SyslogAppender::setOption(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
395
396
void SyslogAppender::setSyslogHost(const LogString& syslogHost1)
397
0
{
398
0
  if (_priv->sw != 0)
399
0
  {
400
0
    _priv->sw = nullptr;
401
0
  }
402
403
0
  LogString slHost = syslogHost1;
404
0
  int slHostPort = -1;
405
406
0
  LogString::size_type colonPos = 0;
407
0
  colonPos = slHost.rfind(':');
408
409
0
  if (colonPos != LogString::npos)
410
0
  {
411
0
    slHostPort = StringHelper::toInt(slHost.substr(colonPos + 1));
412
    // Erase the :port part of the host name
413
0
    slHost.erase( colonPos );
414
0
  }
415
416
  // On the local host, we can directly use the system function 'syslog'
417
  // if it is available (cf. append)
418
0
#if LOG4CXX_HAVE_SYSLOG
419
420
0
  if (syslogHost1 != LOG4CXX_STR("localhost") && syslogHost1 != LOG4CXX_STR("127.0.0.1")
421
0
    && !syslogHost1.empty())
422
0
#endif
423
0
  {
424
0
    if (slHostPort >= 0)
425
0
    {
426
0
      _priv->sw = std::make_unique<SyslogWriter>(slHost, slHostPort);
427
0
    }
428
0
    else
429
0
    {
430
0
      _priv->sw = std::make_unique<SyslogWriter>(slHost);
431
0
    }
432
0
  }
433
434
0
  _priv->syslogHost = slHost;
435
0
  _priv->syslogHostPort = slHostPort;
436
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::setSyslogHost(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cxx::net::SyslogAppender::setSyslogHost(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
437
438
439
void SyslogAppender::setFacility(const LogString& facilityName)
440
0
{
441
0
  if (facilityName.empty())
442
0
  {
443
0
    return;
444
0
  }
445
446
0
  _priv->syslogFacility = getFacility(facilityName);
447
448
0
  if (_priv->syslogFacility == LOG_UNDEF)
449
0
  {
450
0
    LogLog::warn(LOG4CXX_STR("[") + facilityName +
451
0
      LOG4CXX_STR("] is an unknown syslog facility. Defaulting to [USER]."));
452
0
    _priv->syslogFacility = LOG_USER;
453
0
  }
454
455
0
  this->initSyslogFacilityStr();
456
0
}
Unexecuted instantiation: log4cxx::net::SyslogAppender::setFacility(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cxx::net::SyslogAppender::setFacility(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
457
458
const LogString& SyslogAppender::getSyslogHost() const
459
0
{
460
0
  return _priv->syslogHost;
461
0
}
462
463
LogString SyslogAppender::getFacility() const
464
0
{
465
0
  return getFacilityString(_priv->syslogFacility);
466
0
}
467
468
void SyslogAppender::setFacilityPrinting(bool facilityPrinting1)
469
0
{
470
0
  _priv->facilityPrinting = facilityPrinting1;
471
0
}
472
473
bool SyslogAppender::getFacilityPrinting() const
474
0
{
475
0
  return _priv->facilityPrinting;
476
0
}
477
478
void SyslogAppender::setMaxMessageLength(int maxMessageLength1)
479
0
{
480
  // append() reserves 12 characters per chunk for an "(x/y)" sequence suffix.
481
  // A value at or below the suffix size produces a zero-length chunk (causing
482
  // an infinite split loop) or an iterator computed before msg.begin() (UB).
483
0
  static const int MIN_MAX_MESSAGE_LENGTH = 13;
484
0
  if (maxMessageLength1 < MIN_MAX_MESSAGE_LENGTH)
485
0
  {
486
0
    LogLog::warn(LOG4CXX_STR("SyslogAppender MaxMessageLength is too small. Using the default value."));
487
0
    maxMessageLength1 = 1024;
488
0
  }
489
0
  _priv->maxMessageLength = maxMessageLength1;
490
0
}
491
492
int SyslogAppender::getMaxMessageLength() const
493
0
{
494
0
  return _priv->maxMessageLength;
495
0
}
496