http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/Properties.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/Properties.cpp b/libminifi/src/Properties.cpp new file mode 100644 index 0000000..f877e7a --- /dev/null +++ b/libminifi/src/Properties.cpp @@ -0,0 +1,148 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "properties/Properties.h" +#include <string> +#include "utils/StringUtils.h" +#include "core/Core.h" +#include "core/logging/LoggerConfiguration.h" + +namespace org { +namespace apache { +namespace nifi { +namespace minifi { + +#define BUFFER_SIZE 512 + +Properties::Properties() : logger_(logging::LoggerFactory<Properties>::getLogger()) {} + +// Get the config value +bool Properties::get(std::string key, std::string &value) { + std::lock_guard<std::mutex> lock(mutex_); + auto it = properties_.find(key); + + if (it != properties_.end()) { + value = it->second; + return true; + } else { + return false; + } +} + +int Properties::getInt(const std::string &key, int default_value) { + std::lock_guard<std::mutex> lock(mutex_); + auto it = properties_.find(key); + + if (it != properties_.end()) { + return std::atol(it->second.c_str()); + } else { + return default_value; + } +} + +// Parse one line in configure file like key=value +void Properties::parseConfigureFileLine(char *buf) { + char *line = buf; + + while ((line[0] == ' ') || (line[0] == '\t')) + ++line; + + char first = line[0]; + if ((first == '\0') || (first == '#') || (first == '\r') || (first == '\n') + || (first == '=')) { + return; + } + + char *equal = strchr(line, '='); + if (equal == NULL) { + return; + } + + equal[0] = '\0'; + std::string key = line; + + equal++; + while ((equal[0] == ' ') || (equal[0] == '\t')) + ++equal; + + first = equal[0]; + if ((first == '\0') || (first == '\r') || (first == '\n')) { + return; + } + + std::string value = equal; + key = org::apache::nifi::minifi::utils::StringUtils::trimRight(key); + value = org::apache::nifi::minifi::utils::StringUtils::trimRight(value); + set(key, value); +} + +// Load Configure File +void Properties::loadConfigureFile(const char *fileName) { + std::string adjustedFilename; + if (fileName) { + // perform a naive determination if this is a relative path + if (fileName[0] != '/') { + adjustedFilename = adjustedFilename + getHome() + "/" + + fileName; + } else { + adjustedFilename += fileName; + } + } + char *path = NULL; + char full_path[PATH_MAX]; + path = realpath(adjustedFilename.c_str(), full_path); + logger_->log_info("Using configuration file located at %s", path); + + std::ifstream file(path, std::ifstream::in); + if (!file.good()) { + logger_->log_error("load configure file failed %s", path); + return; + } + this->clear(); + + char buf[BUFFER_SIZE]; + for (file.getline(buf, BUFFER_SIZE); file.good(); + file.getline(buf, BUFFER_SIZE)) { + parseConfigureFileLine(buf); + } +} + +// Parse Command Line +void Properties::parseCommandLine(int argc, char **argv) { + int i; + bool keyFound = false; + std::string key, value; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] != '\0') { + keyFound = true; + key = &argv[i][1]; + continue; + } + if (keyFound) { + value = argv[i]; + set(key, value); + keyFound = false; + } + } + return; +} + +} /* namespace minifi */ +} /* namespace nifi */ +} /* namespace apache */ +} /* namespace org */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/ResourceClaim.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/ResourceClaim.cpp b/libminifi/src/ResourceClaim.cpp index b71032b..818e99b 100644 --- a/libminifi/src/ResourceClaim.cpp +++ b/libminifi/src/ResourceClaim.cpp @@ -17,12 +17,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <vector> -#include <queue> +#include <uuid/uuid.h> + #include <map> +#include <queue> #include <string> +#include <vector> #include "ResourceClaim.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -35,7 +38,8 @@ char *ResourceClaim::default_directory_path = const_cast<char*>(DEFAULT_CONTENT_ ResourceClaim::ResourceClaim(const std::string contentDirectory) : _id(_localResourceClaimNumber.load()), - _flowFileRecordOwnedCount(0) { + _flowFileRecordOwnedCount(0), + logger_(logging::LoggerFactory<ResourceClaim>::getLogger()) { char uuidStr[37]; @@ -47,7 +51,6 @@ ResourceClaim::ResourceClaim(const std::string contentDirectory) // Create the full content path for the content _contentFullPath = contentDirectory + "/" + uuidStr; - logger_ = logging::Logger::getLogger(); logger_->log_debug("Resource Claim created %s", _contentFullPath.c_str()); } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/ClassLoader.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/ClassLoader.cpp b/libminifi/src/core/ClassLoader.cpp index 77c4a85..72ac80c 100644 --- a/libminifi/src/core/ClassLoader.cpp +++ b/libminifi/src/core/ClassLoader.cpp @@ -15,17 +15,21 @@ * limitations under the License. */ -#include "core/ClassLoader.h" #include <sys/mman.h> #include <memory> #include <string> +#include "core/ClassLoader.h" +#include "core/logging/LoggerConfiguration.h" + namespace org { namespace apache { namespace nifi { namespace minifi { namespace core { +ClassLoader::ClassLoader() : logger_(logging::LoggerFactory<ClassLoader>::getLogger()) {} + ClassLoader &ClassLoader::getDefaultClassLoader() { static ClassLoader ret; // populate ret http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/ConfigurableComponent.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/ConfigurableComponent.cpp b/libminifi/src/core/ConfigurableComponent.cpp index cf2089e..94fa599 100644 --- a/libminifi/src/core/ConfigurableComponent.cpp +++ b/libminifi/src/core/ConfigurableComponent.cpp @@ -22,24 +22,23 @@ #include <string> #include <set> #include "core/Property.h" -#include "core/logging/Logger.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { namespace nifi { namespace minifi { namespace core { - -ConfigurableComponent::ConfigurableComponent( - std::shared_ptr<logging::Logger> logger) - : my_logger_(logger) { +ConfigurableComponent::ConfigurableComponent() + : logger_(logging::LoggerFactory<ConfigurableComponent>::getLogger()) { } ConfigurableComponent::ConfigurableComponent( const ConfigurableComponent &&other) : properties_(std::move(other.properties_)), - my_logger_(std::move(other.my_logger_)) { + logger_(logging::LoggerFactory<ConfigurableComponent>::getLogger()) { } + ConfigurableComponent::~ConfigurableComponent() { } @@ -71,7 +70,7 @@ bool ConfigurableComponent::getProperty(const std::string name, if (it != properties_.end()) { Property item = it->second; value = item.getValue(); - my_logger_->log_info("Processor %s property name %s value %s", name, + logger_->log_info("Processor %s property name %s value %s", name, item.getName(), value); return true; } else { @@ -93,7 +92,7 @@ bool ConfigurableComponent::setProperty(const std::string name, Property item = it->second; item.setValue(value); properties_[item.getName()] = item; - my_logger_->log_info("Component %s property name %s value %s", name.c_str(), + logger_->log_info("Component %s property name %s value %s", name.c_str(), item.getName().c_str(), value.c_str()); return true; } else { @@ -116,7 +115,7 @@ bool ConfigurableComponent::updateProperty(const std::string &name, Property item = it->second; item.addValue(value); properties_[item.getName()] = item; - my_logger_->log_info("Component %s property name %s value %s", name.c_str(), + logger_->log_info("Component %s property name %s value %s", name.c_str(), item.getName().c_str(), value.c_str()); return true; } else { @@ -138,7 +137,7 @@ bool ConfigurableComponent::setProperty(Property &prop, std::string value) { Property item = it->second; item.setValue(value); properties_[item.getName()] = item; - my_logger_->log_info("property name %s value %s", prop.getName().c_str(), + logger_->log_info("property name %s value %s", prop.getName().c_str(), item.getName().c_str(), value.c_str()); return true; } else { http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/Connectable.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/Connectable.cpp b/libminifi/src/core/Connectable.cpp index 58ae6d4..5bd32e9 100644 --- a/libminifi/src/core/Connectable.cpp +++ b/libminifi/src/core/Connectable.cpp @@ -21,7 +21,7 @@ #include <memory> #include <string> #include <set> -#include "core/logging/Logger.h" +#include "core/logging/LoggerConfiguration.h" #include "core/Relationship.h" namespace org { @@ -32,12 +32,14 @@ namespace core { Connectable::Connectable(std::string name, uuid_t uuid) : CoreComponent(name, uuid), - max_concurrent_tasks_(1) { + max_concurrent_tasks_(1), + logger_(logging::LoggerFactory<Connectable>::getLogger()) { } Connectable::Connectable(const Connectable &&other) : CoreComponent(std::move(other)), - max_concurrent_tasks_(std::move(other.max_concurrent_tasks_)) { + max_concurrent_tasks_(std::move(other.max_concurrent_tasks_)), + logger_(std::move(other.logger_)) { has_work_ = other.has_work_.load(); strategy_ = other.strategy_.load(); } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/FlowFile.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/FlowFile.cpp b/libminifi/src/core/FlowFile.cpp index b3ab741..8c693bf 100644 --- a/libminifi/src/core/FlowFile.cpp +++ b/libminifi/src/core/FlowFile.cpp @@ -20,7 +20,7 @@ #include <memory> #include <string> #include <set> -#include "core/logging/Logger.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { namespace nifi { @@ -38,7 +38,8 @@ FlowFile::FlowFile() claim_(nullptr), marked_delete_(false), connection_(nullptr), - original_connection_() { + original_connection_(), + logger_(logging::LoggerFactory<FlowFile>::getLogger()) { entry_date_ = getTimeMillis(); lineage_start_date_ = entry_date_; @@ -49,8 +50,6 @@ FlowFile::FlowFile() uuid_unparse_lower(uuid_, uuidStr); uuid_str_ = uuidStr; - - logger_ = logging::Logger::getLogger(); } FlowFile::~FlowFile() { http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/ProcessGroup.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/ProcessGroup.cpp b/libminifi/src/core/ProcessGroup.cpp index 01d3dbf..c33800d 100644 --- a/libminifi/src/core/ProcessGroup.cpp +++ b/libminifi/src/core/ProcessGroup.cpp @@ -29,6 +29,7 @@ #include <chrono> #include <thread> #include "core/Processor.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -38,7 +39,8 @@ namespace core { ProcessGroup::ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid, ProcessGroup *parent) - : name_(name), + : logger_(logging::LoggerFactory<ProcessGroup>::getLogger()), + name_(name), type_(type), parent_process_group_(parent) { if (!uuid) @@ -50,7 +52,6 @@ ProcessGroup::ProcessGroup(ProcessGroupType type, std::string name, uuid_t uuid, yield_period_msec_ = 0; transmitting_ = false; - logger_ = logging::Logger::getLogger(); logger_->log_info("ProcessGroup %s created", name_.c_str()); } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/Processor.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/Processor.cpp b/libminifi/src/core/Processor.cpp index ac03fde..dbeb46f 100644 --- a/libminifi/src/core/Processor.cpp +++ b/libminifi/src/core/Processor.cpp @@ -36,6 +36,7 @@ #include "core/ProcessSession.h" #include "core/ProcessSessionFactory.h" #include "../include/io/StreamFactory.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -44,8 +45,8 @@ namespace minifi { namespace core { Processor::Processor(std::string name, uuid_t uuid) - : Connectable(name, uuid), - ConfigurableComponent(logging::Logger::getLogger()) { + : Connectable(name, uuid), ConfigurableComponent(), + logger_(logging::LoggerFactory<Processor>::getLogger()) { has_work_.store(false); // Setup the default values state_ = DISABLED; @@ -60,7 +61,6 @@ Processor::Processor(std::string name, uuid_t uuid) active_tasks_ = 0; yield_expiration_ = 0; incoming_connections_Iter = this->_incomingConnections.begin(); - logger_ = logging::Logger::getLogger(); logger_->log_info("Processor %s created UUID %s", name_.c_str(), uuidStr_.c_str()); } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/ProcessorNode.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/ProcessorNode.cpp b/libminifi/src/core/ProcessorNode.cpp index 8979e32..bf39738 100644 --- a/libminifi/src/core/ProcessorNode.cpp +++ b/libminifi/src/core/ProcessorNode.cpp @@ -25,8 +25,7 @@ namespace core { ProcessorNode::ProcessorNode(const std::shared_ptr<Connectable> processor) : processor_(processor), - Connectable(processor->getName(), 0), - ConfigurableComponent(logging::Logger::getLogger()) { + Connectable(processor->getName(), 0), ConfigurableComponent() { uuid_t copy; processor->getUUID(copy); setUUID(copy); @@ -34,8 +33,7 @@ ProcessorNode::ProcessorNode(const std::shared_ptr<Connectable> processor) ProcessorNode::ProcessorNode(const ProcessorNode &other) : processor_(other.processor_), - Connectable(other.getName(), 0), - ConfigurableComponent(logging::Logger::getLogger()) { + Connectable(other.getName(), 0) { uuid_t copy; processor_->getUUID(copy); setUUID(copy); http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/logging/BaseLogger.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/logging/BaseLogger.cpp b/libminifi/src/core/logging/BaseLogger.cpp deleted file mode 100644 index 9164270..0000000 --- a/libminifi/src/core/logging/BaseLogger.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "core/logging/BaseLogger.h" -#include <utility> -#include <memory> -#include <algorithm> -#include <string> - -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace core { -namespace logging { - -// Logger related configuration items. -const char *BaseLogger::nifi_log_level = "nifi.log.level"; -const char *BaseLogger::nifi_log_appender = "nifi.log.appender"; - - -// overridables - -/** - * @brief Log error message - * @param format format string ('man printf' for syntax) - * @warning does not check @p log or @p format for null. Caller must ensure parameters and format string lengths match - */ -void BaseLogger::log_str(LOG_LEVEL_E level, const std::string &buffer) { - switch (level) { - case err: - case critical: - if (stderr_ != nullptr) { - stderr_->error(buffer); - } else { - logger_->error(buffer); - } - break; - case warn: - logger_->warn(buffer); - break; - case info: - logger_->info(buffer); - break; - case debug: - logger_->debug(buffer); - break; - case trace: - logger_->trace(buffer); - break; - case off: - break; - default: - logger_->info(buffer); - break; - } -} - -void BaseLogger::setLogLevel(const std::string &level, - LOG_LEVEL_E defaultLevel) { - std::string logLevel = level; - std::transform(logLevel.begin(), logLevel.end(), logLevel.begin(), ::tolower); - - if (logLevel == "trace") { - setLogLevel(trace); - } else if (logLevel == "debug") { - setLogLevel(debug); - } else if (logLevel == "info") { - setLogLevel(info); - } else if (logLevel == "warn") { - setLogLevel(warn); - } else if (logLevel == "error") { - setLogLevel(err); - } else if (logLevel == "critical") { - setLogLevel(critical); - } else if (logLevel == "off") { - setLogLevel(off); - } else { - setLogLevel(defaultLevel); - } -} - -void BaseLogger::set_error_logger(std::shared_ptr<spdlog::logger> other) { - stderr_ = std::move(other); -} - -} /* namespace logging */ -} /* namespace core */ -} /* namespace minifi */ -} /* namespace nifi */ -} /* namespace apache */ -} /* namespace org */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/logging/LogAppenders.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/logging/LogAppenders.cpp b/libminifi/src/core/logging/LogAppenders.cpp deleted file mode 100644 index 1918a0d..0000000 --- a/libminifi/src/core/logging/LogAppenders.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "core/logging/LogAppenders.h" -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace core { -namespace logging { - -const char *OutputStreamAppender::nifi_log_output_stream_error_stderr = - "nifi.log.outputstream.appender.error.stderr"; - -const char *RollingAppender::nifi_log_rolling_apender_file = - "nifi.log.rolling.appender.file"; -const char *RollingAppender::nifi_log_rolling_appender_max_files = - "nifi.log.rolling.appender.max.files"; -const char *RollingAppender::nifi_log_rolling_appender_max_file_size = - "nifi.log.rolling.appender.max.file_size"; - -} /* namespace logging */ -} /* namespace core */ -} /* namespace minifi */ -} /* namespace nifi */ -} /* namespace apache */ -} /* namespace org */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/logging/Logger.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/logging/Logger.cpp b/libminifi/src/core/logging/Logger.cpp deleted file mode 100644 index 5c08fa8..0000000 --- a/libminifi/src/core/logging/Logger.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file Logger.cpp - * Logger class implementation - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "core/logging/Logger.h" - -#include <vector> -#include <queue> -#include <memory> -#include <map> - -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace core { -namespace logging { - -std::shared_ptr<Logger> Logger::singleton_logger_(nullptr); - -} /* namespace logging */ -} /* namespace core */ -} /* namespace minifi */ -} /* namespace nifi */ -} /* namespace apache */ -} /* namespace org */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/core/logging/LoggerConfiguration.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/core/logging/LoggerConfiguration.cpp b/libminifi/src/core/logging/LoggerConfiguration.cpp new file mode 100644 index 0000000..4bb6615 --- /dev/null +++ b/libminifi/src/core/logging/LoggerConfiguration.cpp @@ -0,0 +1,254 @@ +/** + * @file Logger.cpp + * Logger class implementation + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> +#include <vector> +#include <queue> +#include <memory> +#include <map> +#include <string> + +#include "core/Core.h" +#include "core/logging/LoggerConfiguration.h" +#include "utils/StringUtils.h" + +#include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_sinks.h" +#include "spdlog/sinks/null_sink.h" + +namespace org { +namespace apache { +namespace nifi { +namespace minifi { +namespace core { +namespace logging { + +const char* LoggerConfiguration::spdlog_default_pattern = "[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v"; + +std::vector< std::string > LoggerProperties::get_keys_of_type(const std::string &type) { + std::vector<std::string> appenders; + std::string prefix = type + "."; + for (auto const & entry : properties_) { + if (entry.first.rfind(prefix, 0) == 0 && + entry.first.find(".", prefix.length() + 1) == std::string::npos) { + appenders.push_back(entry.first); + } + } + return appenders; +} + +LoggerConfiguration::LoggerConfiguration() : root_namespace_(create_default_root()), loggers(std::vector<std::shared_ptr<LoggerImpl>>()), + formatter_(std::make_shared<spdlog::pattern_formatter>(spdlog_default_pattern)) { + logger_ = std::shared_ptr<LoggerImpl>(new LoggerImpl(core::getClassName<LoggerConfiguration>(), get_logger(nullptr, root_namespace_, core::getClassName<LoggerConfiguration>(), formatter_))); + loggers.push_back(logger_); +} + +void LoggerConfiguration::initialize(const std::shared_ptr<LoggerProperties> &logger_properties) { + std::lock_guard<std::mutex> lock(mutex); + root_namespace_ = initialize_namespaces(logger_properties); + std::string spdlog_pattern; + if (!logger_properties->get("spdlog.pattern", spdlog_pattern)) { + spdlog_pattern = spdlog_default_pattern; + } + formatter_ = std::make_shared<spdlog::pattern_formatter>(spdlog_pattern); + std::map<std::string, std::shared_ptr<spdlog::logger>> spdloggers; + for (auto const & logger_impl : loggers) { + std::shared_ptr<spdlog::logger> spdlogger; + auto it = spdloggers.find(logger_impl->name); + if (it == spdloggers.end()) { + spdlogger = get_logger(logger_, root_namespace_, logger_impl->name, formatter_, true); + spdloggers[logger_impl->name] = spdlogger; + } else { + spdlogger = it->second; + } + logger_impl->set_delegate(spdlogger); + } + logger_->log_debug("Set following pattern on loggers: %s", spdlog_pattern); +} + +std::shared_ptr<Logger> LoggerConfiguration::getLogger(const std::string &name) { + std::lock_guard<std::mutex> lock(mutex); + std::shared_ptr<LoggerImpl> result = std::make_shared<LoggerImpl>(name, get_logger(logger_, root_namespace_, name, formatter_)); + loggers.push_back(result); + return result; +} + +std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration:: + initialize_namespaces(const std::shared_ptr<LoggerProperties> &logger_properties) { + std::map<std::string, std::shared_ptr<spdlog::sinks::sink>> sink_map = logger_properties->initial_sinks(); + + std::string appender_type = "appender"; + for (auto const & appender_key : logger_properties->get_keys_of_type(appender_type)) { + std::string appender_name = appender_key.substr(appender_type.length() + 1); + std::string appender_type; + if (!logger_properties->get(appender_key, appender_type)) { + appender_type = "stderr"; + } + std::transform(appender_type.begin(), appender_type.end(), appender_type.begin(), ::tolower); + + if ("nullappender" == appender_type || "null appender" == appender_type || "null" == appender_type) { + sink_map[appender_name] = std::make_shared<spdlog::sinks::null_sink_st>(); + } else if ("rollingappender" == appender_type || "rolling appender" == appender_type || "rolling" == appender_type) { + std::string file_name = ""; + if (!logger_properties->get(appender_key + ".file_name", file_name)) { + file_name = "minifi-app.log"; + } + + int max_files = 3; + std::string max_files_str = ""; + if (logger_properties->get(appender_key + ".max_files", max_files_str)) { + try { + max_files = std::stoi(max_files_str); + } catch (const std::invalid_argument &ia) { + } catch (const std::out_of_range &oor) {} + } + + int max_file_size = 5*1024*1024; + std::string max_file_size_str = ""; + if (logger_properties->get(appender_key + ".max_file_size", max_file_size_str)) { + try { + max_file_size = std::stoi(max_file_size_str); + } catch (const std::invalid_argument &ia) { + } catch (const std::out_of_range &oor) {} + } + sink_map[appender_name] = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_name, max_file_size, max_files); + } else if ("stdout" == appender_type) { + sink_map[appender_name] = spdlog::sinks::stdout_sink_mt::instance(); + } else { + sink_map[appender_name] = spdlog::sinks::stderr_sink_mt::instance(); + } + } + + std::shared_ptr<internal::LoggerNamespace> root_namespace = std::make_shared<internal::LoggerNamespace>(); + std::string logger_type = "logger"; + for (auto const & logger_key : logger_properties->get_keys_of_type(logger_type)) { + std::string logger_def; + if (!logger_properties->get(logger_key, logger_def)) { + continue; + } + bool first = true; + spdlog::level::level_enum level = spdlog::level::info; + std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks; + for (auto const & segment : utils::StringUtils::split(logger_def, ",")) { + std::string level_name = utils::StringUtils::trim(segment); + if (first) { + first = false; + std::transform(level_name.begin(), level_name.end(), level_name.begin(), ::tolower); + if ("trace" == level_name) { + level = spdlog::level::trace; + } else if ("debug" == level_name) { + level = spdlog::level::debug; + } else if ("warn" == level_name) { + level = spdlog::level::warn; + } else if ("critical" == level_name) { + level = spdlog::level::critical; + } else if ("error" == level_name) { + level = spdlog::level::err; + } else if ("off" == level_name) { + level = spdlog::level::off; + } + } else { + sinks.push_back(sink_map[level_name]); + } + } + std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace; + if (logger_key != "logger.root") { + for (auto const & name : utils::StringUtils::split(logger_key.substr(logger_type.length() + 1, + logger_key.length() - logger_type.length()), "::")) { + auto child_pair = current_namespace->children.find(name); + std::shared_ptr<internal::LoggerNamespace> child; + if (child_pair == current_namespace->children.end()) { + child = std::make_shared<internal::LoggerNamespace>(); + current_namespace->children[name] = child; + } else { + child = child_pair->second; + } + current_namespace = child; + } + } + current_namespace->level = level; + current_namespace->has_level = true; + current_namespace->sinks = sinks; + } + return root_namespace; +} + +std::shared_ptr<spdlog::logger> LoggerConfiguration::get_logger(std::shared_ptr<Logger> logger, const std::shared_ptr<internal::LoggerNamespace> &root_namespace, + const std::string &name, std::shared_ptr<spdlog::formatter> formatter, bool remove_if_present) { + std::shared_ptr<spdlog::logger> spdlogger = spdlog::get(name); + if (spdlogger) { + if (remove_if_present) { + spdlog::drop(name); + } else { + return spdlogger; + } + } + std::shared_ptr<internal::LoggerNamespace> current_namespace = root_namespace; + std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks = root_namespace->sinks; + spdlog::level::level_enum level = root_namespace->level; + std::string current_namespace_str = ""; + std::string sink_namespace_str = "root"; + std::string level_namespace_str = "root"; + for (auto const & name_segment : utils::StringUtils::split(name, "::")) { + current_namespace_str += name_segment; + auto child_pair = current_namespace->children.find(name_segment); + if (child_pair == current_namespace->children.end()) { + break; + } + current_namespace = child_pair->second; + if (current_namespace->sinks.size() > 0) { + sinks = current_namespace->sinks; + sink_namespace_str = current_namespace_str; + } + if (current_namespace->has_level) { + level = current_namespace->level; + level_namespace_str = current_namespace_str; + } + current_namespace_str += "::"; + } + if (logger != nullptr) { + logger->log_debug("%s logger got sinks from namespace %s and level %s from namespace %s", name, sink_namespace_str, spdlog::level::level_names[level], level_namespace_str); + } + spdlogger = std::make_shared<spdlog::logger>(name, begin(sinks), end(sinks)); + spdlogger->set_level(level); + spdlogger->set_formatter(formatter); + spdlogger->flush_on(std::max(spdlog::level::info, current_namespace->level)); + try { + spdlog::register_logger(spdlogger); + } catch (const spdlog::spdlog_ex &ex) { + // Ignore as someone else beat us to registration, we should get the one they made below + } + return spdlog::get(name); +} + +std::shared_ptr<internal::LoggerNamespace> LoggerConfiguration::create_default_root() { + std::shared_ptr<internal::LoggerNamespace> result = std::make_shared<internal::LoggerNamespace>(); + result->sinks = std::vector<std::shared_ptr<spdlog::sinks::sink>>(); + result->sinks.push_back(spdlog::sinks::stderr_sink_mt::instance()); + result->level = spdlog::level::info; + return result; +} + +} /* namespace logging */ +} /* namespace core */ +} /* namespace minifi */ +} /* namespace nifi */ +} /* namespace apache */ +} /* namespace org */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/io/ClientSocket.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/io/ClientSocket.cpp b/libminifi/src/io/ClientSocket.cpp index 7a4a191..bd99bc7 100644 --- a/libminifi/src/io/ClientSocket.cpp +++ b/libminifi/src/io/ClientSocket.cpp @@ -31,6 +31,7 @@ #include <iostream> #include <string> #include "io/validation.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -38,8 +39,6 @@ namespace nifi { namespace minifi { namespace io { -char *Socket::HOSTNAME = const_cast<char*>(Socket::getMyHostName(0).c_str()); - Socket::Socket(const std::shared_ptr<SocketContext> &context, const std::string &hostname, const uint16_t port, const uint16_t listeners = -1) : requested_hostname_(hostname), @@ -48,8 +47,8 @@ Socket::Socket(const std::shared_ptr<SocketContext> &context, const std::string socket_file_descriptor_(-1), socket_max_(0), listeners_(listeners), - canonical_hostname_("") { - logger_ = logging::Logger::getLogger(); + canonical_hostname_(""), + logger_(logging::LoggerFactory<Socket>::getLogger()) { FD_ZERO(&total_list_); FD_ZERO(&read_fds_); } @@ -67,8 +66,8 @@ Socket::Socket(const Socket &&other) listeners_(other.listeners_), total_list_(other.total_list_), read_fds_(other.read_fds_), - canonical_hostname_(std::move(other.canonical_hostname_)) { - logger_ = logging::Logger::getLogger(); + canonical_hostname_(std::move(other.canonical_hostname_)), + logger_(std::move(other.logger_)) { } Socket::~Socket() { http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/io/tls/TLSSocket.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/io/tls/TLSSocket.cpp b/libminifi/src/io/tls/TLSSocket.cpp index 4c3bf51..b269cef 100644 --- a/libminifi/src/io/tls/TLSSocket.cpp +++ b/libminifi/src/io/tls/TLSSocket.cpp @@ -25,6 +25,7 @@ #include "properties/Configure.h" #include "utils/StringUtils.h" #include "core/Property.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -39,7 +40,7 @@ TLSContext::TLSContext(const std::shared_ptr<Configure> &configure) : SocketContext(configure), error_value(0), ctx(0), - logger_(logging::Logger::getLogger()), + logger_(logging::LoggerFactory<TLSContext>::getLogger()), configure_(configure) { } /** @@ -152,20 +153,20 @@ TLSSocket::TLSSocket(const std::shared_ptr<TLSContext> &context, const std::string &hostname, const uint16_t port, const uint16_t listeners) : Socket(context, hostname, port, listeners), - ssl(0) { + ssl(0), logger_(logging::LoggerFactory<TLSSocket>::getLogger()) { context_ = context; } TLSSocket::TLSSocket(const std::shared_ptr<TLSContext> &context, const std::string &hostname, const uint16_t port) : Socket(context, hostname, port, 0), - ssl(0) { + ssl(0), logger_(logging::LoggerFactory<TLSSocket>::getLogger()) { context_ = context; } TLSSocket::TLSSocket(const TLSSocket &&d) : Socket(std::move(d)), - ssl(0) { + ssl(0), logger_(std::move(d.logger_)) { context_ = d.context_; } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/processors/ListenHTTP.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/processors/ListenHTTP.cpp b/libminifi/src/processors/ListenHTTP.cpp index 5c4a6bb..9fce69a 100644 --- a/libminifi/src/processors/ListenHTTP.cpp +++ b/libminifi/src/processors/ListenHTTP.cpp @@ -34,6 +34,7 @@ #include "core/ProcessContext.h" #include "core/ProcessSession.h" #include "core/ProcessSessionFactory.h" +#include "core/logging/LoggerConfiguration.h" namespace org { namespace apache { @@ -75,7 +76,7 @@ core::Relationship ListenHTTP::Success("success", "All files are routed to success"); void ListenHTTP::initialize() { - _logger->log_info("Initializing ListenHTTP"); + logger_->log_info("Initializing ListenHTTP"); // Set the supported properties std::set<core::Property> properties; @@ -99,7 +100,7 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, std::string basePath; if (!context->getProperty(BasePath.getName(), basePath)) { - _logger->log_info( + logger_->log_info( "%s attribute is missing, so default value of %s will be used", BasePath.getName().c_str(), BasePath.getValue().c_str()); basePath = BasePath.getValue(); @@ -110,7 +111,7 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, std::string listeningPort; if (!context->getProperty(Port.getName(), listeningPort)) { - _logger->log_error("%s attribute is missing or invalid", + logger_->log_error("%s attribute is missing or invalid", Port.getName().c_str()); return; } @@ -119,7 +120,7 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, if (context->getProperty(AuthorizedDNPattern.getName(), authDNPattern) && !authDNPattern.empty()) { - _logger->log_info("ListenHTTP using %s: %s", + logger_->log_info("ListenHTTP using %s: %s", AuthorizedDNPattern.getName().c_str(), authDNPattern.c_str()); } @@ -128,7 +129,7 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, if (context->getProperty(SSLCertificate.getName(), sslCertFile) && !sslCertFile.empty()) { - _logger->log_info("ListenHTTP using %s: %s", + logger_->log_info("ListenHTTP using %s: %s", SSLCertificate.getName().c_str(), sslCertFile.c_str()); } @@ -141,23 +142,23 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, if (context->getProperty(SSLCertificateAuthority.getName(), sslCertAuthorityFile) && !sslCertAuthorityFile.empty()) { - _logger->log_info("ListenHTTP using %s: %s", + logger_->log_info("ListenHTTP using %s: %s", SSLCertificateAuthority.getName().c_str(), sslCertAuthorityFile.c_str()); } if (context->getProperty(SSLVerifyPeer.getName(), sslVerifyPeer)) { if (sslVerifyPeer.empty() || sslVerifyPeer.compare("no") == 0) { - _logger->log_info("ListenHTTP will not verify peers"); + logger_->log_info("ListenHTTP will not verify peers"); } else { - _logger->log_info("ListenHTTP will verify peers"); + logger_->log_info("ListenHTTP will verify peers"); } } else { - _logger->log_info("ListenHTTP will not verify peers"); + logger_->log_info("ListenHTTP will not verify peers"); } if (context->getProperty(SSLMinimumVersion.getName(), sslMinVer)) { - _logger->log_info("ListenHTTP using %s: %s", + logger_->log_info("ListenHTTP using %s: %s", SSLMinimumVersion.getName().c_str(), sslMinVer.c_str()); } } @@ -167,14 +168,14 @@ void ListenHTTP::onSchedule(core::ProcessContext *context, if (context->getProperty(HeadersAsAttributesRegex.getName(), headersAsAttributesPattern) && !headersAsAttributesPattern.empty()) { - _logger->log_info("ListenHTTP using %s: %s", + logger_->log_info("ListenHTTP using %s: %s", HeadersAsAttributesRegex.getName().c_str(), headersAsAttributesPattern.c_str()); } auto numThreads = getMaxConcurrentTasks(); - _logger->log_info( + logger_->log_info( "ListenHTTP starting HTTP server on port %s and path %s with %d threads", listeningPort.c_str(), basePath.c_str(), numThreads); @@ -255,7 +256,8 @@ ListenHTTP::Handler::Handler(core::ProcessContext *context, std::string &&authDNPattern, std::string &&headersAsAttributesPattern) : _authDNRegex(std::move(authDNPattern)), - _headersAsAttributesRegex(std::move(headersAsAttributesPattern)) { + _headersAsAttributesRegex(std::move(headersAsAttributesPattern)), + logger_(logging::LoggerFactory<ListenHTTP::Handler>::getLogger()) { _processContext = context; _processSessionFactory = sessionFactory; } @@ -268,10 +270,8 @@ void ListenHTTP::Handler::sendErrorResponse(struct mg_connection *conn) { bool ListenHTTP::Handler::handlePost(CivetServer *server, struct mg_connection *conn) { - _logger = logging::Logger::getLogger(); - auto req_info = mg_get_request_info(conn); - _logger->log_info("ListenHTTP handling POST request of length %d", + logger_->log_info("ListenHTTP handling POST request of length %d", req_info->content_length); // If this is a two-way TLS connection, authorize the peer against the configured pattern @@ -280,7 +280,7 @@ bool ListenHTTP::Handler::handlePost(CivetServer *server, mg_printf(conn, "HTTP/1.1 403 Forbidden\r\n" "Content-Type: text/html\r\n" "Content-Length: 0\r\n\r\n"); - _logger->log_warn("ListenHTTP client DN not authorized: %s", + logger_->log_warn("ListenHTTP client DN not authorized: %s", req_info->client_cert->subject); return true; } @@ -319,12 +319,12 @@ bool ListenHTTP::Handler::handlePost(CivetServer *server, session->transfer(flowFile, Success); session->commit(); } catch (std::exception &exception) { - _logger->log_debug("ListenHTTP Caught Exception %s", exception.what()); + logger_->log_debug("ListenHTTP Caught Exception %s", exception.what()); sendErrorResponse(conn); session->rollback(); throw; } catch (...) { - _logger->log_debug("ListenHTTP Caught Exception Processor::onTrigger"); + logger_->log_debug("ListenHTTP Caught Exception Processor::onTrigger"); sendErrorResponse(conn); session->rollback(); throw; @@ -337,9 +337,8 @@ bool ListenHTTP::Handler::handlePost(CivetServer *server, return true; } -ListenHTTP::WriteCallback::WriteCallback( - struct mg_connection *conn, const struct mg_request_info *reqInfo) { - _logger = logging::Logger::getLogger(); +ListenHTTP::WriteCallback::WriteCallback(struct mg_connection *conn, const struct mg_request_info *reqInfo) : + logger_(logging::LoggerFactory<ListenHTTP::WriteCallback>::getLogger()) { _conn = conn; _reqInfo = reqInfo; } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/src/processors/PutFile.cpp ---------------------------------------------------------------------- diff --git a/libminifi/src/processors/PutFile.cpp b/libminifi/src/processors/PutFile.cpp index bd08877..d8832c7 100644 --- a/libminifi/src/processors/PutFile.cpp +++ b/libminifi/src/processors/PutFile.cpp @@ -153,8 +153,8 @@ PutFile::ReadCallback::ReadCallback(const std::string &tmpFile, const std::string &destFile) : _tmpFile(tmpFile), _tmpFileOs(tmpFile), - _destFile(destFile) { - logger_ = logging::Logger::getLogger(); + _destFile(destFile), + logger_(logging::LoggerFactory<PutFile::ReadCallback>::getLogger()) { } // Copy the entire file contents to the temporary file http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/TestBase.h ---------------------------------------------------------------------- diff --git a/libminifi/test/TestBase.h b/libminifi/test/TestBase.h index 18d5d01..7b1ac6b 100644 --- a/libminifi/test/TestBase.h +++ b/libminifi/test/TestBase.h @@ -21,35 +21,124 @@ #include <dirent.h> #include <cstdio> #include <cstdlib> +#include <sstream> #include "ResourceClaim.h" #include "catch.hpp" #include <vector> -#include "core/logging/LogAppenders.h" #include "core/logging/Logger.h" #include "core/Core.h" #include "properties/Configure.h" +#include "properties/Properties.h" +#include "core/logging/LoggerConfiguration.h" +#include "spdlog/sinks/ostream_sink.h" +#include "spdlog/sinks/dist_sink.h" class LogTestController { public: - LogTestController(const std::string level = "debug") { - logging::Logger::getLogger()->setLogLevel(level); + static LogTestController& getInstance() { + static LogTestController instance; + return instance; } - - void enableDebug() { - logging::Logger::getLogger()->setLogLevel("debug"); + + template<typename T> + void setTrace() { + setLevel<T>(spdlog::level::trace); + } + + template<typename T> + void setDebug() { + setLevel<T>(spdlog::level::debug); + } + + template<typename T> + void setInfo() { + setLevel<T>(spdlog::level::info); + } + + template<typename T> + void setWarn() { + setLevel<T>(spdlog::level::warn); + } + + template<typename T> + void setError() { + setLevel<T>(spdlog::level::err); + } + + template<typename T> + void setOff() { + setLevel<T>(spdlog::level::off); + } + + template<typename T> + void setLevel(spdlog::level::level_enum level) { + logging::LoggerFactory<T>::getLogger(); + std::string name = core::getClassName<T>(); + modified_loggers.push_back(name); + setLevel(name, level); + } + + bool contains(const std::string &ending) { + return contains(log_output, ending); + } + + bool contains(const std::ostringstream &stream, const std::string &ending) { + std::string str = stream.str(); + logger_->log_info("Looking for %s in %s.", ending, str); + return (ending.length() > 0 && str.find(ending) != std::string::npos); + } + + void reset() { + for (auto const & name : modified_loggers) { + setLevel(name, spdlog::level::err); + } + modified_loggers = std::vector<std::string>(); + resetStream(log_output); + } + + inline void resetStream(std::ostringstream &stream) { + stream.str(""); + stream.clear(); + } + + std::ostringstream log_output; + + std::shared_ptr<logging::Logger> logger_; + private: + class TestBootstrapLogger: public logging::Logger { + public: + TestBootstrapLogger(std::shared_ptr<spdlog::logger> logger):Logger(logger){}; + }; + LogTestController() { + std::shared_ptr<logging::LoggerProperties> logger_properties = std::make_shared<logging::LoggerProperties>(); + logger_properties->set("logger.root", "ERROR,ostream"); + logger_properties->set("logger." + core::getClassName<LogTestController>(), "INFO"); + logger_properties->set("logger." + core::getClassName<logging::LoggerConfiguration>(), "DEBUG"); + std::shared_ptr<spdlog::sinks::dist_sink_mt> dist_sink = std::make_shared<spdlog::sinks::dist_sink_mt>(); + dist_sink->add_sink(std::make_shared<spdlog::sinks::ostream_sink_mt>(log_output, true)); + dist_sink->add_sink(spdlog::sinks::stderr_sink_mt::instance()); + logger_properties->add_sink("ostream", dist_sink); + logging::LoggerConfiguration::getConfiguration().initialize(logger_properties); + logger_ = logging::LoggerFactory<LogTestController>::getLogger(); } + LogTestController(LogTestController const&); + LogTestController& operator=(LogTestController const&); + ~LogTestController() {}; - ~LogTestController() { - logging::Logger::getLogger()->setLogLevel(logging::LOG_LEVEL_E::info); + void setLevel(const std::string name, spdlog::level::level_enum level) { + logger_->log_info("Setting log level for %s to %s", name, spdlog::level::to_str(level)); + spdlog::get(name)->set_level(level); } + std::vector<std::string> modified_loggers; }; class TestController { public: TestController() - : log("info") { + : log(LogTestController::getInstance()) { minifi::ResourceClaim::default_directory_path = const_cast<char*>("./"); + log.reset(); } ~TestController() { @@ -73,30 +162,6 @@ class TestController { } } - void setDebugToConsole( - std::shared_ptr<org::apache::nifi::minifi::Configure> configure) { - std::ostringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender( - std::cout, configure)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - } - - void setNullAppender() { - - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::NullAppender()); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - } - - void enableDebug() { - log.enableDebug(); - } - char *createTempDirectory(char *format) { char *dir = mkdtemp(format); directories.push_back(dir); @@ -104,7 +169,7 @@ class TestController { } protected: - LogTestController log; + LogTestController &log; std::vector<char*> directories; }; http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/integration/ControllerServiceIntegrationTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/integration/ControllerServiceIntegrationTests.cpp b/libminifi/test/integration/ControllerServiceIntegrationTests.cpp index 4668bb9..f1376e0 100644 --- a/libminifi/test/integration/ControllerServiceIntegrationTests.cpp +++ b/libminifi/test/integration/ControllerServiceIntegrationTests.cpp @@ -24,8 +24,6 @@ #include <utility> #include <thread> #include <type_traits> -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" #include <vector> #include "../include/core/controller/ControllerServiceMap.h" @@ -33,7 +31,7 @@ #include "../include/core/controller/StandardControllerServiceProvider.h" #include "controllers/SSLContextService.h" #include "../include/core/Core.h" -#include "../include/core/logging/Logger.h" +#include "../include/core/logging/LoggerConfiguration.h" #include "../include/core/ProcessGroup.h" #include "../include/core/Resource.h" #include "../include/core/yaml/YamlConfiguration.h" @@ -71,8 +69,6 @@ int main(int argc, char **argv) { key_dir = argv[1]; } - logging::Logger::getLogger()->setLogLevel("trace"); - std::shared_ptr<minifi::Configure> configuration = std::make_shared< minifi::Configure>(); @@ -138,8 +134,6 @@ int main(int argc, char **argv) { std::shared_ptr<core::controller::ControllerServiceNode> notexistNode = pg ->findControllerService("MockItLikeItsWrong"); assert(notexistNode == nullptr); - logging::Logger::getLogger()->log_info( - "STARTING FLOW CONTROLLER INTEGRATION TEST"); controller->load(); controller->start(); std::shared_ptr<core::controller::ControllerServiceNode> ssl_client_cont = http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/integration/HttpGetIntegrationTest.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/integration/HttpGetIntegrationTest.cpp b/libminifi/test/integration/HttpGetIntegrationTest.cpp index 866309f..018ab59 100644 --- a/libminifi/test/integration/HttpGetIntegrationTest.cpp +++ b/libminifi/test/integration/HttpGetIntegrationTest.cpp @@ -29,9 +29,7 @@ #include "../TestBase.h" #include "utils/StringUtils.h" #include "core/Core.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" -#include "core/logging/Logger.h" +#include "../include/core/logging/Logger.h" #include "core/ProcessGroup.h" #include "core/yaml/YamlConfiguration.h" #include "FlowController.h" @@ -44,6 +42,8 @@ void waitToVerifyProcessor() { } int main(int argc, char **argv) { + LogTestController::getInstance().setInfo<minifi::processors::InvokeHTTP>(); + LogTestController::getInstance().setInfo<minifi::processors::LogAttribute>(); std::string key_dir, test_file_location; if (argc > 1) { test_file_location = argv[1]; @@ -53,14 +53,6 @@ int main(int argc, char **argv) { minifi::Configure>(); configuration->set(minifi::Configure::nifi_default_directory, key_dir); mkdir("content_repository", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - std::ostringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - logger->setLogLevel("debug"); std::shared_ptr<core::Repository> test_repo = std::make_shared<TestRepository>(); @@ -98,8 +90,7 @@ int main(int argc, char **argv) { waitToVerifyProcessor(); controller->waitUnload(60000); - std::string logs = oss.str(); - std::cout << logs << std::endl; + std::string logs = LogTestController::getInstance().log_output.str(); assert(logs.find("key:filename value:") != std::string::npos); assert( logs.find( @@ -121,6 +112,7 @@ int main(int argc, char **argv) { if (loc == std::string::npos) break; } + LogTestController::getInstance().reset(); rmdir("./content_repository"); return 0; } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/integration/HttpPostIntegrationTest.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/integration/HttpPostIntegrationTest.cpp b/libminifi/test/integration/HttpPostIntegrationTest.cpp index 8e6ebec..e88fc57 100644 --- a/libminifi/test/integration/HttpPostIntegrationTest.cpp +++ b/libminifi/test/integration/HttpPostIntegrationTest.cpp @@ -28,15 +28,14 @@ #include <vector> #include "utils/StringUtils.h" #include "core/Core.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" -#include "core/logging/Logger.h" +#include "../include/core/logging/Logger.h" #include "core/ProcessGroup.h" #include "core/yaml/YamlConfiguration.h" #include "FlowController.h" #include "properties/Configure.h" #include "../unit/ProvenanceTestHelper.h" #include "io/StreamFactory.h" +#include "../TestBase.h" void waitToVerifyProcessor() { @@ -44,6 +43,8 @@ void waitToVerifyProcessor() { } int main(int argc, char **argv) { + LogTestController::getInstance().setDebug<processors::InvokeHTTP>(); + LogTestController::getInstance().setDebug<minifi::core::ProcessSession>(); std::string test_file_location; if (argc > 1) { test_file_location = argv[1]; @@ -54,14 +55,6 @@ int main(int argc, char **argv) { myfile << "Hello world" << std::endl; myfile.close(); mkdir("content_repository", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - std::ostringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - logger->setLogLevel("debug"); std::shared_ptr<minifi::Configure> configuration = std::make_shared< minifi::Configure>(); @@ -103,12 +96,12 @@ int main(int argc, char **argv) { waitToVerifyProcessor(); controller->waitUnload(60000); - std::string logs = oss.str(); - assert(logs.find("curl performed") != std::string::npos); - assert(logs.find("Import offset 0 length 12") != std::string::npos); + assert(LogTestController::getInstance().contains("curl performed") == true); + assert(LogTestController::getInstance().contains("Import offset 0 length 12") == true); std::string stringtofind = "Resource Claim created ./content_repository/"; + std::string logs = LogTestController::getInstance().log_output.str(); size_t loc = logs.find(stringtofind); while (loc > 0 && loc != std::string::npos) { std::string id = logs.substr(loc + stringtofind.size(), 36); @@ -120,5 +113,6 @@ int main(int argc, char **argv) { } rmdir("./content_repository"); + LogTestController::getInstance().reset(); return 0; } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/integration/ProvenanceReportingTest.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/integration/ProvenanceReportingTest.cpp b/libminifi/test/integration/ProvenanceReportingTest.cpp index ff5d563..5e2c7b8 100644 --- a/libminifi/test/integration/ProvenanceReportingTest.cpp +++ b/libminifi/test/integration/ProvenanceReportingTest.cpp @@ -28,8 +28,6 @@ #include <vector> #include "utils/StringUtils.h" #include "core/Core.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" #include "core/logging/Logger.h" #include "core/ProcessGroup.h" #include "core/yaml/YamlConfiguration.h" @@ -37,6 +35,7 @@ #include "properties/Configure.h" #include "../unit/ProvenanceTestHelper.h" #include "io/StreamFactory.h" +#include "../TestBase.h" void waitToVerifyProcessor() { @@ -51,14 +50,8 @@ int main(int argc, char **argv) { mkdir("/tmp/aljs39/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); mkdir("content_repository", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - std::ostringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - logger->setLogLevel("debug"); + + LogTestController::getInstance().setDebug<core::ProcessGroup>(); std::shared_ptr<minifi::Configure> configuration = std::make_shared< minifi::Configure>(); @@ -105,10 +98,9 @@ int main(int argc, char **argv) { waitToVerifyProcessor(); controller->waitUnload(60000); - std::string logs = oss.str(); + std::string logs = LogTestController::getInstance().log_output.str(); assert(logs.find("Add processor SiteToSiteProvenanceReportingTask into process group MiNiFi Flow") != std::string::npos); - - + LogTestController::getInstance().reset(); rmdir("./content_repository"); rmdir("/tmp/aljs39/"); return 0; http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/integration/TestExecuteProcess.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/integration/TestExecuteProcess.cpp b/libminifi/test/integration/TestExecuteProcess.cpp index e947a46..c3a3f4c 100644 --- a/libminifi/test/integration/TestExecuteProcess.cpp +++ b/libminifi/test/integration/TestExecuteProcess.cpp @@ -16,6 +16,13 @@ * limitations under the License. */ + +#include <cassert> +#include <chrono> +#include <string> +#include <thread> +#include <type_traits> +#include <sys/stat.h> #include <uuid/uuid.h> #include <utility> #include <memory> @@ -24,8 +31,6 @@ #include "../unit/ProvenanceTestHelper.h" #include "FlowController.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" #include "processors/GetFile.h" #include "core/Core.h" #include "core/FlowFile.h" @@ -36,20 +41,10 @@ #include "core/ProcessContext.h" #include "core/ProcessSession.h" #include "core/ProcessorNode.h" +#include "../TestBase.h" int main(int argc, char **argv) { - std::ostringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - - outputLogger = std::unique_ptr<logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::NullAppender()); - logger->updateLogger(std::move(outputLogger)); - + TestController testController; std::shared_ptr<core::Processor> processor = std::make_shared< org::apache::nifi::minifi::processors::ExecuteProcess>("executeProcess"); processor->setMaxConcurrentTasks(1); @@ -118,9 +113,6 @@ int main(int argc, char **argv) { t.join(); }); - outputLogger = std::unique_ptr<logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::NullAppender()); - logger->updateLogger(std::move(outputLogger)); std::shared_ptr<org::apache::nifi::minifi::processors::ExecuteProcess> execp = std::static_pointer_cast< http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/unit/ClassLoaderTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/unit/ClassLoaderTests.cpp b/libminifi/test/unit/ClassLoaderTests.cpp index 7928832..e27c753 100644 --- a/libminifi/test/unit/ClassLoaderTests.cpp +++ b/libminifi/test/unit/ClassLoaderTests.cpp @@ -21,10 +21,10 @@ #include "io/ClientSocket.h" #include "core/Processor.h" #include "core/ClassLoader.h" -#include "processors/AppendHostInfo.h" -#include "core/logging/LogAppenders.h" +#include "core/yaml/YamlConfiguration.h" TEST_CASE("TestLoader", "[TestLoader]") { + TestController controller; REQUIRE( nullptr != core::ClassLoader::getDefaultClassLoader().instantiate( http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/unit/ControllerServiceTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/unit/ControllerServiceTests.cpp b/libminifi/test/unit/ControllerServiceTests.cpp index 508e37f..44d30d4 100644 --- a/libminifi/test/unit/ControllerServiceTests.cpp +++ b/libminifi/test/unit/ControllerServiceTests.cpp @@ -23,8 +23,6 @@ #include "FlowController.h" #include "../TestBase.h" #include "properties/Configure.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" #include "processors/GetFile.h" #include "core/Core.h" #include "Exception.h" @@ -35,6 +33,7 @@ #include "core/Processor.h" #include "core/controller/ControllerServiceMap.h" #include "core/controller/StandardControllerServiceNode.h" + namespace ControllerServiceTests { TEST_CASE("Test ControllerServicesMap", "[cs1]") { http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/unit/InvokeHTTPTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/unit/InvokeHTTPTests.cpp b/libminifi/test/unit/InvokeHTTPTests.cpp index 458a1c7..95b4a2e 100644 --- a/libminifi/test/unit/InvokeHTTPTests.cpp +++ b/libminifi/test/unit/InvokeHTTPTests.cpp @@ -26,8 +26,6 @@ #include <set> #include "FlowController.h" #include "../TestBase.h" -#include "core/logging/LogAppenders.h" -#include "core/logging/BaseLogger.h" #include "processors/GetFile.h" #include "core/Core.h" #include "../../include/core/FlowFile.h" @@ -38,17 +36,8 @@ #include "core/ProcessorNode.h" TEST_CASE("HTTPTestsPostNoResourceClaim", "[httptest1]") { - std::stringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - TestController testController; - - testController.enableDebug(); + LogTestController::getInstance().setInfo<org::apache::nifi::minifi::processors::InvokeHTTP>(); std::shared_ptr<TestRepository> repo = std::make_shared<TestRepository>(); @@ -149,25 +138,13 @@ TEST_CASE("HTTPTestsPostNoResourceClaim", "[httptest1]") { REQUIRE(provEventRecord->getComponentType() == processor->getName()); } std::shared_ptr<core::FlowFile> ffr = session2.get(); - std::string log_attribute_output = oss.str(); - std::cout << log_attribute_output << std::endl; - REQUIRE( - log_attribute_output.find("exiting because method is POST") - != std::string::npos); + REQUIRE(true == LogTestController::getInstance().contains("exiting because method is POST")); + LogTestController::getInstance().reset(); } TEST_CASE("HTTPTestsWithNoResourceClaimPOST", "[httptest1]") { - std::stringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - TestController testController; - - testController.enableDebug(); + LogTestController::getInstance().setInfo<org::apache::nifi::minifi::processors::InvokeHTTP>(); std::shared_ptr<TestRepository> repo = std::make_shared<TestRepository>(); @@ -279,10 +256,8 @@ TEST_CASE("HTTPTestsWithNoResourceClaimPOST", "[httptest1]") { REQUIRE(provEventRecord->getComponentType() == listenhttp->getName()); } std::shared_ptr<core::FlowFile> ffr = session2.get(); - std::string log_attribute_output = oss.str(); - REQUIRE( - log_attribute_output.find("exiting because method is POST") - != std::string::npos); + REQUIRE(true == LogTestController::getInstance().contains("exiting because method is POST")); + LogTestController::getInstance().reset(); } class CallBack : public minifi::OutputStreamCallback { @@ -298,19 +273,11 @@ class CallBack : public minifi::OutputStreamCallback { }; TEST_CASE("HTTPTestsWithResourceClaimPOST", "[httptest1]") { - std::stringstream oss; - std::unique_ptr<logging::BaseLogger> outputLogger = std::unique_ptr< - logging::BaseLogger>( - new org::apache::nifi::minifi::core::logging::OutputStreamAppender(oss, - 0)); - std::shared_ptr<logging::Logger> logger = logging::Logger::getLogger(); - logger->updateLogger(std::move(outputLogger)); - TestController testController; + LogTestController::getInstance().setInfo<org::apache::nifi::minifi::processors::InvokeHTTP>(); - testController.enableDebug(); - - std::shared_ptr<TestRepository> repo = std::make_shared<TestRepository>(); + std::shared_ptr<TestRepository> repo = std::make_shared< + TestRepository>(); std::shared_ptr<core::Processor> getfileprocessor = std::make_shared< org::apache::nifi::minifi::processors::GetFile>("getfileCreate2"); @@ -437,9 +404,7 @@ TEST_CASE("HTTPTestsWithResourceClaimPOST", "[httptest1]") { REQUIRE(provEventRecord->getComponentType() == listenhttp->getName()); } std::shared_ptr<core::FlowFile> ffr = session2.get(); - std::string log_attribute_output = oss.str(); - REQUIRE( - log_attribute_output.find("exiting because method is POST") - != std::string::npos); + REQUIRE(true == LogTestController::getInstance().contains("exiting because method is POST")); + LogTestController::getInstance().reset(); } http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/73ecc667/libminifi/test/unit/LoggerConfigurationTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/unit/LoggerConfigurationTests.cpp b/libminifi/test/unit/LoggerConfigurationTests.cpp new file mode 100644 index 0000000..7c340d1 --- /dev/null +++ b/libminifi/test/unit/LoggerConfigurationTests.cpp @@ -0,0 +1,99 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include <algorithm> +#include <memory> +#include <string> +#include <vector> + +#include "../TestBase.h" +#include "core/logging/LoggerConfiguration.h" +#include "spdlog/formatter.h" + +TEST_CASE("TestLoggerProperties::get_keys_of_type", "[test get_keys_of_type]") { + TestController test_controller; + LogTestController::getInstance().setDebug<logging::LoggerProperties>(); + logging::LoggerProperties logger_properties; + logger_properties.set("appender.rolling", "rolling"); + logger_properties.set("notappender.notrolling", "notrolling"); + logger_properties.set("appender.stdout", "stdout"); + logger_properties.set("appender.stdout2.ignore", "stdout"); + std::vector<std::string> expected = {"appender.rolling", "appender.stdout"}; + std::vector<std::string> actual = logger_properties.get_keys_of_type("appender"); + std::sort(actual.begin(), actual.end()); + REQUIRE(expected == actual); +} + +class TestLoggerConfiguration : public logging::LoggerConfiguration { + public: + static std::shared_ptr<logging::internal::LoggerNamespace> initialize_namespaces(const std::shared_ptr<logging::LoggerProperties> &logger_properties) { + return logging::LoggerConfiguration::initialize_namespaces(logger_properties); + } + static std::shared_ptr<spdlog::logger> get_logger(const std::shared_ptr<logging::internal::LoggerNamespace> &root_namespace, const std::string &name, std::shared_ptr<spdlog::formatter> formatter) { + return logging::LoggerConfiguration::get_logger(LogTestController::getInstance().logger_, root_namespace, name, formatter); + } +}; + +TEST_CASE("TestLoggerConfiguration::initialize_namespaces", "[test initialize_namespaces]") { + TestController test_controller; + LogTestController &logTestController = LogTestController::getInstance(); + LogTestController::getInstance().setDebug<logging::LoggerProperties>(); + std::shared_ptr<logging::LoggerProperties> logger_properties = std::make_shared<logging::LoggerProperties>(); + + std::ostringstream stdout; + std::ostringstream stderr; + logger_properties->add_sink("stdout", std::make_shared<spdlog::sinks::ostream_sink_mt>(stdout, true)); + logger_properties->add_sink("stderr", std::make_shared<spdlog::sinks::ostream_sink_mt>(stderr, true)); + + std::string stdout_only_warn_class = "org::apache::nifi::minifi::fake::test::StdoutOnlyWarn"; + std::string stderr_only_error_pkg = "org::apache::nifi::minifi::fake2"; + std::string stderr_only_error_class = stderr_only_error_pkg + "::test::StderrOnlyError"; + logger_properties->set("logger.root", "INFO,stdout,stderr"); + logger_properties->set("logger." + stdout_only_warn_class, "WARN,stdout"); + logger_properties->set("logger." + stderr_only_error_pkg, "ERROR,stderr"); + + std::shared_ptr<logging::internal::LoggerNamespace> root_namespace = TestLoggerConfiguration::initialize_namespaces(logger_properties); + + std::shared_ptr<spdlog::formatter> formatter = std::make_shared<spdlog::pattern_formatter>(logging::LoggerConfiguration::spdlog_default_pattern); + std::shared_ptr<spdlog::logger> logger = TestLoggerConfiguration::get_logger(root_namespace, "org::apache::nifi::minifi::fake::test::ClassName1", formatter); + std::string test_log_statement = "Test log statement"; + logger->info(test_log_statement); + REQUIRE(true == logTestController.contains(stdout, test_log_statement)); + REQUIRE(true == logTestController.contains(stderr, test_log_statement)); + logTestController.resetStream(stdout); + logTestController.resetStream(stderr); + + logger = TestLoggerConfiguration::get_logger(root_namespace, stdout_only_warn_class, formatter); + logger->info(test_log_statement); + REQUIRE(false == logTestController.contains(stdout, test_log_statement)); + logger->warn(test_log_statement); + REQUIRE(true == logTestController.contains(stdout, test_log_statement)); + REQUIRE(false == logTestController.contains(stderr, test_log_statement)); + logTestController.resetStream(stdout); + logTestController.resetStream(stderr); + + logger = TestLoggerConfiguration::get_logger(root_namespace, stderr_only_error_class, formatter); + logger->warn(test_log_statement); + REQUIRE(false == logTestController.contains(stderr, test_log_statement)); + logger->error(test_log_statement); + REQUIRE(false == logTestController.contains(stdout, test_log_statement)); + REQUIRE(true == logTestController.contains(stderr, test_log_statement)); + logTestController.resetStream(stdout); + logTestController.resetStream(stderr); +}
