tools: add gen-eventfilter.py
Generate event filtering code for lg2::commit from an input json
file, so that system integrators can create default filtering rules
to omit undesired events and errors from their systems.
Tested:
Used `log-create` to create an event and observed it. Modified the
default event filter as follows and saw log was not created.
```
@@ -3,6 +3,9 @@
"default": "allowed"
},
"errors": {
- "default": "allowed"
+ "default": "allowed",
+ "ids": [
+ "xyz.openbmc_project.State.SMC.SMCFailed"
+ ]
}
}
```
```
$ ./builddir/log-create xyz.openbmc_project.State.SMC.SMCFailed --json '{ "IDENTIFIER": "/xyz/openbmc_project/inventory/SomeSMC", "FAILURE_TYPE": "Timeout for the SMC" }'
```
Change-Id: Ib6041481075758b994bb27a816dbf5e9f26c2841
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/tools/gen-eventfilter.py b/tools/gen-eventfilter.py
new file mode 100755
index 0000000..56151d6
--- /dev/null
+++ b/tools/gen-eventfilter.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+
+import argparse
+import json
+import os
+import sys
+
+import jsonschema
+from mako.template import Template
+
+import yaml
+
+# Determine the script's directory to find the schema file relative to it.
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+SCHEMA_FILE = os.path.join(
+ SCRIPT_DIR, "phosphor-logging", "schemas", "eventfilter.schema.yaml"
+)
+TEMPLATE_FILE = os.path.join(
+ SCRIPT_DIR, "phosphor-logging", "templates", "event-filter.cpp.mako"
+)
+
+
+def main() -> int:
+ """
+ Validates a JSON filter file against the eventfilter schema.
+ """
+ parser = argparse.ArgumentParser(
+ description="Validate an event filter JSON file against the schema."
+ )
+ parser.add_argument(
+ "filter",
+ type=str,
+ help="Path to the JSON filter file to validate.",
+ )
+ args = parser.parse_args()
+
+ with open(args.filter, "r") as f:
+ filter_data = json.load(f)
+
+ with open(SCHEMA_FILE, "r") as f:
+ schema_data = yaml.safe_load(f)
+
+ jsonschema.validate(instance=filter_data, schema=schema_data)
+
+ template = Template(filename=TEMPLATE_FILE)
+ output = template.render(data=filter_data)
+ print(output)
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/tools/meson.build b/tools/meson.build
index bb08ffb..fcde0bf 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -1,4 +1,7 @@
tool_dir = meson.current_source_dir()
elog_gen = files('elog-gen.py')
+eventfilter_gen = files('gen-eventfilter.py')
+default_eventfilter_json = files('phosphor-logging/default-eventfilter.json')
+
subdir('phosphor-logging/templates')
diff --git a/tools/phosphor-logging/default-eventfilter.json b/tools/phosphor-logging/default-eventfilter.json
new file mode 100644
index 0000000..501ace6
--- /dev/null
+++ b/tools/phosphor-logging/default-eventfilter.json
@@ -0,0 +1,8 @@
+{
+ "events": {
+ "default": "allowed"
+ },
+ "errors": {
+ "default": "allowed"
+ }
+}
diff --git a/tools/phosphor-logging/schemas/eventfilter.schema.yaml b/tools/phosphor-logging/schemas/eventfilter.schema.yaml
new file mode 100644
index 0000000..aa7e511
--- /dev/null
+++ b/tools/phosphor-logging/schemas/eventfilter.schema.yaml
@@ -0,0 +1,36 @@
+$id: "http://openbmc-project.xyz/phosphor-logging/eventdefault.yaml"
+$schema: "https://json-schema.org/draft/2020-12/schema"
+title: "Event and Error defaults"
+
+$defs:
+ base-event:
+ type: object
+ properties:
+ default:
+ description:
+ The default setting for any event not specified in ids.
+ type: string
+ enum:
+ - "blocked"
+ - "allowed"
+ ids:
+ description: The list of ids to do the opposite of 'default'.
+ type: array
+ items:
+ type: string
+ description: Event ids from phosphor-dbus-interfaces.
+ pattern: "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+$"
+ required:
+ - default
+ additionalProperties: false
+
+type: object
+properties:
+ events:
+ $ref: "#/$defs/base-event"
+ errors:
+ $ref: "#/$defs/base-event"
+required:
+ - events
+ - errors
+additionalProperties: false
diff --git a/tools/phosphor-logging/templates/event-filter.cpp.mako b/tools/phosphor-logging/templates/event-filter.cpp.mako
new file mode 100644
index 0000000..0a4a4ef
--- /dev/null
+++ b/tools/phosphor-logging/templates/event-filter.cpp.mako
@@ -0,0 +1,62 @@
+## Note that this file is not auto generated, it is what generates the
+## lg2_eventfilter.cpp file
+// This file was autogenerated. Do not edit!
+
+#include <string>
+#include <unordered_set>
+
+namespace lg2
+{
+namespace details
+{
+
+bool filterEvent([[maybe_unused]] const std::string& id)
+{
+ static constexpr bool default_return = \
+ % if data['events']['default'] == 'allowed':
+false;
+ % else:
+true;
+ % endif
+ % if "ids" in data['events'] and len(data['events']['ids']) != 0:
+ static const std::unordered_set<std::string> event_ids = {
+ % for item in data['events']['ids']:
+ "${item}",
+ % endfor
+ };
+
+ if (event_ids.contains(id))
+ {
+ return !default_return;
+ }
+ % endif
+
+ return default_return;
+}
+
+bool filterError([[maybe_unused]] const std::string& id)
+{
+ static constexpr bool default_return = \
+ % if data['errors']['default'] == 'allowed':
+false;
+ % else:
+true;
+ % endif
+ % if "ids" in data['errors'] and len(data['errors']['ids']) != 0:
+ static const std::unordered_set<std::string> error_ids = {
+ % for item in data['errors']['ids']:
+ "${item}",
+ % endfor
+ };
+
+ if (error_ids.contains(id))
+ {
+ return !default_return;
+ }
+ % endif
+
+ return default_return;
+}
+
+} // namespace details
+} // namespace lg2
diff --git a/tools/phosphor-logging/templates/meson.build b/tools/phosphor-logging/templates/meson.build
index e713aaf..ee9e24c 100644
--- a/tools/phosphor-logging/templates/meson.build
+++ b/tools/phosphor-logging/templates/meson.build
@@ -1 +1,2 @@
template_elog_gen = files('elog-gen-template.hpp.mako')
+template_eventfilter_gen = files('event-filter.cpp.mako')