Coverage Report

Created: 2026-02-14 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/log4cplus/src/appender.cxx
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    appender.cxx
3
// Created: 6/2001
4
// Author:  Tad E. Smith
5
//
6
//
7
// Copyright 2003-2017 Tad E. Smith
8
//
9
// Licensed under the Apache License, Version 2.0 (the "License");
10
// you may not use this file except in compliance with the License.
11
// You may obtain a copy of the License at
12
//
13
//     http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software
16
// distributed under the License is distributed on an "AS IS" BASIS,
17
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
// See the License for the specific language governing permissions and
19
// limitations under the License.
20
21
#include <log4cplus/appender.h>
22
#include <log4cplus/layout.h>
23
#include <log4cplus/helpers/loglog.h>
24
#include <log4cplus/helpers/pointer.h>
25
#include <log4cplus/helpers/stringhelper.h>
26
#include <log4cplus/helpers/property.h>
27
#include <log4cplus/spi/factory.h>
28
#include <log4cplus/spi/loggingevent.h>
29
#include <log4cplus/internal/internal.h>
30
#include <log4cplus/thread/syncprims-pub-impl.h>
31
#include <stdexcept>
32
33
34
namespace log4cplus
35
{
36
37
38
///////////////////////////////////////////////////////////////////////////////
39
// log4cplus::ErrorHandler dtor
40
///////////////////////////////////////////////////////////////////////////////
41
42
ErrorHandler::ErrorHandler ()
43
484k
{ }
44
45
46
ErrorHandler::~ErrorHandler()
47
484k
{ }
48
49
50
51
///////////////////////////////////////////////////////////////////////////////
52
// log4cplus::OnlyOnceErrorHandler
53
///////////////////////////////////////////////////////////////////////////////
54
55
OnlyOnceErrorHandler::OnlyOnceErrorHandler()
56
484k
    : firstTime(true)
57
484k
{ }
58
59
60
OnlyOnceErrorHandler::~OnlyOnceErrorHandler ()
61
{ }
62
63
64
void
65
OnlyOnceErrorHandler::error(const log4cplus::tstring& err)
66
0
{
67
0
    if(firstTime) {
68
0
        helpers::getLogLog().error(err);
69
0
        firstTime = false;
70
0
    }
71
0
}
72
73
74
75
void
76
OnlyOnceErrorHandler::reset()
77
0
{
78
0
    firstTime = true;
79
0
}
80
81
82
83
///////////////////////////////////////////////////////////////////////////////
84
// log4cplus::Appender ctors
85
///////////////////////////////////////////////////////////////////////////////
86
87
Appender::Appender()
88
342k
 : layout(new SimpleLayout),
89
342k
   name(internal::empty_str),
90
342k
   threshold(NOT_SET_LOG_LEVEL),
91
342k
   errorHandler(new OnlyOnceErrorHandler),
92
342k
   useLockFile(false),
93
342k
   async(false),
94
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
95
342k
   in_flight(0),
96
#endif
97
342k
   closed(false)
98
342k
{
99
342k
}
100
101
102
103
Appender::Appender(const log4cplus::helpers::Properties & properties)
104
142k
    : layout(new SimpleLayout)
105
142k
    , name()
106
142k
    , threshold(NOT_SET_LOG_LEVEL)
107
142k
    , errorHandler(new OnlyOnceErrorHandler)
108
142k
    , useLockFile(false)
109
142k
    , async(false)
110
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
111
142k
    , in_flight(0)
112
#endif
113
142k
    , closed(false)
114
142k
{
115
142k
    if(properties.exists( LOG4CPLUS_TEXT("layout") ))
116
0
    {
117
0
        log4cplus::tstring const & factoryName
118
0
            = properties.getProperty( LOG4CPLUS_TEXT("layout") );
119
0
        spi::LayoutFactory* factory
120
0
            = spi::getLayoutFactoryRegistry().get(factoryName);
121
0
        if (factory == nullptr) {
122
0
            helpers::getLogLog().error(
123
0
                LOG4CPLUS_TEXT("Cannot find LayoutFactory: \"")
124
0
                + factoryName
125
0
                + LOG4CPLUS_TEXT("\""), true);
126
0
        }
127
128
0
        helpers::Properties layoutProperties =
129
0
                properties.getPropertySubset( LOG4CPLUS_TEXT("layout.") );
130
0
        try {
131
0
            std::unique_ptr<Layout> newLayout(factory->createObject(layoutProperties));
132
0
            if (newLayout == nullptr) {
133
0
                helpers::getLogLog().error(
134
0
                    LOG4CPLUS_TEXT("Failed to create Layout: ")
135
0
                    + factoryName, true);
136
0
            }
137
0
            else {
138
0
                layout = std::move(newLayout);
139
0
            }
140
0
        }
141
0
        catch(std::exception const & e) {
142
0
            helpers::getLogLog().error(
143
0
                LOG4CPLUS_TEXT("Error while creating Layout: ")
144
0
                + LOG4CPLUS_C_STR_TO_TSTRING(e.what()), true);
145
0
        }
146
147
0
    }
148
149
    // Support for appender.Threshold in properties configuration file
150
142k
    if(properties.exists(LOG4CPLUS_TEXT("Threshold"))) {
151
0
        tstring tmp = properties.getProperty(LOG4CPLUS_TEXT("Threshold"));
152
0
        tmp = log4cplus::helpers::toUpper(tmp);
153
0
        threshold = log4cplus::getLogLevelManager().fromString(tmp);
154
0
    }
155
156
    // Configure the filters
157
142k
    helpers::Properties filterProps
158
142k
        = properties.getPropertySubset( LOG4CPLUS_TEXT("filters.") );
159
142k
    unsigned filterCount = 0;
160
142k
    tstring filterName;
161
142k
    while (filterProps.exists(
162
142k
        filterName = helpers::convertIntegerToString (++filterCount)))
163
0
    {
164
0
        tstring const & factoryName = filterProps.getProperty(filterName);
165
0
        spi::FilterFactory* factory
166
0
            = spi::getFilterFactoryRegistry().get(factoryName);
167
168
0
        if(! factory)
169
0
        {
170
0
            helpers::getLogLog().error(
171
0
                LOG4CPLUS_TEXT("Appender::ctor()- Cannot find FilterFactory: ")
172
0
                + factoryName, true);
173
0
        }
174
0
        spi::FilterPtr tmpFilter = factory->createObject (
175
0
            filterProps.getPropertySubset(filterName + LOG4CPLUS_TEXT(".")));
176
0
        if (! tmpFilter)
177
0
        {
178
0
            helpers::getLogLog().error(
179
0
                LOG4CPLUS_TEXT("Appender::ctor()- Failed to create filter: ")
180
0
                + filterName, true);
181
0
        }
182
0
        addFilter (std::move (tmpFilter));
183
0
    }
184
185
    // Deal with file locking settings.
186
142k
    properties.getBool (useLockFile, LOG4CPLUS_TEXT("UseLockFile"));
187
142k
    if (useLockFile)
188
0
    {
189
0
        tstring const & lockFileName
190
0
            = properties.getProperty (LOG4CPLUS_TEXT ("LockFile"));
191
0
        if (! lockFileName.empty ())
192
0
        {
193
0
            try
194
0
            {
195
0
                lockFile.reset (new helpers::LockFile (lockFileName));
196
0
            }
197
0
            catch (std::runtime_error const &)
198
0
            {
199
0
                return;
200
0
            }
201
0
        }
202
0
        else
203
0
        {
204
0
            helpers::getLogLog ().debug (
205
0
                LOG4CPLUS_TEXT (
206
0
                    "UseLockFile is true but LockFile is not specified"));
207
0
        }
208
0
    }
209
210
    // Deal with asynchronous append flag.
211
142k
    properties.getBool (async, LOG4CPLUS_TEXT("AsyncAppend"));
212
142k
}
213
214
215
Appender::~Appender()
216
484k
{
217
484k
    helpers::LogLog & loglog = helpers::getLogLog ();
218
219
484k
    loglog.debug(LOG4CPLUS_TEXT("Destroying appender named [") + name
220
484k
        + LOG4CPLUS_TEXT("]."));
221
222
484k
    if (! closed)
223
0
        loglog.error (
224
0
            LOG4CPLUS_TEXT ("Derived Appender did not call destructorImpl()."));
225
484k
}
226
227
228
229
///////////////////////////////////////////////////////////////////////////////
230
// log4cplus::Appender public methods
231
///////////////////////////////////////////////////////////////////////////////
232
233
void
234
Appender::waitToFinishAsyncLogging()
235
484k
{
236
484k
#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
237
484k
    && defined (LOG4CPLUS_ENABLE_THREAD_POOL)
238
484k
    if (async)
239
0
    {
240
        // When async flag is true we might have some logging still in flight
241
        // on thread pool threads. Wait for them to finish.
242
243
0
        std::unique_lock<std::mutex> lock (in_flight_mutex);
244
0
        in_flight_condition.wait (lock,
245
0
            [&] { return this->in_flight == 0; });
246
0
    }
247
484k
#endif
248
484k
}
249
250
void
251
Appender::destructorImpl()
252
484k
{
253
    // An appender might be closed then destroyed. There is no point
254
    // in closing twice. It can actually be a wrong thing to do, e.g.,
255
    // files get rolled more than once.
256
484k
    if (closed)
257
413k
        return;
258
259
71.0k
    waitToFinishAsyncLogging ();
260
261
71.0k
    close();
262
71.0k
    closed = true;
263
71.0k
}
264
265
266
bool Appender::isClosed() const
267
413k
{
268
413k
    return closed;
269
413k
}
270
271
272
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
273
void
274
Appender::subtract_in_flight ()
275
0
{
276
0
#if defined (LOG4CPLUS_ENABLE_THREAD_POOL)
277
0
    std::size_t const prev = std::atomic_fetch_sub_explicit (&in_flight,
278
0
        std::size_t (1), std::memory_order_acq_rel);
279
0
    if (prev == 1)
280
0
    {
281
0
        std::unique_lock<std::mutex> lock (in_flight_mutex);
282
0
        in_flight_condition.notify_all ();
283
0
    }
284
0
#endif
285
0
}
286
287
#endif
288
289
290
// from global-init.cxx
291
void enqueueAsyncDoAppend (SharedAppenderPtr const & appender,
292
    spi::InternalLoggingEvent const & event);
293
294
295
void
296
Appender::doAppend(const log4cplus::spi::InternalLoggingEvent& event)
297
733k
{
298
733k
#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
299
733k
    && defined (LOG4CPLUS_ENABLE_THREAD_POOL)
300
733k
    if (async)
301
0
    {
302
0
        event.gatherThreadSpecificData ();
303
304
0
        std::atomic_fetch_add_explicit (&in_flight, std::size_t (1),
305
0
            std::memory_order_relaxed);
306
307
0
        try
308
0
        {
309
0
            enqueueAsyncDoAppend (SharedAppenderPtr (this), event);
310
0
        }
311
0
        catch (...)
312
0
        {
313
0
            subtract_in_flight ();
314
0
            throw;
315
0
        }
316
0
    }
317
733k
    else
318
733k
#endif
319
733k
        syncDoAppend (event);
320
733k
}
321
322
323
void
324
Appender::asyncDoAppend(const log4cplus::spi::InternalLoggingEvent& event)
325
0
{
326
0
#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
327
0
    && defined (LOG4CPLUS_ENABLE_THREAD_POOL)
328
0
    struct handle_in_flight
329
0
    {
330
0
        Appender * const app;
331
332
0
        explicit
333
0
        handle_in_flight (Appender * app_)
334
0
            : app (app_)
335
0
        { }
336
337
0
        ~handle_in_flight ()
338
0
        {
339
0
            app->subtract_in_flight ();
340
0
        }
341
0
    };
342
343
0
    handle_in_flight guard (this);
344
0
#endif
345
346
0
    syncDoAppend (event);
347
0
}
348
349
350
void
351
Appender::syncDoAppend(const log4cplus::spi::InternalLoggingEvent& event)
352
733k
{
353
733k
    thread::MutexGuard guard (access_mutex);
354
355
733k
    if(closed) {
356
0
        helpers::getLogLog().error(
357
0
            LOG4CPLUS_TEXT("Attempted to append to closed appender named [")
358
0
            + name
359
0
            + LOG4CPLUS_TEXT("]."));
360
0
        return;
361
0
    }
362
363
    // Check appender's threshold logging level.
364
365
733k
    if (! isAsSevereAsThreshold(event.getLogLevel()))
366
0
        return;
367
368
    // Evaluate filters attached to this appender.
369
370
733k
    if (checkFilter(filter.get(), event) == spi::DENY)
371
0
        return;
372
373
    // Lock system wide lock.
374
375
733k
    helpers::LockFileGuard lfguard;
376
733k
    if (useLockFile && lockFile.get ())
377
0
    {
378
0
        try
379
0
        {
380
0
            lfguard.attach_and_lock (*lockFile);
381
0
        }
382
0
        catch (std::runtime_error const &)
383
0
        {
384
0
            return;
385
0
        }
386
0
    }
387
388
    // Finally append given event.
389
390
733k
    append(event);
391
733k
}
392
393
394
tstring &
395
Appender::formatEvent (const spi::InternalLoggingEvent& event) const
396
0
{
397
0
    internal::appender_sratch_pad & appender_sp = internal::get_appender_sp ();
398
0
    detail::clear_tostringstream (appender_sp.oss);
399
0
    layout->formatAndAppend(appender_sp.oss, event);
400
0
    appender_sp.str = appender_sp.oss.str();
401
0
    return appender_sp.str;
402
0
}
403
404
405
log4cplus::tstring
406
Appender::getName()
407
120k
{
408
120k
    return name;
409
120k
}
410
411
412
413
void
414
Appender::setName(const log4cplus::tstring& n)
415
142k
{
416
142k
    this->name = n;
417
142k
}
418
419
420
ErrorHandler*
421
Appender::getErrorHandler()
422
0
{
423
0
    return errorHandler.get();
424
0
}
425
426
427
428
void
429
Appender::setErrorHandler(std::unique_ptr<ErrorHandler> eh)
430
0
{
431
0
    if (! eh.get())
432
0
    {
433
        // We do not throw exception here since the cause is probably a
434
        // bad config file.
435
0
        helpers::getLogLog().warn(
436
0
            LOG4CPLUS_TEXT("You have tried to set a null error-handler."));
437
0
        return;
438
0
    }
439
440
0
    thread::MutexGuard guard (access_mutex);
441
442
0
    this->errorHandler = std::move(eh);
443
0
}
444
445
446
447
void
448
Appender::setLayout(std::unique_ptr<Layout> lo)
449
342k
{
450
342k
    thread::MutexGuard guard (access_mutex);
451
452
342k
    this->layout = std::move(lo);
453
342k
}
454
455
456
457
Layout*
458
Appender::getLayout()
459
0
{
460
0
    thread::MutexGuard guard (access_mutex);
461
462
0
    return layout.get();
463
0
}
464
465
466
void
467
Appender::setFilter(log4cplus::spi::FilterPtr f)
468
0
{
469
0
    thread::MutexGuard guard (access_mutex);
470
471
0
    filter = std::move (f);
472
0
}
473
474
475
log4cplus::spi::FilterPtr
476
Appender::getFilter() const
477
0
{
478
0
    thread::MutexGuard guard (access_mutex);
479
480
0
    return filter;
481
0
}
482
483
484
void
485
Appender::addFilter (log4cplus::spi::FilterPtr f)
486
0
{
487
0
    thread::MutexGuard guard (access_mutex);
488
489
0
    log4cplus::spi::FilterPtr filterChain = getFilter ();
490
0
    if (filterChain)
491
0
        filterChain->appendFilter (std::move (f));
492
0
    else
493
0
        filterChain = std::move (f);
494
495
0
    setFilter (filterChain);
496
0
}
497
498
499
void
500
Appender::addFilter (std::function<
501
    spi::FilterResult (const spi::InternalLoggingEvent &)> filterFunction)
502
0
{
503
0
    addFilter (
504
0
        spi::FilterPtr (new spi::FunctionFilter (std::move (filterFunction))));
505
0
}
506
507
508
} // namespace log4cplus