You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ad...@apache.org on 2021/12/10 12:24:36 UTC
[nifi-minifi-cpp] branch main updated: MINIFICPP-1694 Change unnecessary errors to warnings
This is an automated email from the ASF dual-hosted git repository.
adebreceni pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new f9d8834 MINIFICPP-1694 Change unnecessary errors to warnings
f9d8834 is described below
commit f9d8834f2d5334d438be02d7eea4dc0cee3f8d69
Author: Gabor Gyimesi <ga...@gmail.com>
AuthorDate: Fri Dec 10 13:23:05 2021 +0100
MINIFICPP-1694 Change unnecessary errors to warnings
Signed-off-by: Adam Debreceni <ad...@apache.org>
This closes #1220
---
.../RocksDbPersistableKeyValueStoreService.cpp | 6 ++-
libminifi/include/core/yaml/CheckRequiredField.h | 22 +++++---
libminifi/src/core/yaml/CheckRequiredField.cpp | 61 +++++++++++++++-------
libminifi/src/core/yaml/YamlConfiguration.cpp | 48 ++++++-----------
libminifi/src/core/yaml/YamlConnectionParser.cpp | 4 +-
libminifi/src/properties/Properties.cpp | 4 ++
6 files changed, 82 insertions(+), 63 deletions(-)
diff --git a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
index eb8e1c5..95d6991 100644
--- a/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
+++ b/extensions/rocksdb-repos/controllers/RocksDbPersistableKeyValueStoreService.cpp
@@ -127,7 +127,11 @@ bool RocksDbPersistableKeyValueStoreService::get(const std::string& key, std::st
}
rocksdb::Status status = opendb->Get(rocksdb::ReadOptions(), key, &value);
if (!status.ok()) {
- logger_->log_error("Failed to Get key %s from RocksDB database at %s, error: %s", key.c_str(), directory_.c_str(), status.getState());
+ if (status.getState() != nullptr) {
+ logger_->log_error("Failed to Get key %s from RocksDB database at %s, error: %s", key.c_str(), directory_.c_str(), status.getState());
+ } else {
+ logger_->log_warn("Failed to Get key %s from RocksDB database at %s (it may not have been initialized yet)", key.c_str(), directory_.c_str());
+ }
return false;
}
return true;
diff --git a/libminifi/include/core/yaml/CheckRequiredField.h b/libminifi/include/core/yaml/CheckRequiredField.h
index 7029166..e6e1b50 100644
--- a/libminifi/include/core/yaml/CheckRequiredField.h
+++ b/libminifi/include/core/yaml/CheckRequiredField.h
@@ -19,6 +19,7 @@
#include <string>
#include <memory>
+#include <vector>
#include "core/logging/LoggerConfiguration.h"
#include "yaml-cpp/yaml.h"
@@ -30,26 +31,31 @@ namespace minifi {
namespace core {
namespace yaml {
+bool isFieldPresent(const YAML::Node &yaml_node, std::string_view field_name);
+std::string buildErrorMessage(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_field_names, std::string_view yaml_section = "");
+
/**
* This is a helper function for verifying the existence of a required
* field in a YAML::Node object. If the field is not present, an error
* message will be logged and an std::invalid_argument exception will be
* thrown indicating the absence of the required field in the YAML node.
*
- * @param yamlNode the YAML node to check
- * @param fieldName the required field key
- * @param yamlSection [optional] the top level section of the YAML config
- * for the yamlNode. This is used for generating a
+ * @param yaml_node the YAML node to check
+ * @param field_name the required field key
+ * @param yaml_section [optional] the top level section of the YAML config
+ * for the yaml_node. This is used for generating a
* useful error message for troubleshooting.
- * @param errorMessage [optional] the error message string to use if
+ * @param error_message [optional] the error message string to use if
* the required field is missing. If not provided,
* a default error message will be generated.
*
- * @throws std::invalid_argument if the required field 'fieldName' is
- * not present in 'yamlNode'
+ * @throws std::invalid_argument if the required field 'field_name' is
+ * not present in 'yaml_node'
*/
void checkRequiredField(
- const YAML::Node *yamlNode, const std::string &fieldName, const std::shared_ptr<logging::Logger>& logger, const std::string &yamlSection = "", const std::string &errorMessage = "");
+ const YAML::Node &yaml_node, std::string_view field_name, std::string_view yaml_section = "", std::string error_message = "");
+
+std::string getRequiredField(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_names, std::string_view yaml_section, std::string error_message = {});
} // namespace yaml
} // namespace core
diff --git a/libminifi/src/core/yaml/CheckRequiredField.cpp b/libminifi/src/core/yaml/CheckRequiredField.cpp
index 9ea47d7..493e301 100644
--- a/libminifi/src/core/yaml/CheckRequiredField.cpp
+++ b/libminifi/src/core/yaml/CheckRequiredField.cpp
@@ -19,6 +19,7 @@
#include <stdexcept>
#include "core/yaml/CheckRequiredField.h"
+#include "utils/StringUtils.h"
namespace org {
namespace apache {
@@ -27,28 +28,48 @@ namespace minifi {
namespace core {
namespace yaml {
-void checkRequiredField(const YAML::Node *yamlNode, const std::string &fieldName, const std::shared_ptr<logging::Logger>& logger, const std::string &yamlSection, const std::string &errorMessage) {
- std::string errMsg = errorMessage;
- if (!yamlNode->as<YAML::Node>()[fieldName]) {
- if (errMsg.empty()) {
- const YAML::Node name_node = yamlNode->as<YAML::Node>()["name"];
- // Build a helpful error message for the user so they can fix the
- // invalid YAML config file, using the component name if present
- errMsg =
- name_node ?
- "Unable to parse configuration file for component named '" + name_node.as<std::string>() + "' as required field '" + fieldName + "' is missing" :
- "Unable to parse configuration file as required field '" + fieldName + "' is missing";
- if (!yamlSection.empty()) {
- errMsg += " [in '" + yamlSection + "' section of configuration file]";
- }
- const YAML::Mark mark = yamlNode->Mark();
- if (!mark.is_null()) {
- errMsg += " [line:column, pos at " + std::to_string(mark.line) + ":" + std::to_string(mark.column) + ", " + std::to_string(mark.pos) + "]";
- }
+bool isFieldPresent(const YAML::Node &yaml_node, std::string_view field_name) {
+ return bool{yaml_node.as<YAML::Node>()[field_name.data()]};
+}
+
+std::string buildErrorMessage(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_field_names, std::string_view yaml_section) {
+ const YAML::Node name_node = yaml_node.as<YAML::Node>()["name"];
+ // Build a helpful error message for the user so they can fix the
+ // invalid YAML config file, using the component name if present
+ auto field_list_string = utils::StringUtils::join(", ", alternate_field_names);
+ std::string err_msg =
+ name_node ?
+ "Unable to parse configuration file for component named '" + name_node.as<std::string>() + "' as none of the possible required fields [" + field_list_string + "] is available" :
+ "Unable to parse configuration file as none of the possible required fields [" + field_list_string + "] is available";
+ if (!yaml_section.empty()) {
+ err_msg += " [in '" + std::string(yaml_section) + "' section of configuration file]";
+ }
+ const YAML::Mark mark = yaml_node.Mark();
+ if (!mark.is_null()) {
+ err_msg += " [line:column, pos at " + std::to_string(mark.line) + ":" + std::to_string(mark.column) + ", " + std::to_string(mark.pos) + "]";
+ }
+ return err_msg;
+}
+
+void checkRequiredField(const YAML::Node &yaml_node, std::string_view field_name, std::string_view yaml_section, std::string error_message) {
+ if (!isFieldPresent(yaml_node, field_name)) {
+ if (error_message.empty()) {
+ error_message = buildErrorMessage(yaml_node, std::vector<std::string>{std::string(field_name)}, yaml_section);
}
- logger->log_error(errMsg.c_str());
- throw std::invalid_argument(errMsg);
+ throw std::invalid_argument(error_message);
+ }
+}
+
+std::string getRequiredField(const YAML::Node &yaml_node, const std::vector<std::string> &alternate_names, std::string_view yaml_section, std::string error_message) {
+ for (const auto& name : alternate_names) {
+ if (yaml::isFieldPresent(yaml_node, name)) {
+ return yaml_node[name].as<std::string>();
+ }
+ }
+ if (error_message.empty()) {
+ error_message = buildErrorMessage(yaml_node, alternate_names, yaml_section);
}
+ throw std::invalid_argument(error_message);
}
} // namespace yaml
diff --git a/libminifi/src/core/yaml/YamlConfiguration.cpp b/libminifi/src/core/yaml/YamlConfiguration.cpp
index dbc8df2..a251b0f 100644
--- a/libminifi/src/core/yaml/YamlConfiguration.cpp
+++ b/libminifi/src/core/yaml/YamlConfiguration.cpp
@@ -58,8 +58,7 @@ std::unique_ptr<core::ProcessGroup> YamlConfiguration::parseRootProcessGroupYaml
std::unique_ptr<core::ProcessGroup> YamlConfiguration::createProcessGroup(const YAML::Node& yamlNode, bool is_root) {
int version = 0;
- yaml::checkRequiredField(&yamlNode, "name", logger_,
- CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+ yaml::checkRequiredField(yamlNode, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
std::string flowName = yamlNode["name"].as<std::string>();
utils::Identifier uuid;
@@ -170,14 +169,13 @@ void YamlConfiguration::parseProcessorNodeYaml(const YAML::Node& processorsNode,
core::ProcessorConfig procCfg;
YAML::Node procNode = iter->as<YAML::Node>();
- yaml::checkRequiredField(&procNode, "name", logger_,
- CONFIG_YAML_PROCESSORS_KEY);
+ yaml::checkRequiredField(procNode, "name", CONFIG_YAML_PROCESSORS_KEY);
procCfg.name = procNode["name"].as<std::string>();
procCfg.id = getOrGenerateId(procNode);
uuid = procCfg.id.c_str();
logger_->log_debug("parseProcessorNode: name => [%s] id => [%s]", procCfg.name, procCfg.id);
- yaml::checkRequiredField(&procNode, "class", logger_, CONFIG_YAML_PROCESSORS_KEY);
+ yaml::checkRequiredField(procNode, "class", CONFIG_YAML_PROCESSORS_KEY);
procCfg.javaClass = procNode["class"].as<std::string>();
logger_->log_debug("parseProcessorNode: class => [%s]", procCfg.javaClass);
@@ -327,8 +325,7 @@ void YamlConfiguration::parseRemoteProcessGroupYaml(const YAML::Node& rpgNode, c
for (YAML::const_iterator iter = rpgNode.begin(); iter != rpgNode.end(); ++iter) {
YAML::Node currRpgNode = iter->as<YAML::Node>();
- yaml::checkRequiredField(&currRpgNode, "name", logger_,
- CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+ yaml::checkRequiredField(currRpgNode, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
auto name = currRpgNode["name"].as<std::string>();
id = getOrGenerateId(currRpgNode);
@@ -413,8 +410,7 @@ void YamlConfiguration::parseRemoteProcessGroupYaml(const YAML::Node& rpgNode, c
group->setTransmitting(true);
group->setURL(url);
- yaml::checkRequiredField(&currRpgNode, "Input Ports", logger_,
- CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+ yaml::checkRequiredField(currRpgNode, "Input Ports", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
YAML::Node inputPorts = currRpgNode["Input Ports"].as<YAML::Node>();
if (inputPorts && inputPorts.IsSequence()) {
for (YAML::const_iterator portIter = inputPorts.begin(); portIter != inputPorts.end(); ++portIter) {
@@ -457,11 +453,9 @@ void YamlConfiguration::parseProvenanceReportingYaml(const YAML::Node& reportNod
YAML::Node node = reportNode.as<YAML::Node>();
- yaml::checkRequiredField(&node, "scheduling strategy", logger_,
- CONFIG_YAML_PROVENANCE_REPORT_KEY);
+ yaml::checkRequiredField(node, "scheduling strategy", CONFIG_YAML_PROVENANCE_REPORT_KEY);
auto schedulingStrategyStr = node["scheduling strategy"].as<std::string>();
- yaml::checkRequiredField(&node, "scheduling period", logger_,
- CONFIG_YAML_PROVENANCE_REPORT_KEY);
+ yaml::checkRequiredField(node, "scheduling period", CONFIG_YAML_PROVENANCE_REPORT_KEY);
auto schedulingPeriodStr = node["scheduling period"].as<std::string>();
core::TimeUnit unit;
@@ -496,9 +490,9 @@ void YamlConfiguration::parseProvenanceReportingYaml(const YAML::Node& reportNod
logger_->log_debug("ProvenanceReportingTask URL %s", urlStr);
}
}
- yaml::checkRequiredField(&node, "port uuid", logger_, CONFIG_YAML_PROVENANCE_REPORT_KEY);
+ yaml::checkRequiredField(node, "port uuid", CONFIG_YAML_PROVENANCE_REPORT_KEY);
auto portUUIDStr = node["port uuid"].as<std::string>();
- yaml::checkRequiredField(&node, "batch size", logger_, CONFIG_YAML_PROVENANCE_REPORT_KEY);
+ yaml::checkRequiredField(node, "batch size", CONFIG_YAML_PROVENANCE_REPORT_KEY);
auto batchSizeStr = node["batch size"].as<std::string>();
logger_->log_debug("ProvenanceReportingTask port uuid %s", portUUIDStr);
@@ -523,20 +517,12 @@ void YamlConfiguration::parseControllerServices(const YAML::Node& controllerServ
for (const auto& iter : controllerServicesNode) {
YAML::Node controllerServiceNode = iter.as<YAML::Node>();
try {
- yaml::checkRequiredField(&controllerServiceNode, "name", logger_,
- CONFIG_YAML_CONTROLLER_SERVICES_KEY);
- yaml::checkRequiredField(&controllerServiceNode, "id", logger_,
- CONFIG_YAML_CONTROLLER_SERVICES_KEY);
- std::string type = "";
+ yaml::checkRequiredField(controllerServiceNode, "name", CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+ yaml::checkRequiredField(controllerServiceNode, "id", CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+
+ auto type = yaml::getRequiredField(controllerServiceNode, std::vector<std::string>{"class", "type"}, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
+ logger_->log_debug("Using type %s for controller service node", type);
- try {
- yaml::checkRequiredField(&controllerServiceNode, "class", logger_, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
- type = controllerServiceNode["class"].as<std::string>();
- } catch (const std::invalid_argument &) {
- yaml::checkRequiredField(&controllerServiceNode, "type", logger_, CONFIG_YAML_CONTROLLER_SERVICES_KEY);
- type = controllerServiceNode["type"].as<std::string>();
- logger_->log_debug("Using type %s for controller service node", type);
- }
std::string fullType = type;
auto lastOfIdx = type.find_last_of(".");
if (lastOfIdx != std::string::npos) {
@@ -625,11 +611,9 @@ void YamlConfiguration::parsePortYaml(const YAML::Node& portNode, core::ProcessG
YAML::Node inputPortsObj = portNode.as<YAML::Node>();
// Check for required fields
- yaml::checkRequiredField(&inputPortsObj, "name", logger_,
- CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
+ yaml::checkRequiredField(inputPortsObj, "name", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY);
auto nameStr = inputPortsObj["name"].as<std::string>();
- yaml::checkRequiredField(&inputPortsObj, "id", logger_,
- CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY,
+ yaml::checkRequiredField(inputPortsObj, "id", CONFIG_YAML_REMOTE_PROCESS_GROUP_KEY,
"The field 'id' is required for "
"the port named '" + nameStr + "' in the YAML Config. If this port "
"is an input port for a NiFi Remote Process Group, the port "
diff --git a/libminifi/src/core/yaml/YamlConnectionParser.cpp b/libminifi/src/core/yaml/YamlConnectionParser.cpp
index b8434d5..b434d9d 100644
--- a/libminifi/src/core/yaml/YamlConnectionParser.cpp
+++ b/libminifi/src/core/yaml/YamlConnectionParser.cpp
@@ -114,7 +114,7 @@ utils::Identifier YamlConnectionParser::getSourceUUIDFromYaml() const {
throw std::invalid_argument("Invalid source id");
}
// if we don't have a source id, try to resolve using source name. config schema v2 will make this unnecessary
- checkRequiredField(&connectionNode_, "source name", logger_, CONFIG_YAML_CONNECTIONS_KEY);
+ checkRequiredField(connectionNode_, "source name", CONFIG_YAML_CONNECTIONS_KEY);
const auto connectionSrcProcName = connectionNode_["source name"].as<std::string>();
const auto srcUUID = utils::Identifier::parse(connectionSrcProcName);
if (srcUUID && parent_->findProcessorById(srcUUID.value(), ProcessGroup::Traverse::ExcludeChildren)) {
@@ -147,7 +147,7 @@ utils::Identifier YamlConnectionParser::getDestinationUUIDFromYaml() const {
}
// we use the same logic as above for resolving the source processor
// for looking up the destination processor in absence of a processor id
- checkRequiredField(&connectionNode_, "destination name", logger_, CONFIG_YAML_CONNECTIONS_KEY);
+ checkRequiredField(connectionNode_, "destination name", CONFIG_YAML_CONNECTIONS_KEY);
std::string connectionDestProcName = connectionNode_["destination name"].as<std::string>();
const auto destUUID = utils::Identifier::parse(connectionDestProcName);
if (destUUID && parent_->findProcessorById(destUUID.value(), ProcessGroup::Traverse::ExcludeChildren)) {
diff --git a/libminifi/src/properties/Properties.cpp b/libminifi/src/properties/Properties.cpp
index 061afed..02b2378 100644
--- a/libminifi/src/properties/Properties.cpp
+++ b/libminifi/src/properties/Properties.cpp
@@ -76,6 +76,10 @@ void Properties::loadConfigureFile(const char *fileName) {
}
properties_file_ = utils::file::getFullPath(utils::file::FileUtils::concat_path(getHome(), fileName));
+ if (properties_file_.empty()) {
+ logger_->log_warn("Configuration file '%s' does not exist, so it could not be loaded.", fileName);
+ return;
+ }
logger_->log_info("Using configuration file to load configuration for %s from %s (located at %s)",
getName().c_str(), fileName, properties_file_);