mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-18 18:58:41 +00:00
feat: add JSON as output format for --list/--list_events
- Added support of the JSON format - Refactored field and events formatting using the strategy pattern Signed-off-by: Paolo Polidori <paolo.polidori@sysdig.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<std::string, std::set<std::string>> 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<std::string> 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<load_result> falco_engine::load_rules(const std::string &rules_content,
|
||||
|
||||
@@ -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*
|
||||
|
||||
122
userspace/engine/field_formatter.cpp
Normal file
122
userspace/engine/field_formatter.cpp
Normal file
@@ -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> FieldFormatter::create(output_format format, bool verbose) {
|
||||
switch(format) {
|
||||
case output_format::JSON:
|
||||
return std::make_unique<JsonFieldFormatter>(verbose);
|
||||
case output_format::MARKDOWN:
|
||||
return std::make_unique<MarkdownFieldFormatter>(verbose);
|
||||
case output_format::TEXT:
|
||||
default:
|
||||
return std::make_unique<TextFieldFormatter>(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<std::string>& 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<std::string>& 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<std::string>& 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());
|
||||
}
|
||||
}
|
||||
102
userspace/engine/field_formatter.h
Normal file
102
userspace/engine/field_formatter.h
Normal file
@@ -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 <string>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <libsinsp/sinsp.h>
|
||||
|
||||
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<std::string>& 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<FieldFormatter> 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<std::string>& 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<std::string>& 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<std::string>& 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
|
||||
@@ -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
|
||||
|
||||
200
userspace/falco/app/actions/event_formatter.cpp
Normal file
200
userspace/falco/app/actions/event_formatter.cpp
Normal file
@@ -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 <libsinsp/sinsp.h>
|
||||
#include <libsinsp/event.h>
|
||||
|
||||
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> EventFormatter::create(output_format format) {
|
||||
switch(format) {
|
||||
case output_format::JSON:
|
||||
return std::make_unique<JsonFormatter>();
|
||||
case output_format::MARKDOWN:
|
||||
return std::make_unique<MarkdownFormatter>();
|
||||
case output_format::TEXT:
|
||||
default:
|
||||
return std::make_unique<TextFormatter>();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 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<const ppm_name_value*>(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<const ppm_name_value*>(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<const ppm_name_value*>(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;
|
||||
}
|
||||
112
userspace/falco/app/actions/event_formatter.h
Normal file
112
userspace/falco/app/actions/event_formatter.h
Normal file
@@ -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 <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#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<EventFormatter> 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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<event_entry> syscalls;
|
||||
std::vector<event_entry> 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<const ppm_name_value*>(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<event_entry>& 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<ppm_event_code> 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();
|
||||
}
|
||||
|
||||
@@ -25,10 +25,33 @@ limitations under the License.
|
||||
#include <cxxopts.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
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<bool>(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 <num_seconds> are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
|
||||
("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<bool>(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<bool>(markdown))
|
||||
("format", "Print output in the specified <format> 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), "<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 <opt> to <val>. Overrides values in the configuration file. <opt> 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), "<opt>=<val>")
|
||||
("plugin-info", "Print info for the plugin specified by <plugin_name> 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<plugin_name> can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "<plugin_name>")
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <libsinsp/event.h>
|
||||
#include "../output_format.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -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<std::string> cmdline_config_options;
|
||||
|
||||
23
userspace/falco/output_format.h
Normal file
23
userspace/falco/output_format.h
Normal file
@@ -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
|
||||
};
|
||||
Reference in New Issue
Block a user