Coverage Report

Created: 2025-07-18 06:17

/src/logging-log4cxx/src/main/cpp/hierarchy.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/hierarchy.h>
19
#if LOG4CXX_ABI_VERSION <= 15
20
#include <log4cxx/defaultloggerfactory.h>
21
#endif
22
#include <log4cxx/helpers/loglog.h>
23
#include <log4cxx/appender.h>
24
#include <log4cxx/helpers/stringhelper.h>
25
#include <log4cxx/spi/rootlogger.h>
26
#include <algorithm>
27
#include <map>
28
#include <mutex>
29
#include <vector>
30
31
32
using namespace LOG4CXX_NS;
33
using namespace LOG4CXX_NS::spi;
34
using namespace LOG4CXX_NS::helpers;
35
36
37
typedef std::map<LogString, LoggerPtr> LoggerMap;
38
typedef std::map<LogString, ProvisionNode> ProvisionNodeMap;
39
40
struct Hierarchy::HierarchyPrivate
41
{
42
  HierarchyPrivate()
43
5
    : configured(false)
44
5
    , emittedNoAppenderWarning(false)
45
5
    , emittedNoResourceBundleWarning(false)
46
5
    , thresholdInt(Level::ALL_INT)
47
5
  {
48
5
  }
49
50
  helpers::Pool pool;
51
  mutable std::recursive_mutex mutex;
52
  mutable std::mutex configuredMutex;
53
  bool configured;
54
  bool emittedNoAppenderWarning;
55
  bool emittedNoResourceBundleWarning;
56
  int thresholdInt;
57
58
  spi::HierarchyEventListenerList listeners;
59
  LoggerPtr root;
60
  LevelPtr threshold;
61
  LoggerMap loggers;
62
  ProvisionNodeMap provisionNodes;
63
64
  std::vector<AppenderPtr> allAppenders;
65
66
  mutable std::mutex listenerMutex;
67
};
68
69
IMPLEMENT_LOG4CXX_OBJECT(Hierarchy)
70
71
Hierarchy::Hierarchy() :
72
5
  m_priv(std::make_unique<HierarchyPrivate>())
73
5
{
74
5
}
Unexecuted instantiation: log4cxx::Hierarchy::Hierarchy()
log4cxx::Hierarchy::Hierarchy()
Line
Count
Source
72
5
  m_priv(std::make_unique<HierarchyPrivate>())
73
5
{
74
5
}
75
76
Hierarchy::~Hierarchy()
77
5
{
78
5
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
79
5
  for (auto& item : m_priv->loggers)
80
1
  {
81
1
    if (auto& pLogger = item.second)
82
1
    {
83
1
      pLogger->removeHierarchy();
84
1
      pLogger->removeAllAppenders();
85
1
    }
86
1
  }
87
5
  if (m_priv->root)
88
3
  {
89
3
    m_priv->root->removeHierarchy();
90
3
    m_priv->root->removeAllAppenders();
91
3
  }
92
5
}
93
94
void Hierarchy::addHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener)
95
0
{
96
0
  std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
97
98
0
  if (std::find(m_priv->listeners.begin(), m_priv->listeners.end(), listener) != m_priv->listeners.end())
99
0
  {
100
0
    LogLog::warn(LOG4CXX_STR("Ignoring attempt to add an existent listener."));
101
0
  }
102
0
  else
103
0
  {
104
0
    m_priv->listeners.push_back(listener);
105
0
  }
106
0
}
107
108
void Hierarchy::removeHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener)
109
0
{
110
0
  std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
111
112
0
    auto found = std::find(m_priv->listeners.begin(), m_priv->listeners.end(), listener);
113
0
    if(found != m_priv->listeners.end()){
114
0
        m_priv->listeners.erase(found);
115
0
    }
116
0
}
117
118
void Hierarchy::clear()
119
0
{
120
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
121
0
  m_priv->loggers.clear();
122
0
}
123
124
void Hierarchy::emitNoAppenderWarning(const Logger* logger)
125
0
{
126
0
  bool emitWarning = false;
127
0
  {
128
0
    std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
129
0
    emitWarning = !m_priv->emittedNoAppenderWarning;
130
0
    m_priv->emittedNoAppenderWarning = true;
131
0
  }
132
133
  // No appender in hierarchy, warn user only once.
134
0
  if (emitWarning)
135
0
  {
136
0
    LogLog::warn(((LogString) LOG4CXX_STR("No appender could be found for logger ("))
137
0
      + logger->getName() + LOG4CXX_STR(")."));
138
0
    LogLog::warn(LOG4CXX_STR("Please initialize the log4cxx system properly."));
139
0
  }
140
0
}
141
142
143
LoggerPtr Hierarchy::exists(const LogString& name)
144
0
{
145
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
146
147
0
  LoggerPtr logger;
148
0
  LoggerMap::iterator it = m_priv->loggers.find(name);
149
150
0
  if (it != m_priv->loggers.end())
151
0
  {
152
0
    logger = it->second;
153
0
  }
154
155
156
0
  return logger;
157
0
}
Unexecuted instantiation: log4cxx::Hierarchy::exists(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: log4cxx::Hierarchy::exists(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
158
159
void Hierarchy::setThreshold(const LevelPtr& l)
160
13
{
161
13
  if (l != 0)
162
13
  {
163
13
    std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
164
13
    setThresholdInternal(l);
165
13
  }
166
13
}
167
168
void Hierarchy::setThreshold(const LogString& levelStr)
169
182
{
170
182
  LevelPtr l(Level::toLevelLS(levelStr, 0));
171
172
182
  if (l != 0)
173
13
  {
174
13
    setThreshold(l);
175
13
  }
176
169
  else
177
169
  {
178
169
    LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \""))
179
169
      + levelStr + LOG4CXX_STR("\"."));
180
169
  }
181
182
}
log4cxx::Hierarchy::setThreshold(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
169
46
{
170
46
  LevelPtr l(Level::toLevelLS(levelStr, 0));
171
172
46
  if (l != 0)
173
5
  {
174
5
    setThreshold(l);
175
5
  }
176
41
  else
177
41
  {
178
41
    LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \""))
179
41
      + levelStr + LOG4CXX_STR("\"."));
180
41
  }
181
46
}
log4cxx::Hierarchy::setThreshold(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
Line
Count
Source
169
136
{
170
136
  LevelPtr l(Level::toLevelLS(levelStr, 0));
171
172
136
  if (l != 0)
173
8
  {
174
8
    setThreshold(l);
175
8
  }
176
128
  else
177
128
  {
178
128
    LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \""))
179
128
      + levelStr + LOG4CXX_STR("\"."));
180
128
  }
181
136
}
182
183
void Hierarchy::setThresholdInternal(const LevelPtr& l)
184
13
{
185
13
  m_priv->thresholdInt = l->toInt();
186
13
  m_priv->threshold = l;
187
188
13
  if (m_priv->thresholdInt != Level::ALL_INT)
189
13
  {
190
13
    m_priv->configured = true;
191
13
  }
192
13
}
193
194
void Hierarchy::fireAddAppenderEvent(const Logger* logger, const Appender* appender)
195
527
{
196
527
  setConfigured(true);
197
527
  HierarchyEventListenerList clonedList;
198
527
  {
199
527
    std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
200
527
    clonedList = m_priv->listeners;
201
527
  }
202
203
527
  for (auto& item : clonedList)
204
0
    item->addAppenderEvent(logger, appender);
205
527
}
206
207
void Hierarchy::fireRemoveAppenderEvent(const Logger* logger, const Appender* appender)
208
209
525
{
210
525
  HierarchyEventListenerList clonedList;
211
525
  {
212
525
    std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
213
525
    clonedList = m_priv->listeners;
214
525
  }
215
525
  for (auto& item : clonedList)
216
0
    item->removeAppenderEvent(logger, appender);
217
525
}
218
219
LevelPtr Hierarchy::getThreshold() const
220
0
{
221
0
  return m_priv->threshold ? m_priv->threshold : Level::getAll();
222
0
}
223
224
LoggerPtr Hierarchy::getLogger(const LogString& name)
225
525
{
226
525
#if LOG4CXX_ABI_VERSION <= 15
227
525
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<DefaultLoggerFactory>();
228
#else
229
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<LoggerFactory>();
230
#endif
231
525
  return getLogger(name, defaultFactory);
232
525
}
log4cxx::Hierarchy::getLogger(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
225
525
{
226
525
#if LOG4CXX_ABI_VERSION <= 15
227
525
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<DefaultLoggerFactory>();
228
#else
229
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<LoggerFactory>();
230
#endif
231
525
  return getLogger(name, defaultFactory);
232
525
}
Unexecuted instantiation: log4cxx::Hierarchy::getLogger(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&)
233
234
LoggerPtr Hierarchy::getLogger(const LogString& name,
235
  const spi::LoggerFactoryPtr& factory)
236
525
{
237
525
  auto root = getRootLogger();
238
525
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
239
240
525
  LoggerMap::iterator it = m_priv->loggers.find(name);
241
525
  LoggerPtr result;
242
243
525
  if (it != m_priv->loggers.end())
244
524
  {
245
524
    result = it->second;
246
524
  }
247
525
  if (!result && factory)
248
1
  {
249
1
#if LOG4CXX_ABI_VERSION <= 15
250
1
    LoggerPtr logger(factory->makeNewLoggerInstance(m_priv->pool, name));
251
#else
252
    LoggerPtr logger(factory->makeNewLoggerInstance(name));
253
#endif
254
1
    logger->setHierarchy(this);
255
1
    m_priv->loggers.insert(LoggerMap::value_type(name, logger));
256
257
1
    ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(name);
258
259
1
    if (it2 != m_priv->provisionNodes.end())
260
0
    {
261
0
      updateChildren(it2->second, logger);
262
0
      m_priv->provisionNodes.erase(it2);
263
0
    }
264
265
1
    updateParents(logger, root);
266
1
    result = logger;
267
1
  }
268
525
  return result;
269
270
525
}
log4cxx::Hierarchy::getLogger(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<log4cxx::spi::LoggerFactory> const&)
Line
Count
Source
236
525
{
237
525
  auto root = getRootLogger();
238
525
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
239
240
525
  LoggerMap::iterator it = m_priv->loggers.find(name);
241
525
  LoggerPtr result;
242
243
525
  if (it != m_priv->loggers.end())
244
524
  {
245
524
    result = it->second;
246
524
  }
247
525
  if (!result && factory)
248
1
  {
249
1
#if LOG4CXX_ABI_VERSION <= 15
250
1
    LoggerPtr logger(factory->makeNewLoggerInstance(m_priv->pool, name));
251
#else
252
    LoggerPtr logger(factory->makeNewLoggerInstance(name));
253
#endif
254
1
    logger->setHierarchy(this);
255
1
    m_priv->loggers.insert(LoggerMap::value_type(name, logger));
256
257
1
    ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(name);
258
259
1
    if (it2 != m_priv->provisionNodes.end())
260
0
    {
261
0
      updateChildren(it2->second, logger);
262
0
      m_priv->provisionNodes.erase(it2);
263
0
    }
264
265
1
    updateParents(logger, root);
266
1
    result = logger;
267
1
  }
268
525
  return result;
269
270
525
}
Unexecuted instantiation: log4cxx::Hierarchy::getLogger(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::shared_ptr<log4cxx::spi::LoggerFactory> const&)
271
272
LoggerList Hierarchy::getCurrentLoggers() const
273
0
{
274
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
275
276
0
  LoggerList v;
277
0
  for (auto& item : m_priv->loggers)
278
0
  {
279
0
    if (auto pLogger = item.second)
280
0
      v.push_back(pLogger);
281
0
  }
282
0
  return v;
283
0
}
284
285
LoggerPtr Hierarchy::getRootLogger() const
286
1.40k
{
287
1.40k
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
288
1.40k
  if (!m_priv->root)
289
3
  {
290
3
    m_priv->root = std::make_shared<RootLogger>(Level::getDebug());
291
3
    m_priv->root->setHierarchy(const_cast<Hierarchy*>(this));
292
3
  }
293
294
1.40k
  return m_priv->root;
295
1.40k
}
296
297
bool Hierarchy::isDisabled(int level) const
298
484k
{
299
484k
  return m_priv->thresholdInt > level;
300
484k
}
301
302
void Hierarchy::ensureIsConfigured(std::function<void()> configurator)
303
1.40k
{
304
1.40k
  std::lock_guard<std::mutex> lock(m_priv->configuredMutex);
305
1.40k
  if (!m_priv->configured)
306
525
  {
307
525
    configurator();
308
525
    m_priv->configured = true;
309
525
  }
310
1.40k
}
311
312
void Hierarchy::resetConfiguration()
313
0
{
314
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
315
316
0
  if (m_priv->root)
317
0
  {
318
0
    m_priv->root->setLevel(Level::getDebug());
319
0
    m_priv->root->setResourceBundle(0);
320
0
  }
321
0
  setThresholdInternal(Level::getAll());
322
323
0
  shutdownInternal();
324
325
0
  for (auto& item : m_priv->loggers)
326
0
  {
327
0
    if (auto pLogger = item.second)
328
0
    {
329
0
      pLogger->setLevel(0);
330
0
      pLogger->setAdditivity(true);
331
0
      pLogger->setResourceBundle(0);
332
0
    }
333
0
  }
334
0
}
335
336
void Hierarchy::shutdown()
337
525
{
338
525
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
339
340
525
  shutdownInternal();
341
525
}
342
343
void Hierarchy::shutdownInternal()
344
525
{
345
525
  m_priv->configured = false;
346
347
  // begin by closing nested appenders
348
525
  if (m_priv->root)
349
525
    m_priv->root->closeNestedAppenders();
350
351
525
  for (auto& item : m_priv->loggers)
352
525
  {
353
525
    if (auto pLogger = item.second)
354
525
      pLogger->closeNestedAppenders();
355
525
  }
356
357
  // then, remove all appenders
358
525
  if (m_priv->root)
359
525
    m_priv->root->removeAllAppenders();
360
361
525
  for (auto& item : m_priv->loggers)
362
525
  {
363
525
    if (auto pLogger = item.second)
364
525
      pLogger->removeAllAppenders();
365
525
  }
366
525
}
367
368
void Hierarchy::updateParents(const LoggerPtr& logger, const LoggerPtr& root)
369
1
{
370
1
  const LogString name(logger->getName());
371
1
  size_t length = name.size();
372
1
  bool parentFound = false;
373
374
375
  // if name = "w.x.y.z", loop through "w.x.y", "w.x" and "w", but not "w.x.y.z"
376
1
  for (size_t i = name.find_last_of(0x2E /* '.' */, length - 1);
377
4
    (i != LogString::npos) && (i != 0);
378
3
    i = name.find_last_of(0x2E /* '.' */, i - 1))
379
3
  {
380
3
    LogString substr = name.substr(0, i);
381
382
3
    LoggerMap::iterator it = m_priv->loggers.find(substr);
383
384
3
    if (it != m_priv->loggers.end())
385
0
    {
386
0
      parentFound = true;
387
0
      logger->setParent( it->second );
388
0
      break; // no need to update the ancestors of the closest ancestor
389
0
    }
390
3
    else
391
3
    {
392
3
      ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(substr);
393
394
3
      if (it2 != m_priv->provisionNodes.end())
395
0
      {
396
0
        it2->second.push_back(logger);
397
0
      }
398
3
      else
399
3
      {
400
3
        ProvisionNode node(1, logger);
401
3
        m_priv->provisionNodes.insert(
402
3
          ProvisionNodeMap::value_type(substr, node));
403
3
      }
404
3
    }
405
3
  }
406
407
  // If we could not find any existing parents, then link with root.
408
1
  if (!parentFound)
409
1
  {
410
1
    logger->setParent( root );
411
1
  }
412
1
}
413
414
void Hierarchy::updateChildren(ProvisionNode& pn, const LoggerPtr& logger)
415
0
{
416
0
  for (auto& l : pn)
417
0
  {
418
    // Unless this child already points to a correct (lower) parent,
419
    // make logger.parent point to l.parent and l.parent to logger.
420
0
    if (!StringHelper::startsWith(l->getParent()->getName(), logger->getName()))
421
0
    {
422
0
      logger->setParent( l->getParent() );
423
0
      l->setParent( logger );
424
0
    }
425
0
  }
426
    
427
0
}
428
429
void Hierarchy::updateChildren(const Logger* parent)
430
2
{
431
2
  for (auto& item : m_priv->loggers)
432
0
  {
433
0
    for (auto l = item.second; l; l = l->getParent())
434
0
    {
435
0
      if (l->getParent().get() == parent)
436
0
      {
437
0
        item.second->updateThreshold();
438
0
        break;
439
0
      }
440
0
    }
441
0
  }
442
2
}
443
444
void Hierarchy::setConfigured(bool newValue)
445
4.62k
{
446
4.62k
  std::unique_lock<std::mutex> lock(m_priv->configuredMutex, std::try_to_lock);
447
4.62k
  if (lock.owns_lock()) // Not being auto-configured?
448
4.10k
    m_priv->configured = newValue;
449
4.62k
}
450
451
bool Hierarchy::isConfigured()
452
0
{
453
0
  std::lock_guard<std::mutex> lock(m_priv->configuredMutex); // Blocks while auto-configuration is active
454
0
  return m_priv->configured;
455
0
}
456
457
HierarchyPtr Hierarchy::create()
458
5
{
459
5
  HierarchyPtr ret(new Hierarchy);
460
5
  return ret;
461
5
}
462
463
void Hierarchy::clearAppenders()
464
0
{
465
0
  m_priv->allAppenders.clear();
466
0
}
467
468
void Hierarchy::addAppender(AppenderPtr appender)
469
0
{
470
0
  m_priv->allAppenders.push_back(appender);
471
0
}
472
473
bool Hierarchy::removeLogger(const LogString& name, bool ifNotUsed)
474
0
{
475
0
  auto parentRefCount = [this](const LoggerPtr& child) -> int
476
0
  {
477
0
    int result = 0;
478
0
    for (auto& node : m_priv->provisionNodes)
479
0
    {
480
0
      if (node.second.end() != std::find(node.second.begin(), node.second.end(), child))
481
0
        ++result;
482
0
    }
483
0
    return result;
484
0
  };
Unexecuted instantiation: hierarchy.cpp:log4cxx::Hierarchy::removeLogger(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)::$_0::operator()(std::__1::shared_ptr<log4cxx::Logger> const&) const
Unexecuted instantiation: hierarchy.cpp:log4cxx::Hierarchy::removeLogger(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, bool)::$_0::operator()(std::__1::shared_ptr<log4cxx::Logger> const&) const
485
0
  bool result = false;
486
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
487
0
  auto it = m_priv->loggers.find(name);
488
0
  if (it == m_priv->loggers.end())
489
0
    ;
490
0
  else if (ifNotUsed && 1 + parentRefCount(it->second) < it->second.use_count())
491
0
    ;
492
0
  else
493
0
  {
494
0
    for (auto& node : m_priv->provisionNodes)
495
0
    {
496
0
      for (size_t i = node.second.size(); 0 < i; )
497
0
      {
498
0
        if (node.second[--i] == it->second)
499
0
          node.second.erase(node.second.begin() + i);
500
0
      }
501
0
    }
502
0
    m_priv->loggers.erase(it);
503
0
    result = true;
504
0
  }
505
0
  return result;
506
0
}
Unexecuted instantiation: log4cxx::Hierarchy::removeLogger(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)
Unexecuted instantiation: log4cxx::Hierarchy::removeLogger(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, bool)