Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MINIFICPP-2494 windows event log: fix event message formatting, refactor #1900

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions extensions/windows-event-log/ConsumeWindowsEventLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ void ConsumeWindowsEventLog::initialize() {
}

bool ConsumeWindowsEventLog::insertHeaderName(wel::METADATA_NAMES &header, const std::string &key, const std::string & value) {
wel::METADATA name = wel::WindowsEventLogMetadata::getMetadataFromString(key);
wel::Metadata name = wel::WindowsEventLogMetadata::getMetadataFromString(key);

if (name != wel::METADATA::UNKNOWN) {
if (name != wel::Metadata::UNKNOWN) {
header.emplace_back(std::make_pair(name, value));
return true;
}
Expand Down Expand Up @@ -488,7 +488,7 @@ nonstd::expected<cwel::EventRender, std::string> ConsumeWindowsEventLog::createE
std::string_view payload_name = event_message ? "Message" : "Error";

wel::WindowsEventLogHeader log_header(header_names_, header_delimiter_, payload_name.size());
result.plaintext = log_header.getEventHeader([&walker](wel::METADATA metadata) { return walker.getMetadata(metadata); });
result.plaintext = log_header.getEventHeader([&walker](wel::Metadata metadata) { return walker.getMetadata(metadata); });
result.plaintext += payload_name;
result.plaintext += log_header.getDelimiterFor(payload_name.size());
result.plaintext += event_message.has_value() ? *event_message : event_message.error().message();
Expand Down
114 changes: 57 additions & 57 deletions extensions/windows-event-log/tests/MetadataWalkerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "wel/XMLString.h"
#include "pugixml.hpp"

using METADATA = org::apache::nifi::minifi::wel::METADATA;
using Metadata = org::apache::nifi::minifi::wel::Metadata;
using MetadataWalker = org::apache::nifi::minifi::wel::MetadataWalker;
using WindowsEventLogMetadata = org::apache::nifi::minifi::wel::WindowsEventLogMetadata;
using WindowsEventLogMetadataImpl = org::apache::nifi::minifi::wel::WindowsEventLogMetadataImpl;
Expand Down Expand Up @@ -74,7 +74,7 @@ const short event_type_index = 178; // NOLINT short comes from WINDOWS API

class FakeWindowsEventLogMetadata : public WindowsEventLogMetadata {
public:
[[nodiscard]] std::string getEventData(EVT_FORMAT_MESSAGE_FLAGS flags) const override { return "event_data_for_flag_" + std::to_string(flags); }
[[nodiscard]] nonstd::expected<std::string, std::error_code> getEventData(EVT_FORMAT_MESSAGE_FLAGS flags) const noexcept override { return "event_data_for_flag_" + std::to_string(flags); }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this to noexcept. There are allocations here. If they fail, the test will terminate and report failure, which is an acceptable behavior IMO.

[[nodiscard]] std::string getEventTimestamp() const override { return "event_timestamp"; }
short getEventTypeIndex() const override { return event_type_index; } // NOLINT short comes from WINDOWS API
};
Expand Down Expand Up @@ -149,7 +149,7 @@ void extractMappingsTestHelper(const std::string &file_name,
bool update_xml,
bool resolve,
const std::map<std::string, std::string>& expected_identifiers,
const std::map<METADATA, std::string>& expected_metadata,
const std::map<Metadata, std::string>& expected_metadata,
const std::map<std::string, std::string>& expected_field_values) {
std::string input_xml = readFile(file_name);
REQUIRE(!input_xml.empty());
Expand All @@ -175,12 +175,12 @@ TEST_CASE("MetadataWalker extracts mappings correctly when there is a single Sid

const std::map<std::string, std::string> expected_identifiers{{"S-1-0-0", "S-1-0-0"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::EVENT_RECORDID, "2575952"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::EVENT_RECORDID, "2575952"}};

const std::map<std::string, std::string> expected_field_values{};

Expand All @@ -198,18 +198,18 @@ TEST_CASE("MetadataWalker extracts mappings correctly when there is a single Sid

const std::map<std::string, std::string> expected_identifiers{{"S-1-0-0", "Nobody"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::LOG_NAME, "MetadataWalkerTests"},
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::OPCODE, "event_data_for_flag_4"},
{METADATA::EVENT_RECORDID, "2575952"},
{METADATA::EVENT_TYPE, "178"},
{METADATA::TASK_CATEGORY, "event_data_for_flag_3"},
{METADATA::LEVEL, "event_data_for_flag_2"},
{METADATA::KEYWORDS, "event_data_for_flag_5"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::LOG_NAME, "MetadataWalkerTests"},
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::OPCODE, "event_data_for_flag_4"},
{Metadata::EVENT_RECORDID, "2575952"},
{Metadata::EVENT_TYPE, "178"},
{Metadata::TASK_CATEGORY, "event_data_for_flag_3"},
{Metadata::LEVEL, "event_data_for_flag_2"},
{Metadata::KEYWORDS, "event_data_for_flag_5"}};

SECTION("update_xml is false => fields are collected into walker.getFieldValues()") {
const std::map<std::string, std::string> expected_field_values{
Expand All @@ -235,12 +235,12 @@ TEST_CASE("MetadataWalker extracts mappings correctly when there are multiple Si

const std::map<std::string, std::string> expected_identifiers{{"S-1-0-0", "S-1-0-0"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::EVENT_RECORDID, "2575952"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::EVENT_RECORDID, "2575952"}};

const std::map<std::string, std::string> expected_field_values{};

Expand All @@ -264,18 +264,18 @@ TEST_CASE("MetadataWalker extracts mappings correctly when there are multiple Si
{"S-1-0-0", "Nobody"},
{"S-1-1-0", "Everyone"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::LOG_NAME, "MetadataWalkerTests"},
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::OPCODE, "event_data_for_flag_4"},
{METADATA::EVENT_RECORDID, "2575952"},
{METADATA::EVENT_TYPE, "178"},
{METADATA::TASK_CATEGORY, "event_data_for_flag_3"},
{METADATA::LEVEL, "event_data_for_flag_2"},
{METADATA::KEYWORDS, "event_data_for_flag_5"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::LOG_NAME, "MetadataWalkerTests"},
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::OPCODE, "event_data_for_flag_4"},
{Metadata::EVENT_RECORDID, "2575952"},
{Metadata::EVENT_TYPE, "178"},
{Metadata::TASK_CATEGORY, "event_data_for_flag_3"},
{Metadata::LEVEL, "event_data_for_flag_2"},
{Metadata::KEYWORDS, "event_data_for_flag_5"}};

SECTION("update_xml is false => fields are collected into walker.getFieldValues()") {
const std::map<std::string, std::string> expected_field_values{
Expand All @@ -301,12 +301,12 @@ TEST_CASE("MetadataWalker extracts mappings correctly when the Sid is unknown an

const std::map<std::string, std::string> expected_identifiers{{"S-1-8-6-5-3-0-9", "S-1-8-6-5-3-0-9"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::EVENT_RECORDID, "2575952"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::EVENT_RECORDID, "2575952"}};

const std::map<std::string, std::string> expected_field_values{};

Expand All @@ -324,18 +324,18 @@ TEST_CASE("MetadataWalker extracts mappings correctly when the Sid is unknown an

const std::map<std::string, std::string> expected_identifiers{{"S-1-8-6-5-3-0-9", "S-1-8-6-5-3-0-9"}};

using org::apache::nifi::minifi::wel::METADATA;
const std::map<METADATA, std::string> expected_metadata{
{METADATA::LOG_NAME, "MetadataWalkerTests"},
{METADATA::SOURCE, "Microsoft-Windows-Security-Auditing"},
{METADATA::TIME_CREATED, "event_timestamp"},
{METADATA::EVENTID, "4672"},
{METADATA::OPCODE, "event_data_for_flag_4"},
{METADATA::EVENT_RECORDID, "2575952"},
{METADATA::EVENT_TYPE, "178"},
{METADATA::TASK_CATEGORY, "event_data_for_flag_3"},
{METADATA::LEVEL, "event_data_for_flag_2"},
{METADATA::KEYWORDS, "event_data_for_flag_5"}};
using org::apache::nifi::minifi::wel::Metadata;
const std::map<Metadata, std::string> expected_metadata{
{Metadata::LOG_NAME, "MetadataWalkerTests"},
{Metadata::SOURCE, "Microsoft-Windows-Security-Auditing"},
{Metadata::TIME_CREATED, "event_timestamp"},
{Metadata::EVENTID, "4672"},
{Metadata::OPCODE, "event_data_for_flag_4"},
{Metadata::EVENT_RECORDID, "2575952"},
{Metadata::EVENT_TYPE, "178"},
{Metadata::TASK_CATEGORY, "event_data_for_flag_3"},
{Metadata::LEVEL, "event_data_for_flag_2"},
{Metadata::KEYWORDS, "event_data_for_flag_5"}};

SECTION("update_xml is false => fields are collected into walker.getFieldValues()") {
const std::map<std::string, std::string> expected_field_values{
Expand Down
64 changes: 23 additions & 41 deletions extensions/windows-event-log/wel/MetadataWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@
* limitations under the License.
*/

#include <strsafe.h>

#include <map>
#include <functional>
#include <codecvt>
#include <regex>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -90,10 +86,11 @@ bool MetadataWalker::for_each(pugi::xml_node &node) {
if (it != formatFlagMap.end()) {
std::function<std::string(const std::string &)> updateFunc = [&](const std::string &input) -> std::string {
if (resolve_) {
auto resolved = windows_event_log_metadata_.getEventData(it->second);
if (!resolved.empty()) {
return resolved;
const auto resolved = windows_event_log_metadata_.getEventData(it->second);
if (resolved && !resolved->empty()) {
return *resolved;
}
// TODO(szaszm): add error logging
Copy link
Member Author

@szaszm szaszm Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One behavior change in getEventData: allocation failure now returns an error_code, instead of an empty string. Since both empty strings and errors are ignored here, there is no change in overall behavior. Added a comment to do proper error handling later, but I didn't wanna do it in the context of this change. (MetadataWalker has no logger.)

}
return input;
};
Expand Down Expand Up @@ -123,40 +120,25 @@ std::vector<std::string> MetadataWalker::getIdentifiers(const std::string &text)
return found_strings;
}

std::string MetadataWalker::getMetadata(METADATA metadata) const {
switch (metadata) {
case LOG_NAME:
return log_name_;
case SOURCE:
return getString(metadata_, "Provider");
case TIME_CREATED:
return windows_event_log_metadata_.getEventTimestamp();
case EVENTID:
return getString(metadata_, "EventID");
case EVENT_RECORDID:
return getString(metadata_, "EventRecordID");
case OPCODE:
return getString(metadata_, "Opcode");
case TASK_CATEGORY:
return getString(metadata_, "Task");
case LEVEL:
return getString(metadata_, "Level");
case KEYWORDS:
return getString(metadata_, "Keywords");
case EVENT_TYPE:
return std::to_string(windows_event_log_metadata_.getEventTypeIndex());
case COMPUTER:
return WindowsEventLogMetadata::getComputerName();
}
return "N/A";
}

std::map<std::string, std::string> MetadataWalker::getFieldValues() const {
return fields_values_;
}

std::map<std::string, std::string> MetadataWalker::getIdentifiers() const {
return replaced_identifiers_;
Comment on lines -154 to -159
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved inline to the header

std::string MetadataWalker::getMetadata(Metadata metadata) const {
using enum Metadata;
switch (metadata) {
case LOG_NAME: return log_name_;
case SOURCE: return getString(metadata_, "Provider");
case TIME_CREATED: return windows_event_log_metadata_.getEventTimestamp();
case EVENTID: return getString(metadata_, "EventID");
case EVENT_RECORDID: return getString(metadata_, "EventRecordID");
case OPCODE: return getString(metadata_, "Opcode");
case TASK_CATEGORY: return getString(metadata_, "Task");
case LEVEL: return getString(metadata_, "Level");
case KEYWORDS: return getString(metadata_, "Keywords");
case EVENT_TYPE: return std::to_string(windows_event_log_metadata_.getEventTypeIndex());
case COMPUTER: return WindowsEventLogMetadata::getComputerName();
case USER: // TODO(szaszm): unhandled before refactoring
case UNKNOWN: // TODO(szaszm): unhandled before refactoring
break;
}
return "N/A";
}

template<typename Fn>
Expand Down
14 changes: 4 additions & 10 deletions extensions/windows-event-log/wel/MetadataWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,26 @@

#include <Windows.h>
#include <winevt.h>
#include <codecvt>
#include <functional>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <optional>
#include <utility>
#include <type_traits>

#include "core/Core.h"
#include "core/Processor.h"
#include "core/ProcessSession.h"
#include "FlowFileRecord.h"
#include "WindowsEventLog.h"

#include "concurrentqueue.h"
#include "pugixml.hpp"
#include "utils/RegexUtils.h"

namespace org::apache::nifi::minifi::wel {

/**
* Defines a tree walker for the XML input
*
*/
class MetadataWalker : public pugi::xml_tree_walker {
public:
Expand All @@ -65,11 +61,9 @@ class MetadataWalker : public pugi::xml_tree_walker {
*/
bool for_each(pugi::xml_node &node) override;

[[nodiscard]] std::map<std::string, std::string> getFieldValues() const;

[[nodiscard]] std::map<std::string, std::string> getIdentifiers() const;

[[nodiscard]] std::string getMetadata(METADATA metadata) const;
[[nodiscard]] std::map<std::string, std::string> getFieldValues() const { return fields_values_; }
[[nodiscard]] std::map<std::string, std::string> getIdentifiers() const { return replaced_identifiers_; }
[[nodiscard]] std::string getMetadata(Metadata metadata) const;

private:
static std::vector<std::string> getIdentifiers(const std::string &text);
Expand Down
Loading