Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/log4cplus/src/hierarchy.cxx
Line
Count
Source
1
// Module:  Log4CPLUS
2
// File:    hierarchy.cxx
3
// Created: 6/2001
4
// Author:  Tad E. Smith
5
//
6
//
7
// Copyright 2001-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/hierarchy.h>
22
#include <log4cplus/helpers/loglog.h>
23
#include <log4cplus/spi/loggerimpl.h>
24
#include <log4cplus/spi/rootlogger.h>
25
#include <log4cplus/thread/syncprims-pub-impl.h>
26
#include <utility>
27
#include <limits>
28
29
30
namespace log4cplus
31
{
32
33
34
//////////////////////////////////////////////////////////////////////////////
35
// File "Local" methods
36
//////////////////////////////////////////////////////////////////////////////
37
38
namespace
39
{
40
41
static
42
bool startsWith(tstring const & teststr, tstring const & substr)
43
0
{
44
0
    bool val = false;
45
0
    tstring::size_type const len = substr.length();
46
0
    if (teststr.length() > len)
47
0
        val = teststr.compare (0, len, substr) == 0;
48
49
0
    return val;
50
0
}
51
52
} // namespace
53
54
55
//////////////////////////////////////////////////////////////////////////////
56
// Hierarchy static declarations
57
//////////////////////////////////////////////////////////////////////////////
58
59
const LogLevel Hierarchy::DISABLE_OFF = -1;
60
const LogLevel Hierarchy::DISABLE_OVERRIDE = -2;
61
62
63
64
//////////////////////////////////////////////////////////////////////////////
65
// Hierarchy ctor and dtor
66
//////////////////////////////////////////////////////////////////////////////
67
68
Hierarchy::Hierarchy()
69
70
  : defaultFactory(new DefaultLoggerFactory())
70
70
  , root(nullptr)
71
  // Don't disable any LogLevel level by default.
72
70
  , disableValue(DISABLE_OFF)
73
70
  , emittedNoAppenderWarning(false)
74
70
{
75
70
    root = Logger( new spi::RootLogger(*this, DEBUG_LOG_LEVEL) );
76
70
}
77
78
79
Hierarchy::~Hierarchy()
80
0
{
81
0
    shutdown();
82
0
}
83
84
85
86
//////////////////////////////////////////////////////////////////////////////
87
// Hierarchy public methods
88
//////////////////////////////////////////////////////////////////////////////
89
90
void
91
Hierarchy::clear()
92
0
{
93
0
    thread::MutexGuard guard (hashtable_mutex);
94
95
0
    provisionNodes.erase(provisionNodes.begin(), provisionNodes.end());
96
0
    loggerPtrs.erase(loggerPtrs.begin(), loggerPtrs.end());
97
0
}
98
99
100
bool
101
Hierarchy::exists(const tstring& name)
102
0
{
103
    // Root logger always does exist.
104
0
    if (name.empty ())
105
0
        return true;
106
107
0
    thread::MutexGuard guard (hashtable_mutex);
108
109
0
    auto it = loggerPtrs.find(name);
110
0
    return it != loggerPtrs.end();
111
0
}
112
113
114
void
115
Hierarchy::disable(const tstring& loglevelStr)
116
0
{
117
0
    if(disableValue != DISABLE_OVERRIDE) {
118
0
        disableValue = getLogLevelManager().fromString(loglevelStr);
119
0
    }
120
0
}
121
122
123
void
124
Hierarchy::disable(LogLevel ll)
125
0
{
126
0
    if(disableValue != DISABLE_OVERRIDE) {
127
0
        disableValue = ll;
128
0
    }
129
0
}
130
131
132
void
133
Hierarchy::disableAll()
134
0
{
135
0
    disable((std::numeric_limits<LogLevel>::max) ());
136
0
}
137
138
139
void
140
Hierarchy::disableDebug()
141
0
{
142
0
    disable(DEBUG_LOG_LEVEL);
143
0
}
144
145
146
void
147
Hierarchy::disableInfo()
148
0
{
149
0
    disable(INFO_LOG_LEVEL);
150
0
}
151
152
153
void
154
Hierarchy::enableAll()
155
0
{
156
0
    disableValue = DISABLE_OFF;
157
0
}
158
159
160
Logger
161
Hierarchy::getInstance(const tstring& name)
162
281k
{
163
281k
    return getInstance(name, *defaultFactory);
164
281k
}
165
166
167
Logger
168
Hierarchy::getInstance(const tstring& name, spi::LoggerFactory& factory)
169
281k
{
170
281k
    thread::MutexGuard guard (hashtable_mutex);
171
172
281k
    return getInstanceImpl(name, factory);
173
281k
}
174
175
176
LoggerList
177
Hierarchy::getCurrentLoggers()
178
398k
{
179
398k
    LoggerList ret;
180
181
398k
    {
182
398k
        thread::MutexGuard guard (hashtable_mutex);
183
398k
        initializeLoggerList(ret);
184
398k
    }
185
186
398k
    return ret;
187
398k
}
188
189
190
bool
191
Hierarchy::isDisabled(LogLevel level)
192
0
{
193
0
    return disableValue >= level;
194
0
}
195
196
197
Logger
198
Hierarchy::getRoot() const
199
630k
{
200
630k
    return root;
201
630k
}
202
203
204
void
205
Hierarchy::resetConfiguration()
206
304k
{
207
304k
    getRoot().setLogLevel(DEBUG_LOG_LEVEL);
208
304k
    disableValue = DISABLE_OFF;
209
210
304k
    shutdown();
211
212
304k
    LoggerList loggers = getCurrentLoggers();
213
304k
    for (auto & logger : loggers)
214
1.70M
    {
215
1.70M
        logger.setLogLevel(NOT_SET_LOG_LEVEL);
216
1.70M
        logger.setAdditivity(true);
217
1.70M
    }
218
219
304k
}
220
221
222
void
223
Hierarchy::setLoggerFactory(std::unique_ptr<spi::LoggerFactory> factory)
224
0
{
225
0
    defaultFactory = std::move(factory);
226
0
}
227
228
229
spi::LoggerFactory *
230
Hierarchy::getLoggerFactory()
231
0
{
232
0
    return defaultFactory.get();
233
0
}
234
235
236
// from global-init.cxx
237
void waitUntilEmptyThreadPoolQueue ();
238
239
void
240
Hierarchy::shutdown()
241
304k
{
242
304k
    waitUntilEmptyThreadPoolQueue ();
243
244
304k
    LoggerList loggers;
245
304k
    initializeLoggerList (loggers);
246
247
    // begin by closing nested appenders
248
    // then, remove all appenders
249
250
304k
    for (auto & appenderPtr : root.getAllAppenders())
251
116k
    {
252
116k
        Appender & appender = *appenderPtr;
253
116k
        appender.waitToFinishAsyncLogging ();
254
116k
    }
255
304k
    root.closeNestedAppenders();
256
304k
    root.removeAllAppenders();
257
258
    // repeat
259
304k
    for (auto & logger : loggers)
260
1.70M
    {
261
1.70M
        for (auto & appenderPtr : logger.getAllAppenders())
262
223k
        {
263
223k
            Appender & appender = *appenderPtr;
264
223k
            appender.waitToFinishAsyncLogging ();
265
223k
        }
266
1.70M
        logger.closeNestedAppenders();
267
1.70M
        logger.removeAllAppenders();
268
1.70M
    }
269
304k
}
270
271
272
273
//////////////////////////////////////////////////////////////////////////////
274
// Hierarchy private methods
275
//////////////////////////////////////////////////////////////////////////////
276
277
Logger
278
Hierarchy::getInstanceImpl(const tstring& name, spi::LoggerFactory& factory)
279
281k
{
280
281k
    Logger logger;
281
281k
    LoggerMap::iterator lm_it;
282
283
281k
    if (name.empty ())
284
0
        logger = root;
285
281k
    else if ((lm_it = loggerPtrs.find(name)) != loggerPtrs.end())
286
281k
        logger = lm_it->second;
287
166
    else
288
166
    {
289
        // Need to create a new logger
290
166
        logger = factory.makeNewLoggerInstance(name, *this);
291
166
        bool inserted = loggerPtrs.emplace (name, logger).second;
292
166
        if (! inserted)
293
0
        {
294
0
            helpers::getLogLog().error(
295
0
                LOG4CPLUS_TEXT("Hierarchy::getInstanceImpl()- Insert failed"),
296
0
                true);
297
0
        }
298
299
166
        auto pnm_it = provisionNodes.find(name);
300
166
        if (pnm_it != provisionNodes.end())
301
0
        {
302
0
            updateChildren(pnm_it->second, logger);
303
0
            bool deleted = (provisionNodes.erase(name) > 0);
304
0
            if (! deleted)
305
0
            {
306
0
                helpers::getLogLog().error(
307
0
                    LOG4CPLUS_TEXT("Hierarchy::getInstanceImpl()- Delete failed"),
308
0
                    true);
309
0
            }
310
0
        }
311
166
        updateParents(logger);
312
166
    }
313
314
281k
    return logger;
315
281k
}
316
317
318
void
319
Hierarchy::initializeLoggerList(LoggerList& list) const
320
703k
{
321
703k
    list.reserve (list.size () + loggerPtrs.size ());
322
703k
    for (auto & kv : loggerPtrs)
323
3.96M
        list.push_back(kv.second);
324
703k
}
325
326
327
void
328
Hierarchy::updateParents(Logger const & logger)
329
166
{
330
166
    tstring const & name = logger.getName();
331
166
    auto const length = name.length();
332
166
    bool parentFound = false;
333
166
    tstring substr;
334
335
    // if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
336
166
    for(std::size_t i=name.find_last_of(LOG4CPLUS_TEXT('.'), length-1);
337
166
        i != tstring::npos && i > 0;
338
166
        i = name.find_last_of(LOG4CPLUS_TEXT('.'), i-1))
339
130
    {
340
130
        substr.assign (name, 0, i);
341
342
130
        auto it = loggerPtrs.find(substr);
343
130
        if(it != loggerPtrs.end()) {
344
130
            parentFound = true;
345
130
            logger.value->parent = it->second.value;
346
130
            break;  // no need to update the ancestors of the closest ancestor
347
130
        }
348
0
        else {
349
0
            auto it2 = provisionNodes.find(substr);
350
0
            if(it2 != provisionNodes.end()) {
351
0
                it2->second.push_back(logger);
352
0
            }
353
0
            else {
354
0
                ProvisionNode node;
355
0
                node.push_back(logger);
356
0
                std::pair<ProvisionNodeMap::iterator, bool> tmp =
357
0
                    provisionNodes.emplace (substr, node);
358
0
                if(!tmp.second) {
359
0
                    helpers::getLogLog().error(
360
0
                        LOG4CPLUS_TEXT("Hierarchy::updateParents()- Insert failed"),
361
0
                        true);
362
0
                }
363
0
            }
364
0
        } // end if Logger found
365
130
    } // end for loop
366
367
166
    if(!parentFound) {
368
36
        logger.value->parent = root.value;
369
36
    }
370
166
}
371
372
373
void
374
Hierarchy::updateChildren(ProvisionNode& pn, Logger const & logger)
375
0
{
376
0
    for (Logger & c : pn)
377
0
    {
378
        // Unless this child already points to a correct (lower) parent,
379
        // make logger.parent point to c.parent and c.parent to logger.
380
0
        if( !startsWith(c.value->parent->getName(), logger.getName()) ) {
381
0
            logger.value->parent = c.value->parent;
382
0
            c.value->parent = logger.value;
383
0
        }
384
0
    }
385
0
}
386
387
388
} // namespace log4cplus