Coverage Report

Created: 2026-03-19 06:57

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