3434#include " wel/MetadataWalker.h"
3535#include " wel/XMLString.h"
3636#include " wel/UnicodeConversion.h"
37+ #include " wel/JSONUtils.h"
3738
3839#include " io/BufferStream.h"
3940#include " core/ProcessContext.h"
@@ -134,8 +135,16 @@ core::Property ConsumeWindowsEventLog::OutputFormat(
134135 core::PropertyBuilder::createProperty (" Output Format" )->
135136 isRequired(true )->
136137 withDefaultValue(Both)->
137- withAllowableValues<std::string>({XML, Plaintext, Both})->
138- withDescription(" Set the output format type. In case \' Both\' is selected the processor generates two flow files for every event captured" )->
138+ withAllowableValues<std::string>({XML, Plaintext, Both, JSON})->
139+ 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" )->
140+ build());
141+
142+ core::Property ConsumeWindowsEventLog::JSONFormat (
143+ core::PropertyBuilder::createProperty (" JSON Format" )->
144+ isRequired(true )->
145+ withDefaultValue(JSONSimple)->
146+ withAllowableValues<std::string>({JSONSimple, JSONFlattened, JSONRaw})->
147+ withDescription(" Set the json format type. Only applicable if Output Format is set to 'JSON'" )->
139148 build());
140149
141150core::Property ConsumeWindowsEventLog::BatchCommitSize (
@@ -162,17 +171,15 @@ core::Property ConsumeWindowsEventLog::ProcessOldEvents(
162171core::Relationship ConsumeWindowsEventLog::Success (" success" , " Relationship for successfully consumed events." );
163172
164173ConsumeWindowsEventLog::ConsumeWindowsEventLog (const std::string& name, utils::Identifier uuid)
165- : core::Processor(name, uuid), logger_(logging::LoggerFactory<ConsumeWindowsEventLog>::getLogger()), apply_identifier_function_(false ), batch_commit_size_(0U ) {
174+ : core::Processor(name, uuid),
175+ logger_(logging::LoggerFactory<ConsumeWindowsEventLog>::getLogger()) {
166176 char buff[MAX_COMPUTERNAME_LENGTH + 1 ];
167177 DWORD size = sizeof (buff);
168178 if (GetComputerName (buff, &size)) {
169179 computerName_ = buff;
170180 } else {
171181 LogWindowsError ();
172182 }
173-
174- writeXML_ = false ;
175- writePlainText_ = false ;
176183}
177184
178185void ConsumeWindowsEventLog::notifyStop () {
@@ -199,7 +206,7 @@ void ConsumeWindowsEventLog::initialize() {
199206 // ! Set the supported properties
200207 setSupportedProperties ({
201208 Channel, Query, MaxBufferSize, InactiveDurationToReconnect, IdentifierMatcher, IdentifierFunction, ResolveAsAttributes,
202- EventHeaderDelimiter, EventHeader, OutputFormat, BatchCommitSize, BookmarkRootDirectory, ProcessOldEvents
209+ EventHeaderDelimiter, EventHeader, OutputFormat, JSONFormat, BatchCommitSize, BookmarkRootDirectory, ProcessOldEvents
203210 });
204211
205212 // ! Set the supported relationships
@@ -252,11 +259,31 @@ void ConsumeWindowsEventLog::onSchedule(const std::shared_ptr<core::ProcessConte
252259 std::string mode;
253260 context->getProperty (OutputFormat.getName (), mode);
254261
255- writeXML_ = (mode == Both || mode == XML);
256-
257- writePlainText_ = (mode == Both || mode == Plaintext);
262+ output_ = {};
263+ if (mode == XML) {
264+ output_.xml = true ;
265+ } else if (mode == Plaintext) {
266+ output_.plaintext = true ;
267+ } else if (mode == Both) {
268+ output_.xml = true ;
269+ output_.plaintext = true ;
270+ } else if (mode == JSON) {
271+ std::string json_format;
272+ context->getProperty (JSONFormat.getName (), json_format);
273+ if (json_format == JSONRaw) {
274+ output_.json .type = JSONType::Raw;
275+ } else if (json_format == JSONSimple) {
276+ output_.json .type = JSONType::Simple;
277+ } else if (json_format == JSONFlattened) {
278+ output_.json .type = JSONType::Flattened;
279+ }
280+ } else {
281+ // in the future this might be considered an error, but for now due to backwards
282+ // compatibility we just fall through and execute the processor outputing nothing
283+ // throw Exception(PROCESS_SCHEDULE_EXCEPTION, "Unrecognized output format: " + mode);
284+ }
258285
259- if (writeXML_ && !hMsobjsDll_) {
286+ if ((output_. xml || output_. json ) && !hMsobjsDll_) {
260287 char systemDir[MAX_PATH];
261288 if (GetSystemDirectory (systemDir, sizeof (systemDir))) {
262289 hMsobjsDll_ = LoadLibrary ((systemDir + std::string (" \\ msobjs.dll" )).c_str ());
@@ -564,7 +591,7 @@ bool ConsumeWindowsEventLog::createEventRender(EVT_HANDLE hEvent, EventRender& e
564591
565592 logger_->log_debug (" Finish doc traversing, performing writing..." );
566593
567- if (writePlainText_ ) {
594+ if (output_. plaintext ) {
568595 logger_->log_trace (" Writing event in plain text" );
569596
570597 auto handler = getEventLogHandler (providerName);
@@ -583,30 +610,47 @@ bool ConsumeWindowsEventLog::createEventRender(EVT_HANDLE hEvent, EventRender& e
583610 // set the delimiter
584611 log_header.setDelimiter (header_delimiter_);
585612 // render the header.
586- eventRender.rendered_text_ = log_header.getEventHeader ([&walker](wel::METADATA metadata) { return walker.getMetadata (metadata); });
587- eventRender.rendered_text_ += " Message" + header_delimiter_ + " " ;
588- eventRender.rendered_text_ += message;
613+ eventRender.plaintext = log_header.getEventHeader ([&walker](wel::METADATA metadata) { return walker.getMetadata (metadata); });
614+ eventRender.plaintext += " Message" + header_delimiter_ + " " ;
615+ eventRender.plaintext += message;
589616 }
590617 logger_->log_trace (" Finish writing in plain text" );
591618 }
592619
593- if (writeXML_) {
594- logger_->log_trace (" Writing event in XML" );
620+ if (output_.xml || output_.json ) {
595621 substituteXMLPercentageItems (doc);
596622 logger_->log_trace (" Finish substituting %% in XML" );
597623
598624 if (resolve_as_attributes_) {
599- eventRender.matched_fields_ = walker.getFieldValues ();
625+ eventRender.matched_fields = walker.getFieldValues ();
600626 }
627+ }
628+
629+ if (output_.xml ) {
630+ logger_->log_trace (" Writing event in XML" );
601631
602632 wel::XmlString writer;
603633 doc.print (writer, " " , pugi::format_raw); // no indentation or formatting
604634 xml = writer.xml_ ;
605635
606- eventRender.text_ = std::move (xml);
636+ eventRender.xml = std::move (xml);
607637 logger_->log_trace (" Finish writing in XML" );
608638 }
609639
640+ if (output_.json .type == JSONType::Raw) {
641+ logger_->log_trace (" Writing event in raw JSON" );
642+ eventRender.json = wel::jsonToString (wel::toRawJSON (doc));
643+ logger_->log_trace (" Finish writing in raw JSON" );
644+ } else if (output_.json .type == JSONType::Simple) {
645+ logger_->log_trace (" Writing event in simple JSON" );
646+ eventRender.json = wel::jsonToString (wel::toSimpleJSON (doc));
647+ logger_->log_trace (" Finish writing in simple JSON" );
648+ } else if (output_.json .type == JSONType::Flattened) {
649+ logger_->log_trace (" Writing event in flattened JSON" );
650+ eventRender.json = wel::jsonToString (wel::toFlattenedJSON (doc));
651+ logger_->log_trace (" Finish writing in flattened JSON" );
652+ }
653+
610654 return true ;
611655}
612656
@@ -658,39 +702,45 @@ void ConsumeWindowsEventLog::putEventRenderFlowFileToSession(const EventRender&
658702 const std::string& str_;
659703 };
660704
661- if (writeXML_) {
662- auto flowFile = session.create ();
663- logger_->log_trace (" Writing rendered XML to a flow file" );
664-
705+ auto commitFlowFile = [&] (const std::shared_ptr<core::FlowFile>& flowFile, const std::string& content, const std::string& mimeType) {
665706 {
666- WriteCallback wc{ eventRender. text_ };
707+ WriteCallback wc{ content };
667708 session.write (flowFile, &wc);
668709 }
669- for (const auto &fieldMapping : eventRender.matched_fields_ ) {
670- if (!fieldMapping.second .empty ()) {
671- session.putAttribute (flowFile, fieldMapping.first , fieldMapping.second );
672- }
673- }
674- session.putAttribute (flowFile, core::SpecialFlowAttribute::MIME_TYPE, " application/xml" );
710+ session.putAttribute (flowFile, core::SpecialFlowAttribute::MIME_TYPE, mimeType);
675711 session.putAttribute (flowFile, " Timezone name" , timezone_name_);
676712 session.putAttribute (flowFile, " Timezone offset" , timezone_offset_);
677713 session.getProvenanceReporter ()->receive (flowFile, provenanceUri_, getUUIDStr (), " Consume windows event logs" , 0 );
678714 session.transfer (flowFile, Success);
679- }
715+ };
680716
681- if (writePlainText_ ) {
717+ if (output_. xml ) {
682718 auto flowFile = session.create ();
683- logger_->log_trace (" Writing rendered plain text to a flow file" );
719+ logger_->log_trace (" Writing rendered XML to a flow file" );
684720
685- {
686- WriteCallback wc{ eventRender.rendered_text_ };
687- session.write (flowFile, &wc);
721+ for (const auto &fieldMapping : eventRender.matched_fields ) {
722+ if (!fieldMapping.second .empty ()) {
723+ session.putAttribute (flowFile, fieldMapping.first , fieldMapping.second );
724+ }
688725 }
689- session.putAttribute (flowFile, core::SpecialFlowAttribute::MIME_TYPE, " text/plain" );
690- session.putAttribute (flowFile, " Timezone name" , timezone_name_);
691- session.putAttribute (flowFile, " Timezone offset" , timezone_offset_);
692- session.getProvenanceReporter ()->receive (flowFile, provenanceUri_, getUUIDStr (), " Consume windows event logs" , 0 );
693- session.transfer (flowFile, Success);
726+
727+ commitFlowFile (flowFile, eventRender.xml , " application/xml" );
728+ }
729+
730+ if (output_.plaintext ) {
731+ logger_->log_trace (" Writing rendered plain text to a flow file" );
732+ commitFlowFile (session.create (), eventRender.plaintext , " text/plain" );
733+ }
734+
735+ if (output_.json .type == JSONType::Raw) {
736+ logger_->log_trace (" Writing rendered raw JSON to a flow file" );
737+ commitFlowFile (session.create (), eventRender.json , " application/json" );
738+ } else if (output_.json .type == JSONType::Simple) {
739+ logger_->log_trace (" Writing rendered simple JSON to a flow file" );
740+ commitFlowFile (session.create (), eventRender.json , " application/json" );
741+ } else if (output_.json .type == JSONType::Flattened) {
742+ logger_->log_trace (" Writing rendered flattened JSON to a flow file" );
743+ commitFlowFile (session.create (), eventRender.json , " application/json" );
694744 }
695745}
696746
0 commit comments