Coverage Report

Created: 2025-10-10 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/propertyconfigurator.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/logstring.h>
19
#include <log4cxx/propertyconfigurator.h>
20
#include <log4cxx/asyncappender.h>
21
#include <log4cxx/helpers/properties.h>
22
#include <log4cxx/helpers/loglog.h>
23
#include <log4cxx/helpers/exception.h>
24
#include <log4cxx/logmanager.h>
25
#include <log4cxx/helpers/optionconverter.h>
26
#include <log4cxx/level.h>
27
#if LOG4CXX_ABI_VERSION <= 15
28
#include <log4cxx/defaultloggerfactory.h>
29
#else
30
#include <log4cxx/spi/loggerfactory.h>
31
#endif
32
#include <log4cxx/helpers/stringhelper.h>
33
#include <log4cxx/layout.h>
34
#include <log4cxx/config/propertysetter.h>
35
#include <log4cxx/helpers/stringtokenizer.h>
36
#include <log4cxx/helpers/transcoder.h>
37
#include <log4cxx/helpers/fileinputstream.h>
38
#include <log4cxx/helpers/loader.h>
39
#include <log4cxx/helpers/threadutility.h>
40
#include <log4cxx/helpers/singletonholder.h>
41
#include <log4cxx/rolling/rollingfileappender.h>
42
43
#define LOG4CXX 1
44
#include <log4cxx/helpers/aprinitializer.h>
45
46
using namespace LOG4CXX_NS;
47
using namespace LOG4CXX_NS::spi;
48
using namespace LOG4CXX_NS::helpers;
49
using namespace LOG4CXX_NS::config;
50
using namespace LOG4CXX_NS::rolling;
51
52
#include <log4cxx/helpers/filewatchdog.h>
53
namespace LOG4CXX_NS
54
{
55
class PropertyWatchdog  : public FileWatchdog
56
{
57
  public:
58
0
    PropertyWatchdog(const File& filename) : FileWatchdog(filename)
59
0
    {
60
0
    }
61
62
    /**
63
    Call PropertyConfigurator#doConfigure(const String& configFileName,
64
    const spi::LoggerRepositoryPtr& hierarchy) with the
65
    <code>filename</code> to reconfigure log4cxx.
66
    */
67
    void doOnChange()
68
0
    {
69
0
      PropertyConfigurator().doConfigure(file(),
70
0
        LogManager::getLoggerRepository());
71
0
    }
72
73
    static void startWatching(const File& filename, long delay)
74
0
    {
75
0
      using WatchdogHolder = SingletonHolder<PropertyWatchdog>;
76
0
      auto pHolder = APRInitializer::getOrAddUnique<WatchdogHolder>
77
0
        ( [&filename]() -> ObjectPtr
78
0
          { return std::make_shared<WatchdogHolder>(filename); }
79
0
        );
80
0
      auto& pdog = pHolder->value();
81
0
      pdog.setFile(filename);
82
0
      pdog.setDelay(0 < delay ? delay : FileWatchdog::DEFAULT_DELAY);
83
0
      pdog.start();
84
0
    }
85
};
86
}
87
88
IMPLEMENT_LOG4CXX_OBJECT(PropertyConfigurator)
89
90
using RegistryType = std::map<LogString, AppenderPtr>;
91
using RegistryPtr = std::unique_ptr<RegistryType>;
92
93
#if 15 < LOG4CXX_ABI_VERSION
94
struct PropertyConfigurator::PrivateData
95
{
96
97
  /**
98
  Used internally to keep track of configured appenders.
99
  */
100
  RegistryPtr registry{ std::make_unique<RegistryType>() };
101
102
  /**
103
  Used to create new instances of logger
104
  */
105
  spi::LoggerFactoryPtr loggerFactory{ std::make_shared<LoggerFactory>() };
106
107
  /**
108
  True if an appender was added to a logger
109
  */
110
  bool appenderAdded{ false };
111
};
112
PropertyConfigurator::PropertyConfigurator()
113
  : m_priv{ std::make_unique<PrivateData>() }
114
#else
115
0
#define m_priv this
116
PropertyConfigurator::PropertyConfigurator()
117
0
  : registry(new std::map<LogString, AppenderPtr>())
118
0
  , loggerFactory(new DefaultLoggerFactory())
119
#endif
120
0
{
121
0
}
Unexecuted instantiation: log4cxx::PropertyConfigurator::PropertyConfigurator()
Unexecuted instantiation: log4cxx::PropertyConfigurator::PropertyConfigurator()
122
123
PropertyConfigurator::~PropertyConfigurator()
124
0
{
125
0
#if LOG4CXX_ABI_VERSION <= 15
126
0
  delete registry;
127
0
#endif
128
0
}
129
130
spi::ConfigurationStatus PropertyConfigurator::doConfigure
131
  ( const File&                     configFileName
132
#if LOG4CXX_ABI_VERSION <= 15
133
  , spi::LoggerRepositoryPtr        repository
134
#else
135
  , const spi::LoggerRepositoryPtr& repository
136
#endif
137
  )
138
0
{
139
0
  auto result = spi::ConfigurationStatus::NotConfigured;
140
0
  if (LogLog::isDebugEnabled())
141
0
  {
142
0
    LogLog::debug(LOG4CXX_STR("Loading configuration file [")
143
0
      + configFileName.getPath() + LOG4CXX_STR("]"));
144
0
  }
145
0
  Properties props = Configurator::properties();
146
0
  try
147
0
  {
148
0
    InputStreamPtr inputStream = InputStreamPtr( new FileInputStream(configFileName) );
149
0
    props.load(inputStream);
150
0
  }
151
0
  catch (const IOException& ex)
152
0
  {
153
0
    LogLog::error(LOG4CXX_STR("Could not load properties from [")
154
0
      + configFileName.getPath() + LOG4CXX_STR("]"), ex);
155
0
    return result;
156
0
  }
157
158
0
  try
159
0
  {
160
0
    result = doConfigure(props, repository ? repository : LogManager::getLoggerRepository());
161
0
#if LOG4CXX_ABI_VERSION <= 15
162
0
    if (m_priv->registry->empty())
163
#else
164
    if (!m_priv->appenderAdded)
165
#endif
166
0
    {
167
0
      LogLog::warn(LOG4CXX_STR("[") + configFileName.getPath()
168
0
        + LOG4CXX_STR("] did not add an ") + Appender::getStaticClass().getName()
169
0
        + LOG4CXX_STR(" to a logger"));
170
0
    }
171
0
  }
172
0
  catch (const std::exception& ex)
173
0
  {
174
0
    LogLog::error(LOG4CXX_STR("Exception thrown processing [")
175
0
      + configFileName.getPath() + LOG4CXX_STR("]: "), ex);
176
0
  }
177
178
0
  return result;
179
0
}
180
181
spi::ConfigurationStatus PropertyConfigurator::configure(const File& configFilename)
182
0
{
183
0
  return PropertyConfigurator().doConfigure(configFilename, LogManager::getLoggerRepository());
184
0
}
185
186
spi::ConfigurationStatus PropertyConfigurator::configure(helpers::Properties& properties)
187
0
{
188
0
  return PropertyConfigurator().doConfigure(properties, LogManager::getLoggerRepository());
189
0
}
190
191
#if LOG4CXX_ABI_VERSION <= 15
192
spi::ConfigurationStatus PropertyConfigurator::configureAndWatch(const File& configFilename)
193
0
{
194
0
  return configureAndWatch(configFilename, FileWatchdog::DEFAULT_DELAY);
195
0
}
196
#endif
197
198
spi::ConfigurationStatus PropertyConfigurator::configureAndWatch(
199
  const File& configFilename, long delay)
200
0
{
201
0
  spi::ConfigurationStatus stat = PropertyConfigurator().doConfigure(configFilename, LogManager::getLoggerRepository());
202
0
  PropertyWatchdog::startWatching(configFilename, delay);
203
0
  return stat;
204
0
}
205
206
spi::ConfigurationStatus PropertyConfigurator::doConfigure(helpers::Properties& properties,
207
  spi::LoggerRepositoryPtr hierarchy)
208
0
{
209
0
  LogString debugValue(properties.getProperty(LOG4CXX_STR("log4j.debug")));
210
0
  if (!debugValue.empty())
211
0
  {
212
0
    LogLog::setInternalDebugging(OptionConverter::toBoolean(debugValue, true));
213
0
  }
214
215
0
  LogString colorValue(properties.getProperty(LOG4CXX_STR("log4j.color")));
216
0
  if (!colorValue.empty())
217
0
  {
218
0
    LogLog::setColorEnabled(OptionConverter::toBoolean(colorValue, true));
219
0
  }
220
221
0
  LogString thresholdStr =
222
0
    OptionConverter::findAndSubst(LOG4CXX_STR("log4j.threshold"), properties);
223
224
0
  if (!thresholdStr.empty())
225
0
  {
226
0
    hierarchy->setThreshold(OptionConverter::toLevel(thresholdStr, Level::getAll()));
227
0
    if (LogLog::isDebugEnabled())
228
0
    {
229
0
      LogLog::debug(LOG4CXX_STR("Repository threshold =[")
230
0
        + hierarchy->getThreshold()->toString()
231
0
        + LOG4CXX_STR("]"));
232
0
    }
233
0
  }
234
235
0
  LogString threadConfigurationValue(properties.getProperty(LOG4CXX_STR("log4j.threadConfiguration")));
236
237
0
  if ( threadConfigurationValue == LOG4CXX_STR("NoConfiguration") )
238
0
  {
239
0
    helpers::ThreadUtility::configure( ThreadConfigurationType::NoConfiguration );
240
0
  }
241
0
  else if ( threadConfigurationValue == LOG4CXX_STR("BlockSignalsOnly") )
242
0
  {
243
0
    helpers::ThreadUtility::configure( ThreadConfigurationType::BlockSignalsOnly );
244
0
  }
245
0
  else if ( threadConfigurationValue == LOG4CXX_STR("NameThreadOnly") )
246
0
  {
247
0
    helpers::ThreadUtility::configure( ThreadConfigurationType::NameThreadOnly );
248
0
  }
249
0
  else if ( threadConfigurationValue == LOG4CXX_STR("BlockSignalsAndNameThread") )
250
0
  {
251
0
    helpers::ThreadUtility::configure( ThreadConfigurationType::BlockSignalsAndNameThread );
252
0
  }
253
254
0
  configureRootLogger(properties, hierarchy);
255
0
  configureLoggerFactory(properties);
256
0
  parseCatsAndRenderers(properties, hierarchy);
257
0
  LogLog::debug(LOG4CXX_STR("Finished configuring."));
258
0
#if LOG4CXX_ABI_VERSION <= 15
259
0
  auto result = m_priv->registry->empty()
260
#else
261
  auto result = !m_priv->appenderAdded
262
#endif
263
0
    ? spi::ConfigurationStatus::NotConfigured
264
0
    : spi::ConfigurationStatus::Configured;
265
266
0
  if (spi::ConfigurationStatus::Configured == result)
267
0
    hierarchy->setConfigured(true);
268
0
  return result;
269
0
}
270
271
void PropertyConfigurator::configureLoggerFactory(helpers::Properties& props)
272
0
{
273
0
  LogString factoryClassName =
274
0
    OptionConverter::findAndSubst(LOG4CXX_STR("log4j.loggerFactory"), props);
275
276
0
  if (!factoryClassName.empty())
277
0
  {
278
0
    auto instance = OptionConverter::instantiateByClassName
279
0
      ( StringHelper::trim(factoryClassName)
280
0
      , LoggerFactory::getStaticClass()
281
0
#if LOG4CXX_ABI_VERSION <= 15
282
0
      , std::make_shared<DefaultLoggerFactory>()
283
#else
284
      , std::make_shared<LoggerFactory>()
285
#endif
286
0
      );
287
288
0
    m_priv->loggerFactory = LOG4CXX_NS::cast<LoggerFactory>( instance );
289
0
    Pool p;
290
0
    PropertySetter::setProperties(m_priv->loggerFactory, props, LOG4CXX_STR("log4j.factory."), p);
291
0
  }
292
0
}
293
294
void PropertyConfigurator::configureRootLogger(helpers::Properties& props,
295
  spi::LoggerRepositoryPtr& hierarchy)
296
0
{
297
0
  LogString effectivePrefix(LOG4CXX_STR("log4j.rootLogger"));
298
0
  LogString value = OptionConverter::findAndSubst(effectivePrefix, props);
299
300
0
  if (value.empty())
301
0
  {
302
0
    effectivePrefix = LOG4CXX_STR("log4j.rootCategory");
303
0
    value = OptionConverter::findAndSubst(effectivePrefix, props);
304
0
  }
305
306
0
  if (value.empty())
307
0
  {
308
0
    LogLog::debug(LOG4CXX_STR("Neither 'log4j.rootLogger' or 'log4j.rootCategory' found. Is this OK?"));
309
0
  }
310
0
  else
311
0
  {
312
0
    LoggerPtr root = hierarchy->getRootLogger();
313
0
    parseLogger(props, root, effectivePrefix, LOG4CXX_STR("root"), value, true);
314
0
  }
315
0
}
316
317
void PropertyConfigurator::parseCatsAndRenderers(helpers::Properties& props,
318
  spi::LoggerRepositoryPtr& hierarchy)
319
0
{
320
0
  for (auto key : props.propertyNames())
321
0
  {
322
0
    auto categoryFound = (0 == key.find(LOG4CXX_STR("log4j.category.")));
323
0
    if (categoryFound || 0 == key.find(LOG4CXX_STR("log4j.logger.")))
324
0
    {
325
0
      auto prefixLength =
326
0
        ( categoryFound
327
0
        ? LogString(LOG4CXX_STR("log4j.category."))
328
0
        : LogString(LOG4CXX_STR("log4j.logger."))
329
0
        ).length();
330
0
      auto loggerName = key.substr(prefixLength);
331
0
      auto value = OptionConverter::findAndSubst(key, props);
332
0
      auto logger = hierarchy->getLogger(loggerName, m_priv->loggerFactory);
333
0
      auto additivity = parseAdditivityForLogger(props, logger, loggerName);
334
0
      parseLogger(props, logger, key, loggerName, value, additivity);
335
336
0
    }
337
0
  }
338
0
}
339
340
bool PropertyConfigurator::parseAdditivityForLogger(helpers::Properties& props,
341
  LoggerPtr& cat, const LogString& loggerName)
342
0
{
343
0
  LogString value(OptionConverter::findAndSubst(LOG4CXX_STR("log4j.additivity.") + loggerName, props));
344
  // touch additivity only if necessary
345
0
  if (!value.empty())
346
0
  {
347
0
    bool additivity = OptionConverter::toBoolean(value, true);
348
0
    if (LogLog::isDebugEnabled())
349
0
    {
350
0
      LogLog::debug(LOG4CXX_STR("Setting [") + loggerName + LOG4CXX_STR("] additivity to [")
351
0
        + (additivity ? LogString(LOG4CXX_STR("true")) : LogString(LOG4CXX_STR("false")) + LOG4CXX_STR("]")));
352
0
    }
353
354
0
    return additivity;
355
0
  }
356
357
0
  return true;
358
0
}
359
360
/**
361
        This method must work for the root logger as well.
362
*/
363
void PropertyConfigurator::parseLogger(
364
  helpers::Properties& props, LoggerPtr& logger, const LogString& /* optionKey */,
365
  const LogString& loggerName, const LogString& value, bool additivity)
366
0
{
367
0
  if (LogLog::isDebugEnabled())
368
0
  {
369
0
    LogLog::debug(((LogString) LOG4CXX_STR("Parsing for ["))
370
0
      + loggerName
371
0
      + LOG4CXX_STR("] with value=[")
372
0
      + value + LOG4CXX_STR("]"));
373
0
  }
374
375
  // We must skip over ',' but not white space
376
0
  StringTokenizer st(value, LOG4CXX_STR(","));
377
378
  // If value is not in the form ", appender.." or "", then we should set
379
  // the level of the logger.
380
0
  if (!(value.find(LOG4CXX_STR(",")) == 0 || value.empty()))
381
0
  {
382
    // just to be on the safe side...
383
0
    if (!st.hasMoreTokens())
384
0
    {
385
0
      return;
386
0
    }
387
388
0
    LogString levelStr = st.nextToken();
389
390
    // If the level value is inherited, set logger level value to
391
    // null. We also check that the user has not specified inherited for the
392
    // root logger.
393
0
    if (StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("INHERITED"), LOG4CXX_STR("inherited"))
394
0
      || StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("NULL"), LOG4CXX_STR("null")))
395
0
    {
396
0
      if (loggerName == LOG4CXX_STR("root"))
397
0
      {
398
0
        LogLog::warn(LOG4CXX_STR("Root level cannot be ") + levelStr + LOG4CXX_STR(". Ignoring directive."));
399
0
      }
400
0
      else
401
0
      {
402
0
        logger->setLevel(0);
403
0
      }
404
0
    }
405
0
    else
406
0
    {
407
0
      logger->setLevel(OptionConverter::toLevel(levelStr, Level::getDebug()));
408
0
    }
409
0
    if (LogLog::isDebugEnabled())
410
0
    {
411
0
      LogLog::debug(loggerName + LOG4CXX_STR(" level set to ") +
412
0
        logger->getEffectiveLevel()->toString());
413
0
    }
414
415
0
  }
416
417
0
  AsyncAppenderPtr async;
418
0
  auto lsAsynchronous = OptionConverter::findAndSubst(LOG4CXX_STR("log4j.asynchronous.") + loggerName, props);
419
0
  if (!lsAsynchronous.empty() && OptionConverter::toBoolean(lsAsynchronous, true))
420
0
  {
421
0
    async = std::make_shared<AsyncAppender>();
422
0
    async->setName(loggerName);
423
0
  }
424
425
0
  std::vector<AppenderPtr> newappenders;
426
0
  while (st.hasMoreTokens())
427
0
  {
428
0
    auto appenderName = StringHelper::trim(st.nextToken());
429
430
0
    if (appenderName.empty() || appenderName == LOG4CXX_STR(","))
431
0
    {
432
0
      continue;
433
0
    }
434
435
0
    if (LogLog::isDebugEnabled())
436
0
    {
437
0
      LogLog::debug(LOG4CXX_STR("Parsing ") + Appender::getStaticClass().getName()
438
0
        + LOG4CXX_STR(" named [") + appenderName + LOG4CXX_STR("]"));
439
0
    }
440
0
    if (auto appender = parseAppender(props, appenderName))
441
0
    {
442
0
      newappenders.push_back(appender);
443
0
      if (log4cxx::cast<AsyncAppender>(appender)) // An explicitly configured AsyncAppender?
444
0
        async.reset(); // Not required
445
0
      if (async)
446
0
        async->addAppender(appender);
447
0
    }
448
0
  }
449
#if 15 < LOG4CXX_ABI_VERSION
450
  if (!newappenders.empty())
451
    m_priv->appenderAdded = true;
452
#endif
453
0
  if (async && !newappenders.empty())
454
0
  {
455
0
    if (LogLog::isDebugEnabled())
456
0
    {
457
0
      LogLog::debug(LOG4CXX_STR("Asynchronous logging for [")
458
0
          + loggerName + LOG4CXX_STR("] is on"));
459
0
    }
460
0
    logger->reconfigure( {async}, additivity );
461
0
  }
462
0
  else
463
0
    logger->reconfigure( newappenders, additivity );
464
0
}
465
466
AppenderPtr PropertyConfigurator::parseAppender(
467
  helpers::Properties& props, const LogString& appenderName)
468
0
{
469
0
  AppenderPtr appender = registryGet(appenderName);
470
471
0
  if (appender != 0)
472
0
  {
473
0
    if (LogLog::isDebugEnabled())
474
0
    {
475
0
      LogLog::debug((LogString) LOG4CXX_STR("Appender [")
476
0
        + appenderName + LOG4CXX_STR("] was already parsed."));
477
0
    }
478
479
0
    return appender;
480
0
  }
481
482
  // Appender was not previously initialized.
483
0
  LogString prefix = LOG4CXX_STR("log4j.appender.") + appenderName;
484
0
  LogString layoutPrefix = prefix + LOG4CXX_STR(".layout");
485
486
0
  std::shared_ptr<Object> obj =
487
0
    OptionConverter::instantiateByKey(
488
0
      props, prefix, Appender::getStaticClass(), 0);
489
0
  appender = LOG4CXX_NS::cast<Appender>( obj );
490
491
  // Map obsolete DailyRollingFileAppender property configuration
492
0
  if (!appender &&
493
0
    StringHelper::endsWith(OptionConverter::findAndSubst(prefix, props), LOG4CXX_STR("DailyRollingFileAppender")))
494
0
  {
495
0
    appender = std::make_shared<RollingFileAppender>();
496
0
    auto datePattern = OptionConverter::findAndSubst(prefix + LOG4CXX_STR(".datePattern"), props);
497
0
    if (!datePattern.empty())
498
0
      props.put(prefix + LOG4CXX_STR(".fileDatePattern"), datePattern);
499
0
  }
500
501
0
  if (!appender)
502
0
  {
503
0
    LogLog::error((LogString) LOG4CXX_STR("Could not instantiate ") + Appender::getStaticClass().getName()
504
0
      + LOG4CXX_STR(" named [") + appenderName + LOG4CXX_STR("]"));
505
0
    return 0;
506
0
  }
507
508
0
  appender->setName(appenderName);
509
510
0
  if (appender->instanceof(OptionHandler::getStaticClass()))
511
0
  {
512
0
    Pool p;
513
514
0
    if (appender->requiresLayout())
515
0
    {
516
0
      LayoutPtr layout;
517
0
      std::shared_ptr<Object> obj =
518
0
        OptionConverter::instantiateByKey(
519
0
          props, layoutPrefix, Layout::getStaticClass(), 0);
520
0
      layout = LOG4CXX_NS::cast<Layout>( obj );
521
522
0
      if (layout != 0)
523
0
      {
524
0
        appender->setLayout(layout);
525
0
        if (LogLog::isDebugEnabled())
526
0
        {
527
0
          LogLog::debug((LogString) LOG4CXX_STR("Parsing ") + Layout::getStaticClass().getName()
528
0
            + LOG4CXX_STR(" options for [") + appenderName + LOG4CXX_STR("]"));
529
0
        }
530
531
0
        PropertySetter::setProperties(layout, props, layoutPrefix + LOG4CXX_STR("."), p);
532
0
        if (LogLog::isDebugEnabled())
533
0
        {
534
0
          LogLog::debug((LogString) LOG4CXX_STR("End of parsing for [")
535
0
            + appenderName +  LOG4CXX_STR("]"));
536
0
        }
537
0
      }
538
0
    }
539
540
0
    RollingFileAppenderPtr rolling = LOG4CXX_NS::cast<rolling::RollingFileAppender>(appender);
541
0
    if (rolling)
542
0
    {
543
0
      LogString rollingPolicyKey = prefix + LOG4CXX_STR(".rollingPolicy");
544
0
      if (!OptionConverter::findAndSubst(rollingPolicyKey, props).empty())
545
0
      {
546
0
        RollingPolicyPtr rollingPolicy;
547
0
        std::shared_ptr<Object> rolling_obj =
548
0
          OptionConverter::instantiateByKey(
549
0
            props, rollingPolicyKey, RollingPolicy::getStaticClass(), 0);
550
0
        rollingPolicy = LOG4CXX_NS::cast<RollingPolicy>( rolling_obj );
551
0
        if(rollingPolicy)
552
0
        {
553
0
          rolling->setRollingPolicy(rollingPolicy);
554
555
0
          if (LogLog::isDebugEnabled())
556
0
          {
557
0
            LogLog::debug((LogString) LOG4CXX_STR("Parsing ") + RollingPolicy::getStaticClass().getName()
558
0
              + LOG4CXX_STR(" options for [") + appenderName + LOG4CXX_STR("]"));
559
0
          }
560
0
          PropertySetter::setProperties(rollingPolicy, props, rollingPolicyKey + LOG4CXX_STR("."), p);
561
0
        }
562
0
      }
563
564
0
      LogString triggeringPolicyKey = prefix + LOG4CXX_STR(".triggeringPolicy");
565
0
      if (!OptionConverter::findAndSubst(triggeringPolicyKey, props).empty())
566
0
      {
567
0
        TriggeringPolicyPtr triggeringPolicy;
568
0
        std::shared_ptr<Object> triggering_obj =
569
0
          OptionConverter::instantiateByKey(
570
0
            props, triggeringPolicyKey, TriggeringPolicy::getStaticClass(), 0);
571
0
        triggeringPolicy = LOG4CXX_NS::cast<TriggeringPolicy>( triggering_obj );
572
0
        if(triggeringPolicy)
573
0
        {
574
0
          rolling->setTriggeringPolicy(triggeringPolicy);
575
576
0
          if (LogLog::isDebugEnabled())
577
0
          {
578
0
            LogLog::debug((LogString) LOG4CXX_STR("Parsing ") + TriggeringPolicy::getStaticClass().getName()
579
0
              + LOG4CXX_STR(" options for [") + appenderName + LOG4CXX_STR("]"));
580
0
          }
581
0
          PropertySetter::setProperties(triggeringPolicy, props, triggeringPolicyKey + LOG4CXX_STR("."), p);
582
0
        }
583
0
      }
584
0
    }
585
586
0
    PropertySetter::setProperties(appender, props, prefix + LOG4CXX_STR("."), p);
587
0
    if (LogLog::isDebugEnabled())
588
0
    {
589
0
      LogLog::debug((LogString) LOG4CXX_STR("Parsed [")
590
0
        + appenderName + LOG4CXX_STR("] options."));
591
0
    }
592
0
  }
593
594
0
  registryPut(appender);
595
596
0
  return appender;
597
0
}
598
599
void PropertyConfigurator::registryPut(const AppenderPtr& appender)
600
0
{
601
0
  (*m_priv->registry)[appender->getName()] = appender;
602
0
}
603
604
AppenderPtr PropertyConfigurator::registryGet(const LogString& name)
605
0
{
606
0
  return (*m_priv->registry)[name];
607
0
}