std::vector<std::string> LoggerDB::processConfigString( folly::StringPiece config) { std::vector<std::string> errors; if (config.empty()) { return errors; } std::vector<StringPiece> pieces; folly::split(",", config, pieces); for (const auto& p : pieces) { auto idx = p.rfind('='); if (idx == folly::StringPiece::npos) { errors.emplace_back( folly::sformat("missing '=' in logger configuration: \"{}\"", p)); continue; } auto category = p.subpiece(0, idx); auto level_str = p.subpiece(idx + 1); LogLevel level; try { level = stringToLogLevel(level_str); } catch (const std::exception&) { errors.emplace_back(folly::sformat( "invalid log level \"{}\" for category \"{}\"", level_str, category)); continue; } setLevel(category, level); } return errors; }
bool StringToLogLevel(const std::string& log_level_text, LogLevel& log_level) { return stringToLogLevel(log_level_text, log_level); }
void LoggingManager::initialize() { if (!m_initialized) { m_initialized = true; // Read the log output stream configuration. ::icl_core::config::ConfigIterator output_stream_it = ::icl_core::config::find("\\/IclCore\\/Logging\\/(OutputStream.*)\\/(.*)"); while (output_stream_it.next()) { ::icl_core::String entry_name = output_stream_it.matchGroup(1); ::icl_core::String value_name = output_stream_it.matchGroup(2); if (value_name == "OutputStreamName") { m_output_stream_config[entry_name].output_stream_name = output_stream_it.value(); } else if (value_name == "Name") { m_output_stream_config[entry_name].name = output_stream_it.value(); } else if (value_name == "LogLevel") { if (!stringToLogLevel(output_stream_it.value(), m_output_stream_config[entry_name].log_level)) { std::cerr << "LOGGING CONFIG ERROR: Illegal log level in " << output_stream_it.key() << std::endl; } } else if (value_name.substr(0, 9) == "LogStream") { m_output_stream_config[entry_name].log_streams.push_back(output_stream_it.value()); } } // Read the log stream configuration. ::icl_core::config::ConfigIterator log_stream_it = ::icl_core::config::find("\\/IclCore\\/Logging\\/(LogStream.*)\\/(.*)"); while (log_stream_it.next()) { ::icl_core::String entry_name = log_stream_it.matchGroup(1); ::icl_core::String value_name = log_stream_it.matchGroup(2); if (value_name == "Name") { m_log_stream_config[entry_name].name = log_stream_it.value(); } else if (value_name == "LogLevel") { if (!stringToLogLevel(log_stream_it.value(), m_log_stream_config[entry_name].log_level)) { std::cerr << "LOGGING CONFIG ERROR: Illegal log level in " << log_stream_it.key() << std::endl; } } } } configure(); // Configure the "QuickDebug" log stream and log output stream. icl_core::String quick_debug_filename; if (icl_core::config::paramOpt<icl_core::String>("quick-debug", quick_debug_filename)) { // Find an unused name for the QuickDebug[0-9]* log output stream. icl_core::String output_stream_name = "QuickDebug"; LogOutputStreamMap::const_iterator find_it = m_log_output_streams.find(output_stream_name); if (find_it != m_log_output_streams.end()) { size_t count = 0; do { ++count; find_it = m_log_output_streams.find(output_stream_name + boost::lexical_cast<icl_core::String>(count)); } while (find_it != m_log_output_streams.end()); output_stream_name = output_stream_name + boost::lexical_cast<icl_core::String>(count); } // Create the log output stream and connect the log stream. LogOutputStream *output_stream = new FileLogOutput(output_stream_name, quick_debug_filename, eLL_TRACE, true); m_log_output_streams[output_stream_name] = output_stream; QuickDebug::instance().addOutputStream(output_stream); QuickDebug::instance().m_initial_level = eLL_TRACE; } // Run the log output stream threads. if (m_default_log_output != 0) { m_default_log_output->start(); } for (LogOutputStreamMap::iterator output_stream_it = m_log_output_streams.begin(); output_stream_it != m_log_output_streams.end(); ++output_stream_it) { output_stream_it->second->start(); } }
void LoggingManager::configure() { // Create the default log output stream, if necessary. if (m_output_stream_config.empty() && m_default_log_output == NULL) { m_default_log_output = StdLogOutput::create("Default", "/IclCore/Logging/Default"); } // Create log stream instances, if necessary. for (LogStreamFactoryMap::iterator log_stream_it = m_log_stream_factories.begin(); log_stream_it != m_log_stream_factories.end(); ++log_stream_it) { if (m_log_streams.find(log_stream_it->first) == m_log_streams.end()) { registerLogStream((*log_stream_it->second)()); } } // Delete the default log output stream, if necessary. if (!m_output_stream_config.empty() && m_default_log_output != NULL) { for (LogStreamMap::iterator it = m_log_streams.begin(); it != m_log_streams.end(); ++it) { it->second->removeOutputStream(m_default_log_output); } m_default_log_output->shutdown(); delete m_default_log_output; m_default_log_output = 0; } // Run through the log output stream configuration for (LogOutputStreamConfigMap::iterator loc_it = m_output_stream_config.begin(); loc_it != m_output_stream_config.end(); ++loc_it) { // Auto-generate a suitable name for the log output stream, if it // has not been set in the configuration. if (loc_it->second.name == ::icl_core::String()) { loc_it->second.name = loc_it->second.output_stream_name; } // Create the configured log output stream, if necessary. LogOutputStreamMap::const_iterator find_log_output_stream = m_log_output_streams.find(loc_it->second.name); if (find_log_output_stream == m_log_output_streams.end()) { LogOutputStreamFactoryMap::const_iterator find_log_output_stream_factory = m_log_output_stream_factories.find(loc_it->second.output_stream_name); if (find_log_output_stream_factory == m_log_output_stream_factories.end()) { // If the log output stream cannot be created then skip to the // next configuration entry. continue; } LogOutputStream *log_output_stream = (*find_log_output_stream_factory->second)(loc_it->second.name, "/IclCore/Logging/" + loc_it->first, loc_it->second.log_level); boost::tuples::tie(find_log_output_stream, boost::tuples::ignore) = m_log_output_streams.insert(std::make_pair(loc_it->second.name, log_output_stream)); } // Check again, just to be sure! if (find_log_output_stream != m_log_output_streams.end()) { // Connect the configured log streams (either the list from the // commandline or all available log streams). if (loc_it->second.log_streams.empty()) { for (LogStreamMap::iterator it = m_log_streams.begin(); it != m_log_streams.end(); ++it) { it->second->addOutputStream(find_log_output_stream->second); } } else { for (StringList::const_iterator it = loc_it->second.log_streams.begin(); it != loc_it->second.log_streams.end(); ++it) { LogStreamMap::iterator find_it = m_log_streams.find(*it); if (find_it == m_log_streams.end()) { // If the log stream cannot be found then skip to the next // entry. Maybe there will be a second call to configure() // in the future and the log stream is available then. continue; } else { find_it->second->addOutputStream(find_log_output_stream->second); } } } } } // Set the log level of the configured log streams (either the list // from the commandline or all available log streams). for (LogStreamConfigMap::const_iterator lsc_it = m_log_stream_config.begin(); lsc_it != m_log_stream_config.end(); ++lsc_it) { LogStreamMap::iterator find_it = m_log_streams.find(lsc_it->second.name); if (find_it == m_log_streams.end()) { // If the log stream cannot be found then skip to the next // entry. Maybe there will be a second call to configure() in // the future and the log stream is available then. continue; } else { find_it->second->m_initial_level = lsc_it->second.log_level; } } if (icl_core::config::Getopt::instance().paramOptPresent("log-level")) { LogLevel initial_level = cDEFAULT_LOG_LEVEL; icl_core::String log_level = icl_core::config::Getopt::instance().paramOpt("log-level"); if (!stringToLogLevel(log_level, initial_level)) { std::cerr << "Illegal log level " << log_level << std::endl; std::cerr << "Valid levels are 'Trace', 'Debug', 'Info', 'Warning', 'Error' and 'Mute'." << std::endl; } else { if (m_default_log_output == NULL) { m_default_log_output = StdLogOutput::create("Default", "/IclCore/Logging/Default"); } m_default_log_output->setLogLevel(initial_level); for (LogStreamMap::iterator lsm_it = m_log_streams.begin(); lsm_it != m_log_streams.end(); ++lsm_it) { lsm_it->second->m_initial_level = initial_level; lsm_it->second->addOutputStream(m_default_log_output); } for (LogOutputStreamMap::iterator los_it = m_log_output_streams.begin(); los_it != m_log_output_streams.end(); ++los_it) { los_it->second->setLogLevel(initial_level); } } } }
std::shared_ptr<StandardLogHandler> StandardLogHandlerFactory::createHandler( StringPiece type, WriterFactory* writerFactory, const Options& options) { std::unique_ptr<FormatterFactory> formatterFactory; // Get the log formatter type auto* formatterType = get_ptr(options, "formatter"); if (!formatterType || *formatterType == "glog") { formatterFactory = std::make_unique<GlogFormatterFactory>(); } else if (!formatterType || *formatterType == "custom") { formatterFactory = std::make_unique<CustomLogFormatterFactory>(); } else { throw std::invalid_argument( to<string>("unknown log formatter type \"", *formatterType, "\"")); } Optional<LogLevel> syncLevel; // Process the log formatter and log handler options std::vector<string> errors; for (const auto& entry : options) { bool handled = false; try { // Allow both the formatterFactory and writerFactory to consume an // option. In general they probably should have mutually exclusive // option names, but we don't give precedence to one over the other here. handled |= formatterFactory->processOption(entry.first, entry.second); handled |= writerFactory->processOption(entry.first, entry.second); } catch (const std::exception& ex) { errors.push_back(to<string>( "error processing option \"", entry.first, "\": ", ex.what())); continue; } // We explicitly processed the "formatter" option above. handled |= handled || (entry.first == "formatter"); // Process the "sync_level" option. if (entry.first == "sync_level") { try { syncLevel = stringToLogLevel(entry.second); } catch (const std::exception& ex) { errors.push_back(to<string>( "unable to parse value for option \"", entry.first, "\": ", ex.what())); } handled = true; } // Complain about unknown options. if (!handled) { errors.push_back(to<string>("unknown option \"", entry.first, "\"")); } } if (!errors.empty()) { throw std::invalid_argument(join(", ", errors)); } // Construct the formatter and writer auto writer = writerFactory->createWriter(); auto formatter = formatterFactory->createFormatter(writer); if (syncLevel) { return std::make_shared<StandardLogHandler>( LogHandlerConfig{type, options}, formatter, writer, *syncLevel); } else { return std::make_shared<StandardLogHandler>( LogHandlerConfig{type, options}, formatter, writer); } }