Coverage Report

Created: 2025-07-01 06:08

/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
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::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
1
  m_priv(std::make_unique<HierarchyPrivate>())
73
1
{
74
1
}
Unexecuted instantiation: log4cxx::Hierarchy::Hierarchy()
log4cxx::Hierarchy::Hierarchy()
Line
Count
Source
72
1
  m_priv(std::make_unique<HierarchyPrivate>())
73
1
{
74
1
}
75
76
Hierarchy::~Hierarchy()
77
1
{
78
1
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
79
1
  for (auto& item : m_priv->loggers)
80
0
  {
81
0
    if (auto& pLogger = item.second)
82
0
    {
83
0
      pLogger->removeHierarchy();
84
0
      pLogger->removeAllAppenders();
85
0
    }
86
0
  }
87
1
  if (m_priv->root)
88
1
  {
89
1
    m_priv->root->removeHierarchy();
90
1
    m_priv->root->removeAllAppenders();
91
1
  }
92
1
}
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
}
158
159
void Hierarchy::setThreshold(const LevelPtr& l)
160
0
{
161
0
  if (l != 0)
162
0
  {
163
0
    std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
164
0
    setThresholdInternal(l);
165
0
  }
166
0
}
167
168
void Hierarchy::setThreshold(const LogString& levelStr)
169
0
{
170
0
  LevelPtr l(Level::toLevelLS(levelStr, 0));
171
172
0
  if (l != 0)
173
0
  {
174
0
    setThreshold(l);
175
0
  }
176
0
  else
177
0
  {
178
0
    LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \""))
179
0
      + levelStr + LOG4CXX_STR("\"."));
180
0
  }
181
0
}
182
183
void Hierarchy::setThresholdInternal(const LevelPtr& l)
184
0
{
185
0
  m_priv->thresholdInt = l->toInt();
186
0
  m_priv->threshold = l;
187
188
0
  if (m_priv->thresholdInt != Level::ALL_INT)
189
0
  {
190
0
    m_priv->configured = true;
191
0
  }
192
0
}
193
194
void Hierarchy::fireAddAppenderEvent(const Logger* logger, const Appender* appender)
195
1
{
196
1
  setConfigured(true);
197
1
  HierarchyEventListenerList clonedList;
198
1
  {
199
1
    std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
200
1
    clonedList = m_priv->listeners;
201
1
  }
202
203
1
  for (auto& item : clonedList)
204
0
    item->addAppenderEvent(logger, appender);
205
1
}
206
207
void Hierarchy::fireRemoveAppenderEvent(const Logger* logger, const Appender* appender)
208
209
0
{
210
0
  HierarchyEventListenerList clonedList;
211
0
  {
212
0
    std::lock_guard<std::mutex> lock(m_priv->listenerMutex);
213
0
    clonedList = m_priv->listeners;
214
0
  }
215
0
  for (auto& item : clonedList)
216
0
    item->removeAppenderEvent(logger, appender);
217
0
}
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
0
{
226
0
#if LOG4CXX_ABI_VERSION <= 15
227
0
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<DefaultLoggerFactory>();
228
#else
229
  static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<LoggerFactory>();
230
#endif
231
0
  return getLogger(name, defaultFactory);
232
0
}
233
234
LoggerPtr Hierarchy::getLogger(const LogString& name,
235
  const spi::LoggerFactoryPtr& factory)
236
0
{
237
0
  auto root = getRootLogger();
238
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
239
240
0
  LoggerMap::iterator it = m_priv->loggers.find(name);
241
0
  LoggerPtr result;
242
243
0
  if (it != m_priv->loggers.end())
244
0
  {
245
0
    result = it->second;
246
0
  }
247
0
  if (!result && factory)
248
0
  {
249
0
#if LOG4CXX_ABI_VERSION <= 15
250
0
    LoggerPtr logger(factory->makeNewLoggerInstance(m_priv->pool, name));
251
#else
252
    LoggerPtr logger(factory->makeNewLoggerInstance(name));
253
#endif
254
0
    logger->setHierarchy(this);
255
0
    m_priv->loggers.insert(LoggerMap::value_type(name, logger));
256
257
0
    ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(name);
258
259
0
    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
0
    updateParents(logger, root);
266
0
    result = logger;
267
0
  }
268
0
  return result;
269
270
0
}
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
301
{
287
301
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
288
301
  if (!m_priv->root)
289
1
  {
290
1
    m_priv->root = std::make_shared<RootLogger>(Level::getDebug());
291
1
    m_priv->root->setHierarchy(const_cast<Hierarchy*>(this));
292
1
  }
293
294
301
  return m_priv->root;
295
301
}
296
297
bool Hierarchy::isDisabled(int level) const
298
44.8k
{
299
44.8k
  return m_priv->thresholdInt > level;
300
44.8k
}
301
302
void Hierarchy::ensureIsConfigured(std::function<void()> configurator)
303
300
{
304
300
  std::lock_guard<std::mutex> lock(m_priv->configuredMutex);
305
300
  if (!m_priv->configured)
306
0
  {
307
0
    configurator();
308
0
    m_priv->configured = true;
309
0
  }
310
300
}
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
0
{
338
0
  std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
339
340
0
  shutdownInternal();
341
0
}
342
343
void Hierarchy::shutdownInternal()
344
0
{
345
0
  m_priv->configured = false;
346
347
  // begin by closing nested appenders
348
0
  if (m_priv->root)
349
0
    m_priv->root->closeNestedAppenders();
350
351
0
  for (auto& item : m_priv->loggers)
352
0
  {
353
0
    if (auto pLogger = item.second)
354
0
      pLogger->closeNestedAppenders();
355
0
  }
356
357
  // then, remove all appenders
358
0
  if (m_priv->root)
359
0
    m_priv->root->removeAllAppenders();
360
361
0
  for (auto& item : m_priv->loggers)
362
0
  {
363
0
    if (auto pLogger = item.second)
364
0
      pLogger->removeAllAppenders();
365
0
  }
366
0
}
367
368
void Hierarchy::updateParents(const LoggerPtr& logger, const LoggerPtr& root)
369
0
{
370
0
  const LogString name(logger->getName());
371
0
  size_t length = name.size();
372
0
  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
0
  for (size_t i = name.find_last_of(0x2E /* '.' */, length - 1);
377
0
    (i != LogString::npos) && (i != 0);
378
0
    i = name.find_last_of(0x2E /* '.' */, i - 1))
379
0
  {
380
0
    LogString substr = name.substr(0, i);
381
382
0
    LoggerMap::iterator it = m_priv->loggers.find(substr);
383
384
0
    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
0
    else
391
0
    {
392
0
      ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(substr);
393
394
0
      if (it2 != m_priv->provisionNodes.end())
395
0
      {
396
0
        it2->second.push_back(logger);
397
0
      }
398
0
      else
399
0
      {
400
0
        ProvisionNode node(1, logger);
401
0
        m_priv->provisionNodes.insert(
402
0
          ProvisionNodeMap::value_type(substr, node));
403
0
      }
404
0
    }
405
0
  }
406
407
  // If we could not find any existing parents, then link with root.
408
0
  if (!parentFound)
409
0
  {
410
0
    logger->setParent( root );
411
0
  }
412
0
}
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
1
{
431
1
  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
1
}
443
444
void Hierarchy::setConfigured(bool newValue)
445
3
{
446
3
  std::unique_lock<std::mutex> lock(m_priv->configuredMutex, std::try_to_lock);
447
3
  if (lock.owns_lock()) // Not being auto-configured?
448
3
    m_priv->configured = newValue;
449
3
}
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
1
{
459
1
  HierarchyPtr ret(new Hierarchy);
460
1
  return ret;
461
1
}
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
  };
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
}