Coverage Report

Created: 2025-12-31 07:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/log4cplus/src/configurator.cxx
Line
Count
Source
1
// Module:  LOG4CPLUS
2
// File:    configurator.cxx
3
// Created: 3/2003
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/configurator.h>
22
#include <log4cplus/hierarchylocker.h>
23
#include <log4cplus/hierarchy.h>
24
#include <log4cplus/helpers/loglog.h>
25
#include <log4cplus/helpers/stringhelper.h>
26
#include <log4cplus/helpers/property.h>
27
#include <log4cplus/helpers/timehelper.h>
28
#include <log4cplus/helpers/fileinfo.h>
29
#include <log4cplus/thread/threads.h>
30
#include <log4cplus/thread/syncprims-pub-impl.h>
31
#include <log4cplus/spi/factory.h>
32
#include <log4cplus/spi/loggerimpl.h>
33
#include <log4cplus/internal/env.h>
34
35
#ifdef LOG4CPLUS_HAVE_SYS_TYPES_H
36
#include <sys/types.h>
37
#endif
38
#ifdef LOG4CPLUS_HAVE_SYS_STAT_H
39
#include <sys/stat.h>
40
#endif
41
42
#ifdef LOG4CPLUS_HAVE_STDLIB_H
43
#include <stdlib.h>
44
#endif
45
#if defined (_WIN32)
46
#include <tchar.h>
47
#endif
48
49
#include <algorithm>
50
#include <cstdlib>
51
#include <iterator>
52
#include <sstream>
53
54
55
namespace log4cplus
56
{
57
58
59
void initializeLog4cplus();
60
61
62
namespace
63
{
64
    //! Translates encoding in ProtpertyConfigurator::PCFlags
65
    //! to helpers::Properties::PFlags
66
    static
67
    unsigned
68
    pcflag_to_pflags_encoding (unsigned pcflags)
69
123k
    {
70
123k
        unsigned pflags = 0;
71
123k
        switch (pcflags
72
123k
            & (PropertyConfigurator::fEncodingMask
73
123k
                << PropertyConfigurator::fEncodingShift))
74
123k
        {
75
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE)
76
        case PropertyConfigurator::fUTF8:
77
            pflags |= helpers::Properties::fUTF8;
78
            break;
79
#endif
80
81
#if (defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) || defined (WIN32)) \
82
    && defined (UNICODE)
83
        case PropertyConfigurator::fUTF16:
84
            pflags |= helpers::Properties::fUTF16;
85
            break;
86
#endif
87
88
#if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE)
89
        case PropertyConfigurator::fUTF32:
90
            pflags |= helpers::Properties::fUTF32;
91
            break;
92
#endif
93
94
123k
        case PropertyConfigurator::fUnspecEncoding:;
95
123k
        default:
96
123k
            break;
97
123k
        }
98
99
123k
        if ((pcflags & PropertyConfigurator::fThrow) != 0)
100
0
            pflags |= helpers::Properties::fThrow;
101
102
123k
        return pflags;
103
123k
    }
104
105
} // namespace
106
107
108
109
//////////////////////////////////////////////////////////////////////////////
110
// PropertyConfigurator ctor and dtor
111
//////////////////////////////////////////////////////////////////////////////
112
113
PropertyConfigurator::PropertyConfigurator(const tstring& propertyFile,
114
    Hierarchy& hier, unsigned f)
115
123k
    : h(hier)
116
123k
    , propertyFilename(propertyFile)
117
123k
    , properties(propertyFile, pcflag_to_pflags_encoding (f))
118
123k
    , flags (f)
119
123k
{
120
123k
    init();
121
123k
}
122
123
124
PropertyConfigurator::PropertyConfigurator(const helpers::Properties& props,
125
    Hierarchy& hier, unsigned f)
126
0
    : h(hier)
127
0
    , propertyFilename( LOG4CPLUS_TEXT("UNAVAILABLE") )
128
0
    , properties( props )
129
0
    , flags (f)
130
0
{
131
0
    init();
132
0
}
133
134
135
PropertyConfigurator::PropertyConfigurator(tistream& propertyStream,
136
    Hierarchy& hier, unsigned f)
137
0
    : h(hier)
138
0
    , propertyFilename( LOG4CPLUS_TEXT("UNAVAILABLE") )
139
0
    , properties(propertyStream)
140
0
    , flags (f)
141
0
{
142
0
    init();
143
0
}
144
145
146
void
147
PropertyConfigurator::init()
148
123k
{
149
123k
    replaceEnvironVariables();
150
123k
    properties = properties.getPropertySubset( LOG4CPLUS_TEXT("log4cplus.") );
151
123k
}
152
153
154
PropertyConfigurator::~PropertyConfigurator()
155
123k
{
156
123k
}
157
158
159
160
//////////////////////////////////////////////////////////////////////////////
161
// PropertyConfigurator static methods
162
//////////////////////////////////////////////////////////////////////////////
163
164
void
165
PropertyConfigurator::doConfigure(const tstring& file, Hierarchy& h,
166
    unsigned flags)
167
0
{
168
0
    PropertyConfigurator tmp(file, h, flags);
169
0
    tmp.configure();
170
0
}
171
172
173
174
//////////////////////////////////////////////////////////////////////////////
175
// PropertyConfigurator public methods
176
//////////////////////////////////////////////////////////////////////////////
177
178
void
179
PropertyConfigurator::configure()
180
123k
{
181
    // Configure log4cplus internals.
182
123k
    bool internal_debugging = false;
183
123k
    if (properties.getBool (internal_debugging, LOG4CPLUS_TEXT ("configDebug")))
184
0
        helpers::getLogLog ().setInternalDebugging (internal_debugging);
185
186
123k
    bool quiet_mode = false;
187
123k
    if (properties.getBool (quiet_mode, LOG4CPLUS_TEXT ("quietMode")))
188
0
        helpers::getLogLog ().setQuietMode (quiet_mode);
189
190
123k
    bool disable_override = false;
191
123k
    properties.getBool (disable_override, LOG4CPLUS_TEXT ("disableOverride"));
192
193
123k
    initializeLog4cplus();
194
195
123k
    unsigned int thread_pool_size;
196
123k
    if (properties.getUInt (thread_pool_size, LOG4CPLUS_TEXT ("threadPoolSize")))
197
0
        thread_pool_size = (std::min) (thread_pool_size, 1024u);
198
123k
    else
199
123k
        thread_pool_size = 4;
200
201
123k
    setThreadPoolSize (thread_pool_size);
202
203
123k
    bool block;
204
123k
    if (properties.getBool (block, LOG4CPLUS_TEXT ("threadPoolBlockOnFull")))
205
0
        setThreadPoolBlockOnFull (block);
206
207
123k
    unsigned int queue_size_limit;
208
123k
    if (properties.getUInt (queue_size_limit, LOG4CPLUS_TEXT ("threadPoolQueueSizeLimit")))
209
0
        setThreadPoolQueueSizeLimit ((std::max) (queue_size_limit, 100u));
210
211
123k
    configureAppenders();
212
123k
    configureLoggers();
213
123k
    configureAdditivity();
214
215
123k
    if (disable_override)
216
0
        h.disable (Hierarchy::DISABLE_OVERRIDE);
217
218
219
220
    // Erase the appenders so that we are not artificially keeping them "alive".
221
123k
    appenders.clear ();
222
123k
}
223
224
225
helpers::Properties const &
226
PropertyConfigurator::getProperties () const
227
0
{
228
0
    return properties;
229
0
}
230
231
232
log4cplus::tstring const &
233
PropertyConfigurator::getPropertyFilename () const
234
0
{
235
0
    return propertyFilename;
236
0
}
237
238
239
//////////////////////////////////////////////////////////////////////////////
240
// PropertyConfigurator protected methods
241
//////////////////////////////////////////////////////////////////////////////
242
243
void
244
PropertyConfigurator::reconfigure()
245
0
{
246
0
    properties = helpers::Properties(propertyFilename);
247
0
    init();
248
0
    configure();
249
0
}
250
251
252
void
253
PropertyConfigurator::replaceEnvironVariables()
254
123k
{
255
123k
    tstring val, subKey, subVal;
256
123k
    std::vector<tstring> keys;
257
123k
    bool const rec_exp
258
123k
        = !! (flags & PropertyConfigurator::fRecursiveExpansion);
259
123k
    bool changed;
260
261
123k
    do
262
123k
    {
263
123k
        changed = false;
264
123k
        keys = properties.propertyNames();
265
123k
        for (std::vector<tstring>::const_iterator it = keys.begin();
266
123k
            it != keys.end(); ++it)
267
0
        {
268
0
            tstring const & key = *it;
269
0
            val = properties.getProperty(key);
270
271
0
            subKey.clear ();
272
0
            if (helpers::substVars(subKey, key, properties, helpers::getLogLog(), flags))
273
0
            {
274
0
                properties.removeProperty(key);
275
0
                properties.setProperty(subKey, val);
276
0
                changed = true;
277
0
            }
278
279
0
            subVal.clear ();
280
0
            if (helpers::substVars(subVal, val, properties, helpers::getLogLog(), flags))
281
0
            {
282
0
                properties.setProperty(subKey, subVal);
283
0
                changed = true;
284
0
            }
285
0
        }
286
123k
    }
287
123k
    while (changed && rec_exp);
288
123k
}
289
290
291
292
void
293
PropertyConfigurator::configureLoggers()
294
123k
{
295
123k
    if(properties.exists( LOG4CPLUS_TEXT("rootLogger") ))
296
123k
    {
297
123k
        Logger root = h.getRoot();
298
123k
        configureLogger(root,
299
123k
                        properties.getProperty(LOG4CPLUS_TEXT("rootLogger")));
300
123k
    }
301
302
123k
    helpers::Properties loggerProperties
303
123k
        = properties.getPropertySubset(LOG4CPLUS_TEXT("logger."));
304
123k
    std::vector<tstring> loggers = loggerProperties.propertyNames();
305
123k
    for (tstring const & loggerName : loggers)
306
0
    {
307
0
        Logger log = getLogger(loggerName);
308
0
        configureLogger(log, loggerProperties.getProperty(loggerName));
309
0
    }
310
123k
}
311
312
313
314
void
315
PropertyConfigurator::configureLogger(Logger logger, const tstring& config)
316
123k
{
317
    // Remove all spaces from config
318
123k
    tstring configString;
319
123k
    std::remove_copy_if(config.begin(), config.end(),
320
123k
        std::back_inserter (configString),
321
1.60M
        [](tchar const ch) -> bool { return ch == LOG4CPLUS_TEXT(' '); });
322
323
    // "Tokenize" configString
324
123k
    std::vector<tstring> tokens;
325
123k
    helpers::tokenize(configString, LOG4CPLUS_TEXT(','),
326
123k
        std::back_insert_iterator<std::vector<tstring> >(tokens));
327
328
123k
    if (tokens.empty ())
329
0
    {
330
0
        helpers::getLogLog().error(
331
0
            LOG4CPLUS_TEXT("PropertyConfigurator::configureLogger()")
332
0
            LOG4CPLUS_TEXT("- Invalid config string(Logger = ")
333
0
            + logger.getName()
334
0
            + LOG4CPLUS_TEXT("): \"")
335
0
            + config
336
0
            + LOG4CPLUS_TEXT("\""));
337
0
        return;
338
0
    }
339
340
    // Set the loglevel
341
123k
    tstring const & loglevel = tokens[0];
342
123k
    if (loglevel != LOG4CPLUS_TEXT("INHERITED"))
343
123k
        logger.setLogLevel( getLogLevelManager().fromString(loglevel) );
344
0
    else
345
0
        logger.setLogLevel (NOT_SET_LOG_LEVEL);
346
347
    // Remove all existing appenders first so that we do not duplicate output.
348
123k
    logger.removeAllAppenders ();
349
350
    // Set the Appenders
351
246k
    for(std::vector<tstring>::size_type j=1; j<tokens.size(); ++j)
352
123k
    {
353
123k
        auto appenderIt = appenders.find(tokens[j]);
354
123k
        if (appenderIt == appenders.end())
355
0
        {
356
0
            helpers::getLogLog().error(
357
0
                LOG4CPLUS_TEXT("PropertyConfigurator::configureLogger()")
358
0
                LOG4CPLUS_TEXT("- Invalid appender: ")
359
0
                + tokens[j]);
360
0
            continue;
361
0
        }
362
123k
        addAppender(logger, appenderIt->second);
363
123k
    }
364
123k
}
365
366
367
368
void
369
PropertyConfigurator::configureAppenders()
370
123k
{
371
123k
    helpers::Properties appenderProperties =
372
123k
        properties.getPropertySubset(LOG4CPLUS_TEXT("appender."));
373
123k
    std::vector<tstring> appendersProps = appenderProperties.propertyNames();
374
123k
    tstring factoryName;
375
123k
    for (tstring & appenderName : appendersProps)
376
246k
    {
377
246k
        if (appenderName.find (LOG4CPLUS_TEXT('.')) == tstring::npos)
378
123k
        {
379
123k
            factoryName = appenderProperties.getProperty(appenderName);
380
123k
            spi::AppenderFactory* factory
381
123k
                = spi::getAppenderFactoryRegistry().get(factoryName);
382
123k
            if (! factory)
383
0
            {
384
0
                helpers::getLogLog().error(
385
0
                    LOG4CPLUS_TEXT("PropertyConfigurator::configureAppenders()")
386
0
                    LOG4CPLUS_TEXT("- Cannot find AppenderFactory: ")
387
0
                    + factoryName);
388
0
                continue;
389
0
            }
390
391
123k
            helpers::Properties props_subset
392
123k
                = appenderProperties.getPropertySubset(appenderName
393
123k
                + LOG4CPLUS_TEXT("."));
394
123k
            try
395
123k
            {
396
123k
                SharedAppenderPtr appender
397
123k
                    = factory->createObject(props_subset);
398
123k
                if (! appender)
399
0
                {
400
0
                    helpers::getLogLog().error(
401
0
                        LOG4CPLUS_TEXT("PropertyConfigurator::")
402
0
                        LOG4CPLUS_TEXT("configureAppenders()")
403
0
                        LOG4CPLUS_TEXT("- Failed to create Appender: ")
404
0
                        + appenderName);
405
0
                }
406
123k
                else
407
123k
                {
408
123k
                    appender->setName(appenderName);
409
123k
                    appenders[std::move (appenderName)] = appender;
410
123k
                }
411
123k
            }
412
123k
            catch(std::exception const & e)
413
123k
            {
414
0
                helpers::getLogLog().error(
415
0
                    LOG4CPLUS_TEXT("PropertyConfigurator::")
416
0
                    LOG4CPLUS_TEXT("configureAppenders()")
417
0
                    LOG4CPLUS_TEXT("- Error while creating Appender: ")
418
0
                    + LOG4CPLUS_C_STR_TO_TSTRING(e.what()));
419
0
            }
420
123k
        }
421
246k
    } // end for loop
422
123k
}
423
424
425
void
426
PropertyConfigurator::configureAdditivity()
427
123k
{
428
123k
    helpers::Properties additivityProperties =
429
123k
        properties.getPropertySubset(LOG4CPLUS_TEXT("additivity."));
430
123k
    std::vector<tstring> additivitysProps
431
123k
        = additivityProperties.propertyNames();
432
433
123k
    for (tstring const & loggerName : additivitysProps)
434
0
    {
435
0
        Logger logger = getLogger(loggerName);
436
0
        bool additivity;
437
0
        if (additivityProperties.getBool (additivity, loggerName))
438
0
            logger.setAdditivity (additivity);
439
0
    }
440
123k
}
441
442
443
444
Logger
445
PropertyConfigurator::getLogger(const tstring& name)
446
0
{
447
0
    return h.getInstance(name);
448
0
}
449
450
451
void
452
PropertyConfigurator::addAppender(Logger &logger, SharedAppenderPtr& appender)
453
123k
{
454
123k
    logger.addAppender(appender);
455
123k
}
456
457
458
459
//////////////////////////////////////////////////////////////////////////////
460
// BasicConfigurator ctor and dtor
461
//////////////////////////////////////////////////////////////////////////////
462
463
log4cplus::tstring DISABLE_OVERRIDE_KEY (
464
    LOG4CPLUS_TEXT ("log4cplus.disableOverride"));
465
466
BasicConfigurator::BasicConfigurator(Hierarchy& hier, bool logToStdErr)
467
123k
    : PropertyConfigurator( LOG4CPLUS_TEXT(""), hier )
468
123k
{
469
123k
    properties.setProperty(LOG4CPLUS_TEXT("rootLogger"),
470
123k
                           LOG4CPLUS_TEXT("DEBUG, STDOUT"));
471
123k
    properties.setProperty(LOG4CPLUS_TEXT("appender.STDOUT"),
472
123k
                           LOG4CPLUS_TEXT("log4cplus::ConsoleAppender"));
473
123k
    properties.setProperty(LOG4CPLUS_TEXT("appender.STDOUT.logToStdErr"),
474
123k
                           logToStdErr ? LOG4CPLUS_TEXT("1")
475
123k
                           : LOG4CPLUS_TEXT("0"));
476
123k
}
477
478
479
480
481
BasicConfigurator::~BasicConfigurator()
482
{
483
}
484
485
486
//////////////////////////////////////////////////////////////////////////////
487
// BasicConfigurator static methods
488
//////////////////////////////////////////////////////////////////////////////
489
490
void
491
BasicConfigurator::doConfigure(Hierarchy& h, bool logToStdErr)
492
0
{
493
0
    BasicConfigurator tmp(h, logToStdErr);
494
0
    tmp.configure();
495
0
}
496
497
498
#if !defined(LOG4CPLUS_SINGLE_THREADED)
499
500
//////////////////////////////////////////////////////////////////////////////
501
// ConfigurationWatchDogThread implementation
502
//////////////////////////////////////////////////////////////////////////////
503
504
class ConfigurationWatchDogThread
505
    : public thread::AbstractThread,
506
      public PropertyConfigurator
507
{
508
public:
509
    ConfigurationWatchDogThread(const tstring& file, unsigned int millis)
510
0
        : PropertyConfigurator(file)
511
0
        , waitMillis(millis < 1000 ? 1000 : millis)
512
0
        , shouldTerminate(false)
513
0
        , lock(nullptr)
514
0
    {
515
0
        lastFileInfo.mtime = helpers::now ();
516
0
        lastFileInfo.size = 0;
517
0
        lastFileInfo.is_link = false;
518
519
0
        updateLastModInfo();
520
0
    }
521
522
    virtual ~ConfigurationWatchDogThread ()
523
0
    { }
524
525
    void terminate ()
526
0
    {
527
0
        shouldTerminate.signal ();
528
0
        join ();
529
0
    }
530
531
protected:
532
    virtual void run();
533
    virtual Logger getLogger(const tstring& name);
534
    virtual void addAppender(Logger &logger, SharedAppenderPtr& appender);
535
536
    bool checkForFileModification();
537
    void updateLastModInfo();
538
539
private:
540
    ConfigurationWatchDogThread (ConfigurationWatchDogThread const &);
541
    ConfigurationWatchDogThread & operator = (
542
        ConfigurationWatchDogThread const &);
543
544
    unsigned int const waitMillis;
545
    thread::ManualResetEvent shouldTerminate;
546
    helpers::FileInfo lastFileInfo;
547
    HierarchyLocker* lock;
548
};
549
550
551
void
552
ConfigurationWatchDogThread::run()
553
0
{
554
0
    while (! shouldTerminate.timed_wait (waitMillis))
555
0
    {
556
0
        bool modified = checkForFileModification();
557
0
        if(modified) {
558
            // Lock the Hierarchy
559
0
            HierarchyLocker theLock(h);
560
0
            lock = &theLock;
561
562
            // reconfigure the Hierarchy
563
0
            theLock.resetConfiguration();
564
0
            reconfigure();
565
0
            updateLastModInfo();
566
567
            // release the lock
568
0
            lock = nullptr;
569
0
        }
570
0
    }
571
0
}
572
573
574
Logger
575
ConfigurationWatchDogThread::getLogger(const tstring& name)
576
0
{
577
0
    if(lock)
578
0
        return lock->getInstance(name);
579
0
    else
580
0
        return PropertyConfigurator::getLogger(name);
581
0
}
582
583
584
void
585
ConfigurationWatchDogThread::addAppender(Logger& logger,
586
                                         SharedAppenderPtr& appender)
587
0
{
588
0
    if(lock)
589
0
        lock->addAppender(logger, appender);
590
0
    else
591
0
        PropertyConfigurator::addAppender(logger, appender);
592
0
}
593
594
595
bool
596
ConfigurationWatchDogThread::checkForFileModification()
597
0
{
598
0
    helpers::FileInfo fi;
599
600
0
    if (helpers::getFileInfo (&fi, propertyFilename) != 0)
601
0
        return false;
602
603
0
    bool modified = fi.mtime > lastFileInfo.mtime
604
0
        || fi.size != lastFileInfo.size;
605
606
0
#if defined(LOG4CPLUS_HAVE_LSTAT)
607
0
    if (!modified && fi.is_link)
608
0
    {
609
0
        struct stat fileStatus;
610
0
        if (lstat(LOG4CPLUS_TSTRING_TO_STRING(propertyFilename).c_str(),
611
0
                &fileStatus) == -1)
612
0
            return false;
613
614
0
        helpers::Time linkModTime(helpers::from_time_t (fileStatus.st_mtime));
615
0
        modified = (linkModTime > fi.mtime);
616
0
    }
617
0
#endif
618
619
0
    return modified;
620
0
}
621
622
623
624
void
625
ConfigurationWatchDogThread::updateLastModInfo()
626
0
{
627
0
    helpers::FileInfo fi;
628
629
0
    if (helpers::getFileInfo (&fi, propertyFilename) == 0)
630
0
        lastFileInfo = fi;
631
0
}
632
633
634
635
//////////////////////////////////////////////////////////////////////////////
636
// PropertyConfiguratorWatchDog ctor and dtor
637
//////////////////////////////////////////////////////////////////////////////
638
639
ConfigureAndWatchThread::ConfigureAndWatchThread(const tstring& file,
640
    unsigned int millis)
641
0
    : watchDogThread(nullptr)
642
0
{
643
0
    watchDogThread = new ConfigurationWatchDogThread(file, millis);
644
0
    watchDogThread->addReference ();
645
0
    watchDogThread->configure();
646
0
    watchDogThread->start();
647
0
}
648
649
650
ConfigureAndWatchThread::~ConfigureAndWatchThread()
651
0
{
652
0
    if (watchDogThread)
653
0
    {
654
0
        watchDogThread->terminate();
655
0
        watchDogThread->removeReference ();
656
0
    }
657
0
}
658
659
660
#endif
661
662
663
} // namespace log4cplus