Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/log4cplus/src/syslogappender.cxx
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    syslogappender.cxx
3
// Created: 6/2001
4
// Author:  Tad E. Smith
5
//
6
// Copyright 2001-2017 Tad E. Smith
7
//
8
// Licensed under the Apache License, Version 2.0 (the "License");
9
// you may not use this file except in compliance with the License.
10
// You may obtain a copy of the License at
11
//
12
//     http://www.apache.org/licenses/LICENSE-2.0
13
//
14
// Unless required by applicable law or agreed to in writing, software
15
// distributed under the License is distributed on an "AS IS" BASIS,
16
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
// See the License for the specific language governing permissions and
18
// limitations under the License.
19
20
#include <log4cplus/syslogappender.h>
21
#include <log4cplus/streams.h>
22
#include <log4cplus/helpers/loglog.h>
23
#include <log4cplus/helpers/property.h>
24
#include <log4cplus/helpers/stringhelper.h>
25
#include <log4cplus/spi/loggingevent.h>
26
#include <log4cplus/internal/internal.h>
27
#include <log4cplus/internal/env.h>
28
#include <log4cplus/thread/syncprims-pub-impl.h>
29
#include <cstring>
30
31
#if defined (LOG4CPLUS_HAVE_SYSLOG_H)
32
#include <syslog.h>
33
34
#else // LOG4CPLUS_HAVE_SYSLOG_H
35
36
// The following bits were derived from SUSv4 documentation and
37
// RFC5424 document.
38
39
// priority codes
40
#define LOG_EMERG   0
41
#define LOG_ALERT   1
42
#define LOG_CRIT    2
43
#define LOG_ERR     3
44
#define LOG_WARNING 4
45
#define LOG_NOTICE  5
46
#define LOG_INFO    6
47
#define LOG_DEBUG   7
48
49
// facility codes
50
#define LOG_KERN      (0 << 3)
51
#define LOG_USER      (1 << 3)
52
#define LOG_MAIL      (2 << 3)
53
#define LOG_DAEMON    (3 << 3)
54
#define LOG_AUTH      (4 << 3)
55
#define LOG_SYSLOG    (5 << 3)
56
#define LOG_LPR       (6 << 3)
57
#define LOG_NEWS      (7 << 3)
58
#define LOG_UUCP      (8 << 3)
59
#define LOG_CRON      (9 << 3)
60
#define LOG_AUTHPRIV (10 << 3)
61
#define LOG_FTP      (11 << 3)
62
#define LOG_NTP      (12 << 3)
63
#define LOG_SECURITY (13 << 3)
64
#define LOG_CONSOLE  (14 << 3)
65
// (15 << 3) is missing here
66
#define LOG_LOCAL0   (16 << 3)
67
#define LOG_LOCAL1   (17 << 3)
68
#define LOG_LOCAL2   (18 << 3)
69
#define LOG_LOCAL3   (19 << 3)
70
#define LOG_LOCAL4   (20 << 3)
71
#define LOG_LOCAL5   (21 << 3)
72
#define LOG_LOCAL6   (22 << 3)
73
#define LOG_LOCAL7   (23 << 3)
74
75
#endif // LOG4CPLUS_HAVE_SYSLOG_H
76
77
78
namespace log4cplus
79
{
80
81
namespace
82
{
83
84
static
85
const char*
86
useIdent (const std::string& string)
87
0
{
88
0
    if (string.empty ())
89
0
        return nullptr;
90
0
    else
91
0
        return string.c_str ();
92
0
}
93
94
95
#ifdef LOG_USER
96
int const fallback_facility = LOG_USER;
97
98
#else
99
int const fallback_facility = 0;
100
101
#endif
102
103
104
static
105
int
106
parseFacility (const tstring& text)
107
0
{
108
0
    if (text.empty ())
109
0
        return fallback_facility;
110
0
#ifdef LOG_AUTH
111
0
    else if (text == LOG4CPLUS_TEXT ("auth"))
112
0
        return LOG_AUTH;
113
0
#endif
114
0
#ifdef LOG_AUTHPRIV
115
0
    else if (text == LOG4CPLUS_TEXT ("authpriv"))
116
0
        return LOG_AUTHPRIV;
117
0
#endif
118
#ifdef LOG_CONSOLE
119
    else if (text == LOG4CPLUS_TEXT ("console"))
120
        return LOG_CONSOLE;
121
#endif
122
0
#ifdef LOG_CRON
123
0
    else if (text == LOG4CPLUS_TEXT ("cron"))
124
0
        return LOG_CRON;
125
0
#endif
126
0
#ifdef LOG_DAEMON
127
0
    else if (text == LOG4CPLUS_TEXT ("daemon"))
128
0
        return LOG_DAEMON;
129
0
#endif
130
0
#ifdef LOG_FTP
131
0
    else if (text == LOG4CPLUS_TEXT ("ftp"))
132
0
        return LOG_FTP;
133
0
#endif
134
0
#ifdef LOG_KERN
135
0
    else if (text == LOG4CPLUS_TEXT ("kern"))
136
0
        return LOG_KERN;
137
0
#endif
138
0
#ifdef LOG_LOCAL0
139
0
    else if (text == LOG4CPLUS_TEXT ("local0"))
140
0
        return LOG_LOCAL0;
141
0
#endif
142
0
#ifdef LOG_LOCAL1
143
0
    else if (text == LOG4CPLUS_TEXT ("local1"))
144
0
        return LOG_LOCAL1;
145
0
#endif
146
0
#ifdef LOG_LOCAL2
147
0
    else if (text == LOG4CPLUS_TEXT ("local2"))
148
0
        return LOG_LOCAL2;
149
0
#endif
150
0
#ifdef LOG_LOCAL3
151
0
    else if (text == LOG4CPLUS_TEXT ("local3"))
152
0
        return LOG_LOCAL3;
153
0
#endif
154
0
#ifdef LOG_LOCAL4
155
0
    else if (text == LOG4CPLUS_TEXT ("local4"))
156
0
        return LOG_LOCAL4;
157
0
#endif
158
0
#ifdef LOG_LOCAL5
159
0
    else if (text == LOG4CPLUS_TEXT ("local5"))
160
0
        return LOG_LOCAL5;
161
0
#endif
162
0
#ifdef LOG_LOCAL6
163
0
    else if (text == LOG4CPLUS_TEXT ("local6"))
164
0
        return LOG_LOCAL6;
165
0
#endif
166
0
#ifdef LOG_LOCAL7
167
0
    else if (text == LOG4CPLUS_TEXT ("local7"))
168
0
        return LOG_LOCAL7;
169
0
#endif
170
0
#ifdef LOG_LPR
171
0
    else if (text == LOG4CPLUS_TEXT ("lpr"))
172
0
        return LOG_LPR;
173
0
#endif
174
0
#ifdef LOG_MAIL
175
0
    else if (text == LOG4CPLUS_TEXT ("mail"))
176
0
        return LOG_MAIL;
177
0
#endif
178
0
#ifdef LOG_NEWS
179
0
    else if (text == LOG4CPLUS_TEXT ("news"))
180
0
        return LOG_NEWS;
181
0
#endif
182
#ifdef LOG_NTP
183
    else if (text == LOG4CPLUS_TEXT ("ntp"))
184
        return LOG_NTP;
185
#endif
186
#ifdef LOG_SECURITY
187
    else if (text == LOG4CPLUS_TEXT ("security"))
188
        return LOG_SECURITY;
189
#endif
190
0
#ifdef LOG_SYSLOG
191
0
    else if (text == LOG4CPLUS_TEXT ("syslog"))
192
0
        return LOG_SYSLOG;
193
0
#endif
194
0
#ifdef LOG_USER
195
0
    else if (text == LOG4CPLUS_TEXT ("user"))
196
0
        return LOG_USER;
197
0
#endif
198
0
#ifdef LOG_UUCP
199
0
    else if (text == LOG4CPLUS_TEXT ("uucp"))
200
0
        return LOG_UUCP;
201
0
#endif
202
0
    else
203
0
    {
204
        // Unknown facility.
205
0
        tstring msg (LOG4CPLUS_TEXT ("Unknown syslog facility: "));
206
0
        msg += text;
207
0
        helpers::getLogLog ().error (msg);
208
209
0
        return fallback_facility;
210
0
    }
211
0
}
212
213
214
} // namespace
215
216
217
///////////////////////////////////////////////////////////////////////////////
218
// SysLogAppender ctors and dtor
219
///////////////////////////////////////////////////////////////////////////////
220
221
#if defined (LOG4CPLUS_HAVE_SYSLOG_H)
222
SysLogAppender::SysLogAppender(const tstring& id)
223
0
    : ident(id)
224
0
    , facility (0)
225
0
    , appendFunc (&SysLogAppender::appendLocal)
226
0
    , port (0)
227
    , remoteSyslogType ()
228
0
    , connected (false)
229
    // Store std::string form of ident as member of SysLogAppender so
230
    // the address of the c_str() result remains stable for openlog &
231
    // co to use even if we use wstrings.
232
0
    , identStr(LOG4CPLUS_TSTRING_TO_STRING (id) )
233
0
    , hostname (helpers::getHostname (true))
234
0
{
235
0
    ::openlog(useIdent(identStr), 0, 0);
236
0
}
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
237
238
#endif
239
240
241
SysLogAppender::SysLogAppender(const helpers::Properties & properties)
242
0
    : Appender(properties)
243
0
    , facility (0)
244
0
    , appendFunc (nullptr)
245
0
    , port (0)
246
0
    , connected (false)
247
0
{
248
0
    ident = properties.getProperty( LOG4CPLUS_TEXT("ident") );
249
0
    facility = parseFacility (
250
0
        helpers::toLower (
251
0
            properties.getProperty (LOG4CPLUS_TEXT ("facility"))));
252
0
    identStr = LOG4CPLUS_TSTRING_TO_STRING (ident);
253
254
0
    bool udp = true;
255
0
    properties.getBool (udp, LOG4CPLUS_TEXT ("udp"));
256
0
    remoteSyslogType = udp ? RSTUdp : RSTTcp;
257
258
0
    properties.getBool (ipv6, LOG4CPLUS_TEXT ("IPv6"));
259
260
0
    bool fqdn = true;
261
0
    properties.getBool (fqdn, LOG4CPLUS_TEXT ("fqdn"));
262
0
    hostname = std::move(helpers::getHostname (fqdn));
263
264
0
    properties.getString (host, LOG4CPLUS_TEXT ("host"))
265
0
      || properties.getString (host, LOG4CPLUS_TEXT ("SyslogHost"));
266
0
    if (host.empty ())
267
0
    {
268
0
#if defined (LOG4CPLUS_HAVE_SYSLOG_H)
269
0
        appendFunc = &SysLogAppender::appendLocal;
270
0
        ::openlog(useIdent(identStr), 0, 0);
271
272
#else
273
        helpers::getLogLog ().error (
274
            LOG4CPLUS_TEXT ("SysLogAppender")
275
            LOG4CPLUS_TEXT ("- local syslog not available"), true);
276
277
#endif
278
0
    }
279
0
    else
280
0
    {
281
0
        if (! properties.getInt (port, LOG4CPLUS_TEXT ("port")))
282
0
            port = 514;
283
284
0
        appendFunc = &SysLogAppender::appendRemote;
285
0
        openSocket ();
286
0
        initConnector ();
287
0
    }
288
0
}
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(log4cplus::helpers::Properties const&)
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(log4cplus::helpers::Properties const&)
289
290
291
SysLogAppender::SysLogAppender(const tstring& id, const tstring & h,
292
    int p, const tstring & f, SysLogAppender::RemoteSyslogType rst,
293
    bool ipv6_ /*= false*/)
294
0
    : SysLogAppender (id, h, p, f, rst, ipv6_, true)
295
0
{ }
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(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&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cplus::SysLogAppender::RemoteSyslogType, bool)
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(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&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cplus::SysLogAppender::RemoteSyslogType, bool)
296
297
298
SysLogAppender::SysLogAppender(const tstring& id, const tstring & h,
299
    int p, const tstring & f, SysLogAppender::RemoteSyslogType rst,
300
    bool ipv6_, bool fqdn)
301
0
    : ident (id)
302
0
    , facility (parseFacility (helpers::toLower (f)))
303
0
    , appendFunc (&SysLogAppender::appendRemote)
304
0
    , host (h)
305
0
    , port (p)
306
0
    , remoteSyslogType (rst)
307
0
    , connected (false)
308
0
    , ipv6 (ipv6_)
309
    // Store std::string form of ident as member of SysLogAppender so
310
    // the address of the c_str() result remains stable for openlog &
311
    // co to use even if we use wstrings.
312
0
    , identStr(LOG4CPLUS_TSTRING_TO_STRING (id) )
313
0
    , hostname (helpers::getHostname (fqdn))
314
0
{
315
0
    openSocket ();
316
0
    initConnector ();
317
0
}
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(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&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cplus::SysLogAppender::RemoteSyslogType, bool, bool)
Unexecuted instantiation: log4cplus::SysLogAppender::SysLogAppender(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&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, log4cplus::SysLogAppender::RemoteSyslogType, bool, bool)
318
319
320
SysLogAppender::~SysLogAppender()
321
0
{
322
0
    destructorImpl();
323
0
}
324
325
326
327
///////////////////////////////////////////////////////////////////////////////
328
// SysLogAppender public methods
329
///////////////////////////////////////////////////////////////////////////////
330
331
void
332
SysLogAppender::close()
333
0
{
334
0
    helpers::getLogLog().debug(
335
0
        LOG4CPLUS_TEXT("Entering SysLogAppender::close()..."));
336
0
    thread::MutexGuard guard (access_mutex);
337
338
0
    if (host.empty ())
339
0
    {
340
0
#if defined (LOG4CPLUS_HAVE_SYSLOG_H)
341
0
        ::closelog();
342
0
#endif
343
0
    }
344
0
    else
345
0
        syslogSocket.close ();
346
347
0
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
348
0
    if (connector)
349
0
        connector->terminate ();
350
0
#endif
351
352
0
    closed = true;
353
0
}
354
355
356
357
///////////////////////////////////////////////////////////////////////////////
358
// SysLogAppender protected methods
359
///////////////////////////////////////////////////////////////////////////////
360
361
int
362
SysLogAppender::getSysLogLevel(const LogLevel& ll) const
363
0
{
364
0
    if(ll < INFO_LOG_LEVEL /* || ll < DEBUG_LOG_LEVEL*/) {
365
0
        return LOG_DEBUG;
366
0
    }
367
0
    else if(ll < WARN_LOG_LEVEL) {
368
0
        return LOG_INFO;
369
0
    }
370
0
    else if(ll < ERROR_LOG_LEVEL) {
371
0
        return LOG_WARNING;
372
0
    }
373
0
    else if(ll < FATAL_LOG_LEVEL) {
374
0
        return LOG_ERR;
375
0
    }
376
0
    else if(ll == FATAL_LOG_LEVEL) {
377
0
        return LOG_CRIT;
378
0
    }
379
380
0
    return LOG_ALERT;  // ll > FATAL_LOG_LEVEL
381
0
}
382
383
384
// This method does not need to be locked since it is called by
385
// doAppend() which performs the locking
386
void
387
SysLogAppender::append(const spi::InternalLoggingEvent& event)
388
0
{
389
0
    (this->*appendFunc) (event);
390
0
}
391
392
393
#if defined (LOG4CPLUS_HAVE_SYSLOG_H)
394
void
395
SysLogAppender::appendLocal(const spi::InternalLoggingEvent& event)
396
0
{
397
0
    int const level = getSysLogLevel(event.getLogLevel());
398
0
    internal::appender_sratch_pad & appender_sp = internal::get_appender_sp ();
399
0
    detail::clear_tostringstream (appender_sp.oss);
400
0
    layout->formatAndAppend(appender_sp.oss, event);
401
0
    appender_sp.str = appender_sp.oss.str ();
402
0
    ::syslog(facility | level, "%s",
403
0
        LOG4CPLUS_TSTRING_TO_STRING(appender_sp.str).c_str());
404
0
}
405
406
#endif
407
408
409
tstring const SysLogAppender::remoteTimeFormat (
410
    LOG4CPLUS_TEXT ("%Y-%m-%dT%H:%M:%S.%qZ"));
411
412
413
void
414
SysLogAppender::appendRemote(const spi::InternalLoggingEvent& event)
415
0
{
416
417
0
    if (! connected)
418
0
    {
419
0
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
420
0
        connector->trigger ();
421
0
        return;
422
423
#else
424
        openSocket ();
425
        if (! connected)
426
        {
427
            helpers::getLogLog ().error (
428
                LOG4CPLUS_TEXT ("SysLogAppender")
429
                LOG4CPLUS_TEXT ("- failed to connect to ")
430
                + host + LOG4CPLUS_TEXT (":")
431
                + helpers::convertIntegerToString (port));
432
            return;
433
        }
434
#endif
435
0
    }
436
437
0
    int const level = getSysLogLevel(event.getLogLevel());
438
0
    internal::appender_sratch_pad & appender_sp = internal::get_appender_sp ();
439
0
    detail::clear_tostringstream (appender_sp.oss);
440
441
0
    appender_sp.oss
442
        // PRI
443
0
        << LOG4CPLUS_TEXT ('<') << (level | facility) << LOG4CPLUS_TEXT ('>')
444
        // VERSION
445
0
        << 1
446
        // TIMESTAMP
447
0
        << LOG4CPLUS_TEXT (' ')
448
0
        << helpers::getFormattedTime (remoteTimeFormat, event.getTimestamp (),
449
0
            true)
450
        // HOSTNAME
451
0
        << LOG4CPLUS_TEXT (' ') << hostname
452
        // APP-NAME
453
0
        << LOG4CPLUS_TEXT (' ') << ident
454
        // PROCID
455
0
        << LOG4CPLUS_TEXT (' ') << internal::get_process_id ()
456
        // MSGID
457
0
        << LOG4CPLUS_TEXT (' ') << event.getLoggerName ()
458
        // STRUCTURED-DATA
459
        // no structured data, it could be whole MDC
460
0
        << LOG4CPLUS_TEXT (" - ");
461
462
    // MSG
463
0
    layout->formatAndAppend (appender_sp.oss, event);
464
465
0
    appender_sp.chstr = LOG4CPLUS_TSTRING_TO_STRING (appender_sp.oss.str ());
466
467
0
    if (remoteSyslogType != RSTUdp)
468
0
    {
469
        // see (RFC6587, 3.4.1 Octet
470
        // Counting)[http://tools.ietf.org/html/rfc6587#section-3.4.1]
471
0
        std::string syslogFrameHeader (
472
0
            helpers::convertIntegerToNarrowString (appender_sp.chstr.size ()));
473
0
        syslogFrameHeader += ' ';
474
0
        appender_sp.chstr.insert (appender_sp.chstr.begin (),
475
0
            syslogFrameHeader.begin (), syslogFrameHeader.end ());
476
0
    }
477
478
0
    bool ret = syslogSocket.write (appender_sp.chstr);
479
0
    if (! ret)
480
0
    {
481
0
        helpers::getLogLog ().warn (
482
0
            LOG4CPLUS_TEXT ("SysLogAppender::appendRemote")
483
0
            LOG4CPLUS_TEXT ("- socket write failed"));
484
485
0
        connected = false;
486
487
0
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
488
0
        connector->trigger ();
489
0
#endif
490
0
    }
491
0
}
492
493
494
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
495
thread::Mutex const &
496
SysLogAppender::ctcGetAccessMutex () const
497
0
{
498
0
    return access_mutex;
499
0
}
500
501
502
helpers::Socket &
503
SysLogAppender::ctcGetSocket ()
504
0
{
505
0
    return syslogSocket;
506
0
}
507
508
509
helpers::Socket
510
SysLogAppender::ctcConnect ()
511
0
{
512
0
    return helpers::Socket (host, static_cast<unsigned short>(port),
513
0
        remoteSyslogType == RSTUdp);
514
0
}
515
516
517
void
518
SysLogAppender::ctcSetConnected ()
519
0
{
520
0
    connected = true;
521
0
}
522
523
#endif
524
525
526
void
527
SysLogAppender::initConnector ()
528
0
{
529
0
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
530
0
    connected = true;
531
0
    connector = new helpers::ConnectorThread (*this);
532
0
    connector->start ();
533
0
#endif
534
0
}
535
536
537
void
538
SysLogAppender::openSocket ()
539
0
{
540
0
    syslogSocket = helpers::Socket (host, static_cast<unsigned short>(port),
541
0
        remoteSyslogType == RSTUdp, ipv6);
542
0
    connected = syslogSocket.isOpen ();
543
0
    if (! connected)
544
0
        helpers::getLogLog ().error (
545
0
            LOG4CPLUS_TEXT ("SysLogAppender")
546
0
            LOG4CPLUS_TEXT ("- failed to connect to ")
547
0
            + host
548
0
            + LOG4CPLUS_TEXT (":") + helpers::convertIntegerToString (port));
549
0
}
550
551
552
} // namespace log4cplus