Coverage Report

Created: 2025-07-01 06:08

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