Coverage Report

Created: 2026-06-30 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oflog/libsrc/syslogap.cc
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    syslogappender.cxx
3
// Created: 6/2001
4
// Author:  Tad E. Smith
5
//
6
// Copyright 2001-2010 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 "dcmtk/oflog/syslogap.h"
21
#include "dcmtk/oflog/streams.h"
22
#include "dcmtk/oflog/logmacro.h"
23
#include "dcmtk/oflog/helpers/loglog.h"
24
#include "dcmtk/oflog/helpers/property.h"
25
#include "dcmtk/oflog/helpers/strhelp.h"
26
#include "dcmtk/oflog/spi/logevent.h"
27
#include "dcmtk/oflog/internal/internal.h"
28
#include "dcmtk/oflog/internal/env.h"
29
#include "dcmtk/oflog/thread/syncpub.h"
30
#include <cstring>
31
32
#if defined (DCMTK_LOG4CPLUS_HAVE_SYSLOG_H)
33
#include <syslog.h>
34
35
#else // DCMTK_LOG4CPLUS_HAVE_SYSLOG_H
36
37
// The following bits were derived from SUSv4 documentation and
38
// RFC5424 document.
39
40
// priority codes
41
#define LOG_EMERG   0
42
#define LOG_ALERT   1
43
#define LOG_CRIT    2
44
#define LOG_ERR     3
45
#define LOG_WARNING 4
46
#define LOG_NOTICE  5
47
#define LOG_INFO    6
48
#define LOG_DEBUG   7
49
50
// facility codes
51
#define LOG_KERN      (0 << 3)
52
#define LOG_USER      (1 << 3)
53
#define LOG_MAIL      (2 << 3)
54
#define LOG_DAEMON    (3 << 3)
55
#define LOG_AUTH      (4 << 3)
56
#define LOG_SYSLOG    (5 << 3)
57
#define LOG_LPR       (6 << 3)
58
#define LOG_NEWS      (7 << 3)
59
#define LOG_UUCP      (8 << 3)
60
#define LOG_CRON      (9 << 3)
61
#define LOG_AUTHPRIV (10 << 3)
62
#define LOG_FTP      (11 << 3)
63
#define LOG_NTP      (12 << 3)
64
#define LOG_SECURITY (13 << 3)
65
#define LOG_CONSOLE  (14 << 3)
66
// (15 << 3) is missing here
67
#define LOG_LOCAL0   (16 << 3)
68
#define LOG_LOCAL1   (17 << 3)
69
#define LOG_LOCAL2   (18 << 3)
70
#define LOG_LOCAL3   (19 << 3)
71
#define LOG_LOCAL4   (20 << 3)
72
#define LOG_LOCAL5   (21 << 3)
73
#define LOG_LOCAL6   (22 << 3)
74
#define LOG_LOCAL7   (23 << 3)
75
76
#endif // DCMTK_LOG4CPLUS_HAVE_SYSLOG_H
77
78
79
namespace dcmtk
80
{
81
namespace log4cplus
82
{
83
84
namespace
85
{
86
87
#ifdef LOG_USER
88
int const fallback_facility = LOG_USER;
89
90
#else
91
int const fallback_facility = 0;
92
93
#endif
94
95
96
static
97
int
98
parseFacility (const tstring& text)
99
0
{
100
0
    if (text.empty ())
101
0
        return fallback_facility;
102
0
#ifdef LOG_AUTH
103
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("auth"))
104
0
        return LOG_AUTH;
105
0
#endif
106
0
#ifdef LOG_AUTHPRIV
107
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("authpriv"))
108
0
        return LOG_AUTHPRIV;
109
0
#endif
110
#ifdef LOG_CONSOLE
111
    else if (text == DCMTK_LOG4CPLUS_TEXT ("console"))
112
        return LOG_CONSOLE;
113
#endif
114
0
#ifdef LOG_CRON
115
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("cron"))
116
0
        return LOG_CRON;
117
0
#endif
118
0
#ifdef LOG_DAEMON
119
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("daemon"))
120
0
        return LOG_DAEMON;
121
0
#endif
122
0
#ifdef LOG_FTP
123
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("ftp"))
124
0
        return LOG_FTP;
125
0
#endif
126
0
#ifdef LOG_KERN
127
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("kern"))
128
0
        return LOG_KERN;
129
0
#endif
130
0
#ifdef LOG_LOCAL0
131
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local0"))
132
0
        return LOG_LOCAL0;
133
0
#endif
134
0
#ifdef LOG_LOCAL1
135
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local1"))
136
0
        return LOG_LOCAL1;
137
0
#endif
138
0
#ifdef LOG_LOCAL2
139
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local2"))
140
0
        return LOG_LOCAL2;
141
0
#endif
142
0
#ifdef LOG_LOCAL3
143
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local3"))
144
0
        return LOG_LOCAL3;
145
0
#endif
146
0
#ifdef LOG_LOCAL4
147
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local4"))
148
0
        return LOG_LOCAL4;
149
0
#endif
150
0
#ifdef LOG_LOCAL5
151
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local5"))
152
0
        return LOG_LOCAL5;
153
0
#endif
154
0
#ifdef LOG_LOCAL6
155
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local6"))
156
0
        return LOG_LOCAL6;
157
0
#endif
158
0
#ifdef LOG_LOCAL7
159
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("local7"))
160
0
        return LOG_LOCAL7;
161
0
#endif
162
0
#ifdef LOG_LPR
163
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("lpr"))
164
0
        return LOG_LPR;
165
0
#endif
166
0
#ifdef LOG_MAIL
167
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("mail"))
168
0
        return LOG_MAIL;
169
0
#endif
170
0
#ifdef LOG_NEWS
171
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("news"))
172
0
        return LOG_NEWS;
173
0
#endif
174
#ifdef LOG_NTP
175
    else if (text == DCMTK_LOG4CPLUS_TEXT ("ntp"))
176
        return LOG_NTP;
177
#endif
178
#ifdef LOG_SECURITY
179
    else if (text == DCMTK_LOG4CPLUS_TEXT ("security"))
180
        return LOG_SECURITY;
181
#endif
182
0
#ifdef LOG_SYSLOG
183
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("syslog"))
184
0
        return LOG_SYSLOG;
185
0
#endif
186
0
#ifdef LOG_USER
187
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("user"))
188
0
        return LOG_USER;
189
0
#endif
190
0
#ifdef LOG_UUCP
191
0
    else if (text == DCMTK_LOG4CPLUS_TEXT ("uucp"))
192
0
        return LOG_UUCP;
193
0
#endif
194
0
    else
195
0
    {
196
        // Unknown facility.
197
0
        tstring msg (DCMTK_LOG4CPLUS_TEXT ("Unknown syslog facility: "));
198
0
        msg += text;
199
0
        helpers::getLogLog ().error (msg);
200
201
0
        return fallback_facility;
202
0
    }
203
0
}
204
205
206
} // namespace
207
208
209
///////////////////////////////////////////////////////////////////////////////
210
// SysLogAppender ctors and dtor
211
///////////////////////////////////////////////////////////////////////////////
212
213
#if defined (DCMTK_LOG4CPLUS_HAVE_SYSLOG_H)
214
static const char*
215
useIdent (const tstring& string)
216
0
{
217
0
    return string.empty() ? 0 : string.c_str();
218
0
}
219
220
SysLogAppender::SysLogAppender(const tstring& id)
221
0
    : ident(id)
222
0
    , appendFunc (&SysLogAppender::appendLocal)
223
0
    , facility (0)
224
0
    , host ()
225
0
    , port (0)
226
0
    , syslogSocket ()
227
    // Store STD_NAMESPACE string form of ident as member of SysLogAppender so
228
    // the address of the c_str() result remains stable for openlog &
229
    // co to use even if we use wstrings.
230
0
    , identStr(DCMTK_LOG4CPLUS_TSTRING_TO_STRING (id) )
231
0
    , hostname (helpers::getHostname (true))
232
0
{
233
0
    ::openlog(useIdent(identStr), 0, 0);
234
0
}
Unexecuted instantiation: dcmtk::log4cplus::SysLogAppender::SysLogAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: dcmtk::log4cplus::SysLogAppender::SysLogAppender(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
235
236
#endif
237
238
239
SysLogAppender::SysLogAppender(const helpers::Properties & properties)
240
0
    : Appender(properties)
241
0
    , ident ()
242
0
    , appendFunc (0)
243
0
    , facility (0)
244
0
    , host ()
245
0
    , port (0)
246
0
    , syslogSocket ()
247
0
    , identStr ()
248
0
    , hostname (helpers::getHostname (true))
249
0
{
250
0
    ident = properties.getProperty( DCMTK_LOG4CPLUS_TEXT("ident") );
251
0
    facility = parseFacility (
252
0
        helpers::toLower (
253
0
            properties.getProperty (DCMTK_LOG4CPLUS_TEXT ("facility"))));
254
0
    identStr = DCMTK_LOG4CPLUS_TSTRING_TO_STRING (ident);
255
256
0
    host = properties.getProperty (DCMTK_LOG4CPLUS_TEXT ("host"));
257
0
    if (host.empty ())
258
0
    {
259
0
#if defined (DCMTK_LOG4CPLUS_HAVE_SYSLOG_H)
260
0
        appendFunc = &SysLogAppender::appendLocal;
261
0
        ::openlog(useIdent(identStr), 0, 0);
262
263
#else
264
        helpers::getLogLog ().error (
265
            DCMTK_LOG4CPLUS_TEXT ("SysLogAppender")
266
            DCMTK_LOG4CPLUS_TEXT ("- local syslog not available"), true);
267
268
#endif
269
0
    }
270
0
    else
271
0
    {
272
0
        if (! properties.getInt (port, DCMTK_LOG4CPLUS_TEXT ("port")))
273
0
            port = 514;
274
275
0
        appendFunc = &SysLogAppender::appendRemote;
276
0
        syslogSocket = helpers::Socket (host, OFstatic_cast(unsigned short, port), true);
277
0
    }
278
0
}
Unexecuted instantiation: dcmtk::log4cplus::SysLogAppender::SysLogAppender(dcmtk::log4cplus::helpers::Properties const&)
Unexecuted instantiation: dcmtk::log4cplus::SysLogAppender::SysLogAppender(dcmtk::log4cplus::helpers::Properties const&)
279
280
281
SysLogAppender::SysLogAppender(const tstring& id, const tstring & h,
282
    int p, const tstring & f)
283
0
    : ident (id)
284
0
    , appendFunc (&SysLogAppender::appendRemote)
285
0
    , facility (parseFacility (helpers::toLower (f)))
286
0
    , host (h)
287
0
    , port (p)
288
0
    , syslogSocket (host, OFstatic_cast(unsigned short, port), true)
289
    // Store STD_NAMESPACE string form of ident as member of SysLogAppender so
290
    // the address of the c_str() result remains stable for openlog &
291
    // co to use even if we use wstrings.
292
0
    , identStr(DCMTK_LOG4CPLUS_TSTRING_TO_STRING (id) )
293
0
    , hostname (helpers::getHostname (true))
294
0
{ }
Unexecuted instantiation: dcmtk::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&)
Unexecuted instantiation: dcmtk::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&)
295
296
297
SysLogAppender::~SysLogAppender()
298
0
{
299
0
    destructorImpl();
300
0
}
301
302
303
304
///////////////////////////////////////////////////////////////////////////////
305
// SysLogAppender public methods
306
///////////////////////////////////////////////////////////////////////////////
307
308
void
309
SysLogAppender::close()
310
0
{
311
0
    helpers::getLogLog().debug(
312
0
        DCMTK_LOG4CPLUS_TEXT("Entering SysLogAppender::close()..."));
313
0
    thread::MutexGuard guard (access_mutex);
314
315
0
    if (host.empty ())
316
0
    {
317
0
#if defined (DCMTK_LOG4CPLUS_HAVE_SYSLOG_H)
318
0
        ::closelog();
319
0
#endif
320
0
    }
321
0
    else
322
0
        syslogSocket.close ();
323
324
0
    closed = true;
325
0
}
326
327
328
329
///////////////////////////////////////////////////////////////////////////////
330
// SysLogAppender protected methods
331
///////////////////////////////////////////////////////////////////////////////
332
333
int
334
SysLogAppender::getSysLogLevel(const LogLevel& ll) const
335
0
{
336
0
    if(ll < INFO_LOG_LEVEL /* || ll < DEBUG_LOG_LEVEL*/) {
337
0
        return LOG_DEBUG;
338
0
    }
339
0
    else if(ll < WARN_LOG_LEVEL) {
340
0
        return LOG_INFO;
341
0
    }
342
0
    else if(ll < ERROR_LOG_LEVEL) {
343
0
        return LOG_WARNING;
344
0
    }
345
0
    else if(ll < FATAL_LOG_LEVEL) {
346
0
        return LOG_ERR;
347
0
    }
348
0
    else if(ll == FATAL_LOG_LEVEL) {
349
0
        return LOG_CRIT;
350
0
    }
351
352
0
    return LOG_ALERT;  // ll > FATAL_LOG_LEVEL
353
0
}
354
355
356
// This method does not need to be locked since it is called by
357
// doAppend() which performs the locking
358
void
359
SysLogAppender::append(const spi::InternalLoggingEvent& event)
360
0
{
361
0
    (this->*appendFunc) (event);
362
0
}
363
364
365
#if defined (DCMTK_LOG4CPLUS_HAVE_SYSLOG_H)
366
void
367
SysLogAppender::appendLocal(const spi::InternalLoggingEvent& event)
368
0
{
369
0
    int const level = getSysLogLevel(event.getLogLevel());
370
0
    internal::appender_sratch_pad & appender_sp = internal::get_appender_sp ();
371
0
    detail::clear_tostringstream (appender_sp.oss);
372
0
    layout->formatAndAppend(appender_sp.oss, event);
373
0
    appender_sp.str = OFString(appender_sp.oss.str().c_str(), appender_sp.oss.str().length());
374
0
    ::syslog(facility | level, "%s",
375
0
        DCMTK_LOG4CPLUS_TSTRING_TO_STRING(appender_sp.str).c_str());
376
0
}
377
378
#endif
379
380
381
tstring const SysLogAppender::remoteTimeFormat (
382
    DCMTK_LOG4CPLUS_TEXT ("%Y-%m-%dT%H:%M:%S.%qZ"));
383
384
385
void
386
SysLogAppender::appendRemote(const spi::InternalLoggingEvent& event)
387
0
{
388
0
    int const level = getSysLogLevel(event.getLogLevel());
389
0
    internal::appender_sratch_pad & appender_sp = internal::get_appender_sp ();
390
0
    detail::clear_tostringstream (appender_sp.oss);
391
392
0
    appender_sp.oss
393
        // PRI
394
0
        << DCMTK_LOG4CPLUS_TEXT ('<') << (level | facility) << DCMTK_LOG4CPLUS_TEXT ('>')
395
        // VERSION
396
0
        << 1
397
        // TIMESTAMP
398
0
        << DCMTK_LOG4CPLUS_TEXT (' ')
399
0
        << event.getTimestamp ().getFormattedTime (remoteTimeFormat, true)
400
        // HOSTNAME
401
0
        << DCMTK_LOG4CPLUS_TEXT (' ') << hostname
402
        // APP-NAME
403
0
        << DCMTK_LOG4CPLUS_TEXT (' ') << ident
404
        // PROCID
405
0
        << DCMTK_LOG4CPLUS_TEXT (' ') << internal::get_process_id ()
406
        // MSGID
407
0
        << DCMTK_LOG4CPLUS_TEXT (' ') << event.getLoggerName ()
408
        // STRUCTURED-DATA
409
        // no structured data, it could be whole MDC
410
0
        << DCMTK_LOG4CPLUS_TEXT (" - ");
411
412
    // MSG
413
0
    layout->formatAndAppend (appender_sp.oss, event);
414
415
0
    DCMTK_LOG4CPLUS_TSTRING_TO_STRING (appender_sp.oss.str ())
416
0
        .swap (appender_sp.chstr);
417
    
418
0
    bool ret = syslogSocket.write (appender_sp.chstr);
419
0
    if (! ret)
420
0
    {
421
0
        helpers::getLogLog ().warn (
422
0
            DCMTK_LOG4CPLUS_TEXT ("SysLogAppender::appendRemote")
423
0
            DCMTK_LOG4CPLUS_TEXT ("- socket write failed"));
424
0
        syslogSocket = helpers::Socket (host, OFstatic_cast(unsigned short, port), true);
425
0
    }
426
0
}
427
428
429
} // namespace log4cplus
430
} // end namespace dcmtk