diff --git a/userspace/engine/CMakeLists.txt b/userspace/engine/CMakeLists.txt index cca3fd8a..a9b75ea6 100644 --- a/userspace/engine/CMakeLists.txt +++ b/userspace/engine/CMakeLists.txt @@ -21,6 +21,7 @@ add_library( filter_ruleset.cpp evttype_index_ruleset.cpp formats.cpp + field_formatter.cpp filter_details_resolver.cpp filter_macro_resolver.cpp filter_warning_resolver.cpp diff --git a/userspace/engine/falco_engine.cpp b/userspace/engine/falco_engine.cpp index 959bd36d..5baa06ea 100644 --- a/userspace/engine/falco_engine.cpp +++ b/userspace/engine/falco_engine.cpp @@ -42,6 +42,7 @@ limitations under the License. #include "falco_engine_version.h" #include "formats.h" +#include "field_formatter.h" #include "evttype_index_ruleset.h" @@ -117,7 +118,7 @@ static std::string fieldclass_key(const sinsp_filter_factory::filter_fieldclass_ void falco_engine::list_fields(const std::string &source, bool verbose, bool names_only, - bool markdown) const { + output_format format) const { // Maps from field class name + short desc to list of event // sources for which this field class can be used. std::map> fieldclass_event_sources; @@ -138,6 +139,10 @@ void falco_engine::list_fields(const std::string &source, // printing field classes multiple times for different sources std::set seen_fieldclasses; + // Create the appropriate formatter and use it + auto formatter = FieldFormatter::create(format, verbose); + formatter->begin(); + // In the second pass, actually print info, skipping duplicate // field classes and also printing info on supported sources. for(const auto &it : m_sources) { @@ -160,21 +165,15 @@ void falco_engine::list_fields(const std::string &source, continue; } - printf("%s\n", field.name.c_str()); + formatter->print_field_name(field.name); } - } else if(markdown) { - printf("%s\n", - fld_class.as_markdown(fieldclass_event_sources[fieldclass_key(fld_class)]) - .c_str()); } else { - printf("%s\n", - fld_class - .as_string(verbose, - fieldclass_event_sources[fieldclass_key(fld_class)]) - .c_str()); + formatter->print_fieldclass(fld_class, fieldclass_event_sources[key]); } } } + + formatter->end(); } std::unique_ptr falco_engine::load_rules(const std::string &rules_content, diff --git a/userspace/engine/falco_engine.h b/userspace/engine/falco_engine.h index 59c50e0a..73a9696f 100644 --- a/userspace/engine/falco_engine.h +++ b/userspace/engine/falco_engine.h @@ -34,6 +34,7 @@ limitations under the License. #include "falco_source.h" #include "falco_load_result.h" #include "filter_details_resolver.h" +#include "../falco/output_format.h" // // This class acts as the primary interface between a program and the @@ -62,7 +63,7 @@ public: // Print to stdout (using printf) a description of each field supported by this engine. // If source is non-empty, only fields for the provided source are printed. - void list_fields(const std::string &source, bool verbose, bool names_only, bool markdown) const; + void list_fields(const std::string &source, bool verbose, bool names_only, output_format format) const; // Provide an alternate rule reader, collector, and compiler // to compile any rules provided via load_rules* diff --git a/userspace/engine/field_formatter.cpp b/userspace/engine/field_formatter.cpp new file mode 100644 index 00000000..fda51c83 --- /dev/null +++ b/userspace/engine/field_formatter.cpp @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2025 The Falco Authors. + +Licensed 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 "field_formatter.h" +#include "formats.h" + +using namespace falco; + +// Factory method +std::unique_ptr FieldFormatter::create(output_format format, bool verbose) { + switch(format) { + case output_format::JSON: + return std::make_unique(verbose); + case output_format::MARKDOWN: + return std::make_unique(verbose); + case output_format::TEXT: + default: + return std::make_unique(verbose); + } +} + +// ============================================================================ +// TextFieldFormatter implementation +// ============================================================================ + +TextFieldFormatter::TextFieldFormatter(bool verbose): m_verbose(verbose) {} + +void TextFieldFormatter::begin() { + // Nothing to do for text format +} + +void TextFieldFormatter::print_fieldclass( + const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) { + printf("%s\n", fld_class.as_string(m_verbose, event_sources).c_str()); +} + +void TextFieldFormatter::print_field_name(const std::string& name) { + printf("%s\n", name.c_str()); +} + +void TextFieldFormatter::end() { + // Nothing to do for text format +} + +// ============================================================================ +// MarkdownFieldFormatter implementation +// ============================================================================ + +MarkdownFieldFormatter::MarkdownFieldFormatter(bool verbose): m_verbose(verbose) {} + +void MarkdownFieldFormatter::begin() { + // Nothing to do for markdown format +} + +void MarkdownFieldFormatter::print_fieldclass( + const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) { + printf("%s\n", fld_class.as_markdown(event_sources).c_str()); +} + +void MarkdownFieldFormatter::print_field_name(const std::string& name) { + printf("%s\n", name.c_str()); +} + +void MarkdownFieldFormatter::end() { + // Nothing to do for markdown format +} + +// ============================================================================ +// JsonFieldFormatter implementation +// ============================================================================ + +JsonFieldFormatter::JsonFieldFormatter(bool verbose): m_verbose(verbose) {} + +void JsonFieldFormatter::begin() { + m_fieldclasses_array = nlohmann::json::array(); + m_fieldnames_array = nlohmann::json::array(); + m_has_fieldclasses = false; + m_has_fieldnames = false; +} + +void JsonFieldFormatter::print_fieldclass( + const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) { + std::string json_str = fld_class.as_json(event_sources); + if(!json_str.empty()) { + m_fieldclasses_array.push_back(nlohmann::json::parse(json_str)); + m_has_fieldclasses = true; + } +} + +void JsonFieldFormatter::print_field_name(const std::string& name) { + m_fieldnames_array.push_back(name); + m_has_fieldnames = true; +} + +void JsonFieldFormatter::end() { + nlohmann::json root; + + if(m_has_fieldclasses) { + root["fieldclasses"] = m_fieldclasses_array; + printf("%s\n", root.dump(2).c_str()); + } else if(m_has_fieldnames) { + root["fieldnames"] = m_fieldnames_array; + printf("%s\n", root.dump(2).c_str()); + } +} diff --git a/userspace/engine/field_formatter.h b/userspace/engine/field_formatter.h new file mode 100644 index 00000000..3feff839 --- /dev/null +++ b/userspace/engine/field_formatter.h @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2025 The Falco Authors. + +Licensed 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. +*/ + +#pragma once + +#include +#include +#include +#include + +#include + +enum class output_format; + +namespace falco { + +// Abstract formatter interface for field listing +class FieldFormatter { +public: + virtual ~FieldFormatter() = default; + + // Initialize formatter + virtual void begin() = 0; + + // Print a field class with its event sources + virtual void print_fieldclass(const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) = 0; + + // Print a single field name (for names_only mode) + virtual void print_field_name(const std::string& name) = 0; + + // Finalize and output + virtual void end() = 0; + + // Factory method + static std::unique_ptr create(output_format format, bool verbose); +}; + +// Text formatter (default) +class TextFieldFormatter : public FieldFormatter { +public: + explicit TextFieldFormatter(bool verbose); + + void begin() override; + void print_fieldclass(const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) override; + void print_field_name(const std::string& name) override; + void end() override; + +private: + bool m_verbose; +}; + +// Markdown formatter +class MarkdownFieldFormatter : public FieldFormatter { +public: + explicit MarkdownFieldFormatter(bool verbose); + + void begin() override; + void print_fieldclass(const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) override; + void print_field_name(const std::string& name) override; + void end() override; + +private: + bool m_verbose; +}; + +// JSON formatter +class JsonFieldFormatter : public FieldFormatter { +public: + explicit JsonFieldFormatter(bool verbose); + + void begin() override; + void print_fieldclass(const sinsp_filter_factory::filter_fieldclass_info& fld_class, + const std::set& event_sources) override; + void print_field_name(const std::string& name) override; + void end() override; + +private: + bool m_verbose; + nlohmann::json m_fieldclasses_array; + nlohmann::json m_fieldnames_array; + bool m_has_fieldclasses{false}; + bool m_has_fieldnames{false}; +}; + +} // namespace falco diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 0d82c42e..47ceb3ff 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -40,6 +40,7 @@ add_library( app/actions/print_plugin_info.cpp app/actions/print_support.cpp app/actions/print_syscall_events.cpp + app/actions/event_formatter.cpp app/actions/print_version.cpp app/actions/print_page_size.cpp app/actions/configure_syscall_buffer_size.cpp diff --git a/userspace/falco/app/actions/event_formatter.cpp b/userspace/falco/app/actions/event_formatter.cpp new file mode 100644 index 00000000..0e4be249 --- /dev/null +++ b/userspace/falco/app/actions/event_formatter.cpp @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2023 The Falco Authors. + +Licensed 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 "event_formatter.h" + +#include +#include + +using namespace falco::app::actions; + +static bool is_flag_type(ppm_param_type type) { + return (type == PT_FLAGS8 || type == PT_FLAGS16 || type == PT_FLAGS32 || + type == PT_ENUMFLAGS8 || type == PT_ENUMFLAGS16 || type == PT_ENUMFLAGS32); +} + +// Factory method +std::unique_ptr EventFormatter::create(output_format format) { + switch(format) { + case output_format::JSON: + return std::make_unique(); + case output_format::MARKDOWN: + return std::make_unique(); + case output_format::TEXT: + default: + return std::make_unique(); + } +} + +// ============================================================================ +// TextFormatter implementation +// ============================================================================ + +void TextFormatter::begin(const std::string& schema_version) { + printf("The events below are valid for Falco *Schema Version*: %s\n", schema_version.c_str()); +} + +void TextFormatter::begin_category(const std::string& category) { + printf("## %s\n\n", category.c_str()); +} + +void TextFormatter::print_event(const event_entry& e) { + char dir = e.is_enter ? '>' : '<'; + printf("%c %s(", dir, e.name.c_str()); + + for(uint32_t k = 0; k < e.info->nparams; k++) { + if(k != 0) { + printf(", "); + } + print_param(&e.info->params[k]); + } + + printf(")\n"); +} + +void TextFormatter::end_category() { + printf("\n"); +} + +void TextFormatter::end() { + // Nothing to do for text format +} + +void TextFormatter::print_param(const struct ppm_param_info* param) { + printf("%s **%s**", param_type_to_string(param->type), param->name); + + if(is_flag_type(param->type) && param->info) { + auto flag_info = static_cast(param->info); + + printf(": "); + for(size_t i = 0; flag_info[i].name != NULL; i++) { + if(i != 0) { + printf(", "); + } + printf("%s", flag_info[i].name); + } + } +} + +// ============================================================================ +// MarkdownFormatter implementation +// ============================================================================ + +void MarkdownFormatter::begin(const std::string& schema_version) { + printf("The events below are valid for Falco *Schema Version*: %s\n", schema_version.c_str()); +} + +void MarkdownFormatter::begin_category(const std::string& category) { + printf("## %s\n\n", category.c_str()); + printf("Default | Dir | Name | Params \n"); + printf(":-------|:----|:-----|:-----\n"); + m_first_event_in_category = true; +} + +void MarkdownFormatter::print_event(const event_entry& e) { + char dir = e.is_enter ? '>' : '<'; + + printf(e.available ? "Yes" : "No"); + printf(" | `%c` | `%s` | ", dir, e.name.c_str()); + + for(uint32_t k = 0; k < e.info->nparams; k++) { + if(k != 0) { + printf(", "); + } + print_param(&e.info->params[k]); + } + + printf("\n"); +} + +void MarkdownFormatter::end_category() { + printf("\n"); +} + +void MarkdownFormatter::end() { + // Nothing to do for markdown format +} + +void MarkdownFormatter::print_param(const struct ppm_param_info* param) { + printf("%s **%s**", param_type_to_string(param->type), param->name); + + if(is_flag_type(param->type) && param->info) { + auto flag_info = static_cast(param->info); + + printf(": "); + for(size_t i = 0; flag_info[i].name != NULL; i++) { + if(i != 0) { + printf(", "); + } + printf("*%s*", flag_info[i].name); + } + } +} + +// ============================================================================ +// JsonFormatter implementation +// ============================================================================ + +void JsonFormatter::begin(const std::string& schema_version) { + m_root = nlohmann::json::object(); + m_root["schema_version"] = schema_version; +} + +void JsonFormatter::begin_category(const std::string& category) { + m_current_category = nlohmann::json::array(); + m_current_category_name = category; +} + +void JsonFormatter::print_event(const event_entry& e) { + m_current_category.push_back(event_to_json(e)); +} + +void JsonFormatter::end_category() { + m_root[m_current_category_name] = m_current_category; +} + +void JsonFormatter::end() { + printf("%s\n", m_root.dump(2).c_str()); +} + +nlohmann::json JsonFormatter::event_to_json(const event_entry& e) { + nlohmann::json event; + event["name"] = e.name; + event["dir"] = e.is_enter ? ">" : "<"; + event["available"] = e.available; + + nlohmann::json params = nlohmann::json::array(); + for(uint32_t k = 0; k < e.info->nparams; k++) { + nlohmann::json param; + param["type"] = param_type_to_string(e.info->params[k].type); + param["name"] = e.info->params[k].name; + + if(is_flag_type(e.info->params[k].type) && e.info->params[k].info) { + auto flag_info = static_cast(e.info->params[k].info); + nlohmann::json flags = nlohmann::json::array(); + for(size_t i = 0; flag_info[i].name != NULL; i++) { + flags.push_back(flag_info[i].name); + } + param["flags"] = flags; + } + + params.push_back(param); + } + event["params"] = params; + + return event; +} diff --git a/userspace/falco/app/actions/event_formatter.h b/userspace/falco/app/actions/event_formatter.h new file mode 100644 index 00000000..e72ae966 --- /dev/null +++ b/userspace/falco/app/actions/event_formatter.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2023 The Falco Authors. + +Licensed 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. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../../output_format.h" + +struct ppm_param_info; +struct ppm_event_info; + +namespace falco { +namespace app { +namespace actions { + +struct event_entry { + bool is_enter; + bool available; + std::string name; + const ppm_event_info* info; +}; + +// Abstract formatter interface +class EventFormatter { +public: + virtual ~EventFormatter() = default; + + // Initialize formatter with schema version + virtual void begin(const std::string& schema_version) = 0; + + // Print category header + virtual void begin_category(const std::string& category) = 0; + + // Print a single event + virtual void print_event(const event_entry& e) = 0; + + // End category + virtual void end_category() = 0; + + // Finalize and output + virtual void end() = 0; + + // Factory method + static std::unique_ptr create(output_format format); +}; + +// Text formatter (default) +class TextFormatter : public EventFormatter { +public: + void begin(const std::string& schema_version) override; + void begin_category(const std::string& category) override; + void print_event(const event_entry& e) override; + void end_category() override; + void end() override; + +private: + void print_param(const struct ppm_param_info* param); +}; + +// Markdown formatter +class MarkdownFormatter : public EventFormatter { +public: + void begin(const std::string& schema_version) override; + void begin_category(const std::string& category) override; + void print_event(const event_entry& e) override; + void end_category() override; + void end() override; + +private: + void print_param(const struct ppm_param_info* param); + bool m_first_event_in_category{true}; +}; + +// JSON formatter +class JsonFormatter : public EventFormatter { +public: + void begin(const std::string& schema_version) override; + void begin_category(const std::string& category) override; + void print_event(const event_entry& e) override; + void end_category() override; + void end() override; + +private: + nlohmann::json m_root; + nlohmann::json m_current_category; + std::string m_current_category_name; + + nlohmann::json event_to_json(const event_entry& e); +}; + +} // namespace actions +} // namespace app +} // namespace falco diff --git a/userspace/falco/app/actions/list_fields.cpp b/userspace/falco/app/actions/list_fields.cpp index 23999009..2dbdd0a7 100644 --- a/userspace/falco/app/actions/list_fields.cpp +++ b/userspace/falco/app/actions/list_fields.cpp @@ -33,6 +33,6 @@ falco::app::run_result falco::app::actions::list_fields(falco::app::state& s) { s.engine->list_fields(s.options.list_source_fields, s.options.verbose, s.options.names_only, - s.options.markdown); + s.options.output_fmt); return run_result::exit(); } diff --git a/userspace/falco/app/actions/print_syscall_events.cpp b/userspace/falco/app/actions/print_syscall_events.cpp index ee93f90c..53b6544f 100644 --- a/userspace/falco/app/actions/print_syscall_events.cpp +++ b/userspace/falco/app/actions/print_syscall_events.cpp @@ -17,19 +17,13 @@ limitations under the License. #include "actions.h" #include "helpers.h" +#include "event_formatter.h" #include "../app.h" #include "../../versions_info.h" using namespace falco::app; using namespace falco::app::actions; -struct event_entry { - bool is_enter; - bool available; - std::string name; - const ppm_event_info* info; -}; - struct events_by_category { std::vector syscalls; std::vector tracepoints; @@ -69,6 +63,32 @@ struct events_by_category { return; } } + + void print_all(EventFormatter& formatter) { + formatter.begin_category("Syscall events"); + for(const auto& e : syscalls) { + formatter.print_event(e); + } + formatter.end_category(); + + formatter.begin_category("Tracepoint events"); + for(const auto& e : tracepoints) { + formatter.print_event(e); + } + formatter.end_category(); + + formatter.begin_category("Plugin events"); + for(const auto& e : pluginevents) { + formatter.print_event(e); + } + formatter.end_category(); + + formatter.begin_category("Metaevents"); + for(const auto& e : metaevents) { + formatter.print_event(e); + } + formatter.end_category(); + } }; static struct events_by_category get_event_entries_by_category( @@ -100,86 +120,21 @@ static struct events_by_category get_event_entries_by_category( return result; } -static bool is_flag_type(ppm_param_type type) { - return (type == PT_FLAGS8 || type == PT_FLAGS16 || type == PT_FLAGS32 || - type == PT_ENUMFLAGS8 || type == PT_ENUMFLAGS16 || type == PT_ENUMFLAGS32); -} - -static void print_param(const struct ppm_param_info* param, bool markdown) { - printf("%s **%s**", param_type_to_string(param->type), param->name); - - if(is_flag_type(param->type) && param->info) { - auto flag_info = static_cast(param->info); - - printf(": "); - for(size_t i = 0; flag_info[i].name != NULL; i++) { - if(i != 0) { - printf(", "); - } - - if(markdown) { - printf("*%s*", flag_info[i].name); - } else { - printf("%s", flag_info[i].name); - } - } - } -} - -static void print_events(const std::vector& events, bool markdown) { - if(markdown) { - printf("Default | Dir | Name | Params \n"); - printf(":-------|:----|:-----|:-----\n"); - } - - for(const auto& e : events) { - char dir = e.is_enter ? '>' : '<'; - if(markdown) { - printf(e.available ? "Yes" : "No"); - printf(" | `%c` | `%s` | ", dir, e.name.c_str()); - } else { - printf("%c %s(", dir, e.name.c_str()); - } - - for(uint32_t k = 0; k < e.info->nparams; k++) { - if(k != 0) { - printf(", "); - } - - print_param(&e.info->params[k], markdown); - } - if(markdown) { - printf("\n"); - } else { - printf(")\n"); - } - } -} - falco::app::run_result falco::app::actions::print_syscall_events(falco::app::state& s) { if(!s.options.list_syscall_events) { return run_result::ok(); } const falco::versions_info info(s.offline_inspector); - printf("The events below are valid for Falco *Schema Version*: %s\n", - info.driver_schema_version.c_str()); - const libsinsp::events::set available = libsinsp::events::all_event_set().diff( sc_set_to_event_set(falco::app::ignored_sc_set())); - const struct events_by_category events_bc = get_event_entries_by_category(true, available); + struct events_by_category events_bc = get_event_entries_by_category(true, available); - printf("## Syscall events\n\n"); - print_events(events_bc.syscalls, s.options.markdown); - - printf("\n\n## Tracepoint events\n\n"); - print_events(events_bc.tracepoints, s.options.markdown); - - printf("\n\n## Plugin events\n\n"); - print_events(events_bc.pluginevents, s.options.markdown); - - printf("\n\n## Metaevents\n\n"); - print_events(events_bc.metaevents, s.options.markdown); + // Create the appropriate formatter and use it + auto formatter = EventFormatter::create(s.options.output_fmt); + formatter->begin(info.driver_schema_version); + events_bc.print_all(*formatter); + formatter->end(); return run_result::exit(); } diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index d5a35190..bde5cc11 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -25,10 +25,33 @@ limitations under the License. #include #include +#include namespace falco { namespace app { +static bool parse_output_format(const std::string& format_str, output_format& out, std::string& errstr) { + if(format_str.empty()) { + return true; + } + + std::string lower_format = format_str; + std::transform(lower_format.begin(), lower_format.end(), lower_format.begin(), ::tolower); + + if(lower_format == "text") { + out = output_format::TEXT; + } else if(lower_format == "markdown") { + out = output_format::MARKDOWN; + } else if(lower_format == "json") { + out = output_format::JSON; + } else { + errstr = "Invalid format '" + format_str + "'. Valid values are: text, markdown, json"; + return false; + } + + return true; +} + bool options::parse(int argc, char **argv, std::string &errstr) { cxxopts::Options opts("falco", "Falco - Cloud Native Runtime Security"); define(opts); @@ -81,6 +104,22 @@ bool options::parse(int argc, char **argv, std::string &errstr) { list_fields = m_cmdline_parsed.count("list") > 0; + // Validate that both markdown and format are not specified together + if(m_cmdline_parsed.count("markdown") > 0 && m_cmdline_parsed.count("format") > 0) { + errstr = "Cannot specify both --markdown and --format options together"; + return false; + } + + // Parse and validate the format option + if(!format.empty()) { + if(!parse_output_format(format, output_fmt, errstr)) { + return false; + } + } else if(markdown) { + // If markdown flag is set and format is not specified, use MARKDOWN format + output_fmt = output_format::MARKDOWN; + } + return true; } @@ -110,7 +149,8 @@ void options::define(cxxopts::Options& opts) ("list-events", "List all defined syscall events, metaevents, tracepoint events and exit.", cxxopts::value(list_syscall_events)) ("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false")) ("M", "Stop Falco execution after are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "") - ("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value(markdown)) + ("markdown", "DEPRECATED: use --format markdown instead. Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value(markdown)) + ("format", "Print output in the specified when used in conjunction with --list or --list-events options. Valid values are 'text', 'markdown', or 'json'. It has no effect when used with other options. Cannot be used together with --markdown.", cxxopts::value(format), "") ("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false")) ("o,option", "Set the value of option to . Overrides values in the configuration file. can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "=") ("plugin-info", "Print info for the plugin specified by and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "") diff --git a/userspace/falco/app/options.h b/userspace/falco/app/options.h index dd5b95db..af341d76 100644 --- a/userspace/falco/app/options.h +++ b/userspace/falco/app/options.h @@ -18,6 +18,7 @@ limitations under the License. #pragma once #include +#include "../output_format.h" #include #include @@ -57,6 +58,8 @@ public: std::string print_plugin_info; bool list_syscall_events = false; bool markdown = false; + std::string format; + output_format output_fmt = output_format::TEXT; int duration_to_tot = 0; bool names_only = false; std::vector cmdline_config_options; diff --git a/userspace/falco/output_format.h b/userspace/falco/output_format.h new file mode 100644 index 00000000..61b64aef --- /dev/null +++ b/userspace/falco/output_format.h @@ -0,0 +1,23 @@ +/* +Copyright (C) 2023 The Falco Authors. + +Licensed 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. +*/ + +#pragma once + +enum class output_format { + TEXT, + MARKDOWN, + JSON +};