This is an automated email from the ASF dual-hosted git repository. martinzink pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit d23e59615ffb64d1e09cd95c896939a814a011cd Author: Adam Debreceni <adebrec...@apache.org> AuthorDate: Tue Apr 18 21:16:33 2023 +0200 MINIFICPP-2105 - Validate ConsumeWindowsEventLogs output/json format Closes #1559 Signed-off-by: Martin Zink <martinz...@apache.org> --- .../windows-event-log/ConsumeWindowsEventLog.cpp | 93 ++++++++++------------ .../windows-event-log/ConsumeWindowsEventLog.h | 48 +++++------ extensions/windows-event-log/tests/CWELTestUtils.h | 4 +- .../tests/ConsumeWindowsEventLogTests.cpp | 17 ++-- 4 files changed, 69 insertions(+), 93 deletions(-) diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp index abf21def3..d37526c6c 100644 --- a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp +++ b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp @@ -51,6 +51,7 @@ #include "utils/gsl.h" #include "utils/OsUtils.h" +#include "utils/ProcessorConfigUtils.h" #pragma comment(lib, "wevtapi.lib") #pragma comment(lib, "ole32.lib") @@ -137,19 +138,19 @@ const core::Property ConsumeWindowsEventLog::EventHeader( "EVENTID,TASK_CATEGORY,LEVEL,KEYWORDS,USER,COMPUTER, and EVENT_TYPE. Eliminating fields will remove them from the header.")-> build()); -const core::Property ConsumeWindowsEventLog::OutputFormat( +const core::Property ConsumeWindowsEventLog::OutputFormatProperty( core::PropertyBuilder::createProperty("Output Format")-> isRequired(true)-> - withDefaultValue(Both)-> - withAllowableValues<std::string>({XML, Plaintext, Both, JSON})-> + withDefaultValue(toString(OutputFormat::BOTH))-> + withAllowableValues(OutputFormat::values())-> withDescription("Set the output format type. In case \'Both\' is selected the processor generates two flow files for every event captured in format XML and Plaintext")-> build()); -const core::Property ConsumeWindowsEventLog::JSONFormat( +const core::Property ConsumeWindowsEventLog::JsonFormatProperty( core::PropertyBuilder::createProperty("JSON Format")-> isRequired(true)-> - withDefaultValue(JSONSimple)-> - withAllowableValue<std::string>(JSONSimple)->withAllowableValue(JSONRaw)->withAllowableValue(JSONFlattened)-> + withDefaultValue(toString(JsonFormat::SIMPLE))-> + withAllowableValues(JsonFormat::values())-> withDescription("Set the json format type. Only applicable if Output Format is set to 'JSON'")-> build()); @@ -266,34 +267,10 @@ void ConsumeWindowsEventLog::onSchedule(const std::shared_ptr<core::ProcessConte regex_.emplace(*identifier_matcher); } - std::string mode; - context->getProperty(OutputFormat.getName(), mode); - - output_ = {}; - if (mode == XML) { - output_.xml = true; - } else if (mode == Plaintext) { - output_.plaintext = true; - } else if (mode == Both) { - output_.xml = true; - output_.plaintext = true; - } else if (mode == JSON) { - std::string json_format; - context->getProperty(JSONFormat.getName(), json_format); - if (json_format == JSONRaw) { - output_.json.type = JSONType::Raw; - } else if (json_format == JSONSimple) { - output_.json.type = JSONType::Simple; - } else if (json_format == JSONFlattened) { - output_.json.type = JSONType::Flattened; - } - } else { - // in the future this might be considered an error, but for now due to backwards - // compatibility we just fall through and execute the processor outputing nothing - // throw Exception(PROCESS_SCHEDULE_EXCEPTION, "Unrecognized output format: " + mode); - } + output_format_ = utils::parseEnumProperty<OutputFormat>(*context, OutputFormatProperty); + json_format_ = utils::parseEnumProperty<JsonFormat>(*context, JsonFormatProperty); - if ((output_.xml || output_.json) && !hMsobjsDll_) { + if (output_format_ != OutputFormat::PLAINTEXT && !hMsobjsDll_) { char systemDir[MAX_PATH]; if (GetSystemDirectory(systemDir, sizeof(systemDir))) { hMsobjsDll_ = LoadLibrary((systemDir + std::string("\\msobjs.dll")).c_str()); @@ -611,7 +588,7 @@ nonstd::expected<EventRender, std::string> ConsumeWindowsEventLog::createEventRe logger_->log_trace("Finish doc traversing, performing writing..."); - if (output_.plaintext) { + if (output_format_ == OutputFormat::PLAINTEXT || output_format_ == OutputFormat::BOTH) { logger_->log_trace("Writing event in plain text"); auto& handler = getEventLogHandler(provider_name); @@ -637,7 +614,7 @@ nonstd::expected<EventRender, std::string> ConsumeWindowsEventLog::createEventRe logger_->log_trace("Finish writing in plain text"); } - if (output_.xml || output_.json) { + if (output_format_ != OutputFormat::PLAINTEXT) { substituteXMLPercentageItems(doc); logger_->log_trace("Finish substituting %% in XML"); } @@ -646,7 +623,7 @@ nonstd::expected<EventRender, std::string> ConsumeWindowsEventLog::createEventRe result.matched_fields = walker.getFieldValues(); } - if (output_.xml) { + if (output_format_ == OutputFormat::XML || output_format_ == OutputFormat::BOTH) { logger_->log_trace("Writing event in XML"); wel::XmlString writer; @@ -657,18 +634,30 @@ nonstd::expected<EventRender, std::string> ConsumeWindowsEventLog::createEventRe logger_->log_trace("Finish writing in XML"); } - if (output_.json.type == JSONType::Raw) { - logger_->log_trace("Writing event in raw JSON"); - result.json = wel::jsonToString(wel::toRawJSON(doc)); - logger_->log_trace("Finish writing in raw JSON"); - } else if (output_.json.type == JSONType::Simple) { - logger_->log_trace("Writing event in simple JSON"); - result.json = wel::jsonToString(wel::toSimpleJSON(doc)); - logger_->log_trace("Finish writing in simple JSON"); - } else if (output_.json.type == JSONType::Flattened) { - logger_->log_trace("Writing event in flattened JSON"); - result.json = wel::jsonToString(wel::toFlattenedJSON(doc)); - logger_->log_trace("Finish writing in flattened JSON"); + if (output_format_ == OutputFormat::JSON) { + switch (json_format_.value()) { + case JsonFormat::RAW: { + logger_->log_trace("Writing event in raw JSON"); + result.json = wel::jsonToString(wel::toRawJSON(doc)); + logger_->log_trace("Finish writing in raw JSON"); + break; + } + case JsonFormat::SIMPLE: { + logger_->log_trace("Writing event in simple JSON"); + result.json = wel::jsonToString(wel::toSimpleJSON(doc)); + logger_->log_trace("Finish writing in simple JSON"); + break; + } + case JsonFormat::FLATTENED: { + logger_->log_trace("Writing event in flattened JSON"); + result.json = wel::jsonToString(wel::toFlattenedJSON(doc)); + logger_->log_trace("Finish writing in flattened JSON"); + break; + } + default: { + gsl_Assert(false); + } + } } return result; @@ -721,18 +710,18 @@ void ConsumeWindowsEventLog::putEventRenderFlowFileToSession(const EventRender& session.transfer(flow_file, Success); }; - if (output_.xml) { + if (output_format_ == OutputFormat::XML || output_format_ == OutputFormat::BOTH) { logger_->log_trace("Writing rendered XML to a flow file"); commitFlowFile(eventRender.xml, "application/xml"); } - if (output_.plaintext) { + if (output_format_ == OutputFormat::PLAINTEXT || output_format_ == OutputFormat::BOTH) { logger_->log_trace("Writing rendered plain text to a flow file"); commitFlowFile(eventRender.plaintext, "text/plain"); } - if (output_.json) { - logger_->log_trace("Writing rendered %s JSON to a flow file", output_.json.type.toString()); + if (output_format_ == OutputFormat::JSON) { + logger_->log_trace("Writing rendered %s JSON to a flow file", json_format_.toString()); commitFlowFile(eventRender.json, "application/json"); } } diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.h b/extensions/windows-event-log/ConsumeWindowsEventLog.h index 5a3a5b908..85c3db70f 100644 --- a/extensions/windows-event-log/ConsumeWindowsEventLog.h +++ b/extensions/windows-event-log/ConsumeWindowsEventLog.h @@ -74,8 +74,8 @@ class ConsumeWindowsEventLog : public core::Processor { EXTENSIONAPI static const core::Property ResolveAsAttributes; EXTENSIONAPI static const core::Property EventHeaderDelimiter; EXTENSIONAPI static const core::Property EventHeader; - EXTENSIONAPI static const core::Property OutputFormat; - EXTENSIONAPI static const core::Property JSONFormat; + EXTENSIONAPI static const core::Property OutputFormatProperty; + EXTENSIONAPI static const core::Property JsonFormatProperty; EXTENSIONAPI static const core::Property BatchCommitSize; EXTENSIONAPI static const core::Property BookmarkRootDirectory; EXTENSIONAPI static const core::Property ProcessOldEvents; @@ -91,8 +91,8 @@ class ConsumeWindowsEventLog : public core::Processor { ResolveAsAttributes, EventHeaderDelimiter, EventHeader, - OutputFormat, - JSONFormat, + OutputFormatProperty, + JsonFormatProperty, BatchCommitSize, BookmarkRootDirectory, ProcessOldEvents, @@ -127,14 +127,6 @@ class ConsumeWindowsEventLog : public core::Processor { nonstd::expected<std::string, std::string> renderEventAsXml(EVT_HANDLE event_handle); - static constexpr const char* XML = "XML"; - static constexpr const char* Both = "Both"; - static constexpr const char* Plaintext = "Plaintext"; - static constexpr const char* JSON = "JSON"; - static constexpr const char* JSONRaw = "Raw"; - static constexpr const char* JSONSimple = "Simple"; - static constexpr const char* JSONFlattened = "Flattened"; - struct TimeDiff { auto operator()() const { return int64_t{ std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - time_).count() }; @@ -167,23 +159,21 @@ class ConsumeWindowsEventLog : public core::Processor { uint64_t batch_commit_size_{}; bool cache_sid_lookups_ = true; - SMART_ENUM(JSONType, - (None, "None"), - (Raw, "Raw"), - (Simple, "Simple"), - (Flattened, "Flattened")) - - struct OutputFormat { - bool xml{false}; - bool plaintext{false}; - struct JSON { - JSONType type{JSONType::None}; - - explicit operator bool() const noexcept { - return type != JSONType::None; - } - } json; - } output_; + SMART_ENUM(OutputFormat, + (XML, "XML"), + (BOTH, "Both"), + (PLAINTEXT, "Plaintext"), + (JSON, "JSON") + ) + + SMART_ENUM(JsonFormat, + (RAW, "Raw"), + (SIMPLE, "Simple"), + (FLATTENED, "Flattened") + ) + + OutputFormat output_format_; + JsonFormat json_format_; std::unique_ptr<Bookmark> bookmark_; std::mutex on_trigger_mutex_; diff --git a/extensions/windows-event-log/tests/CWELTestUtils.h b/extensions/windows-event-log/tests/CWELTestUtils.h index efe240141..e576c5b2c 100644 --- a/extensions/windows-event-log/tests/CWELTestUtils.h +++ b/extensions/windows-event-log/tests/CWELTestUtils.h @@ -52,9 +52,9 @@ class OutputFormatTestController : public TestController { auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", "cwel"); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Channel.getName(), channel_); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Query.getName(), query_); - test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), output_format_); + test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), output_format_); if (json_format_) { - test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::JSONFormat.getName(), json_format_.value()); + test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::JsonFormatProperty.getName(), json_format_.value()); } auto dir = createTempDirectory(); diff --git a/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp b/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp index 4a309986d..d91174419 100644 --- a/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp +++ b/extensions/windows-event-log/tests/ConsumeWindowsEventLogTests.cpp @@ -95,7 +95,7 @@ TEST_CASE("ConsumeWindowsEventLog properties work with default values", "[create ConsumeWindowsEventLog::IdentifierFunction, ConsumeWindowsEventLog::ResolveAsAttributes, ConsumeWindowsEventLog::EventHeader, - ConsumeWindowsEventLog::OutputFormat, + ConsumeWindowsEventLog::OutputFormatProperty, ConsumeWindowsEventLog::BatchCommitSize, ConsumeWindowsEventLog::BookmarkRootDirectory, // TODO(fgerlits): obsolete, see definition; remove in a later release ConsumeWindowsEventLog::ProcessOldEvents, @@ -241,15 +241,15 @@ TEST_CASE("ConsumeWindowsEventLog extracts some attributes by default", "[onTrig test_plan->setProperty(logger_processor, LogAttribute::FlowFilesToLog.getName(), "0"); SECTION("XML output") { - REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), "XML")); + REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), "XML")); } SECTION("Json output") { - REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), "JSON")); + REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), "JSON")); } SECTION("Plaintext output") { - REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), "Plaintext")); + REQUIRE(test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), "Plaintext")); } // 0th event, only to create a bookmark @@ -297,7 +297,7 @@ void outputFormatSetterTestHelper(const std::string &output_format, int expected auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", "cwel"); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Channel.getName(), APPLICATION_CHANNEL); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Query.getName(), QUERY); - test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), output_format); + test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), output_format); auto logger_processor = test_plan->addProcessor("LogAttribute", "logger", Success, true); test_plan->setProperty(logger_processor, LogAttribute::FlowFilesToLog.getName(), "0"); @@ -326,10 +326,7 @@ TEST_CASE("ConsumeWindowsEventLog output format can be set", "[create][output_fo outputFormatSetterTestHelper("XML", 1); outputFormatSetterTestHelper("Plaintext", 1); outputFormatSetterTestHelper("Both", 2); - - // NOTE(fgerlits): this may be a bug, as I would expect this to throw in onSchedule(), - // but it starts merrily, just does not write flow files in either format - outputFormatSetterTestHelper("InvalidValue", 0); + REQUIRE_THROWS(outputFormatSetterTestHelper("InvalidValue", 0)); } TEST_CASE("ConsumeWindowsEventLog prints events in plain text correctly", "[onTrigger]") { @@ -433,7 +430,7 @@ void batchCommitSizeTestHelper(std::size_t num_events_read, std::size_t batch_co auto cwel_processor = test_plan->addProcessor("ConsumeWindowsEventLog", "cwel"); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Channel.getName(), APPLICATION_CHANNEL); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::Query.getName(), QUERY); - test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormat.getName(), "XML"); + test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::OutputFormatProperty.getName(), "XML"); test_plan->setProperty(cwel_processor, ConsumeWindowsEventLog::BatchCommitSize.getName(), std::to_string(batch_commit_size)); {