elog-gen.py : read multiple error yaml files
This change enables the elog-gen script to look at more than one error
yaml file (and corresponding metadata yaml file). The input to the
script had to be changed to a yaml directory, containing
error yaml files, instead of a single error yaml file.
The reason to support reading multiple error yaml files is that,
without this, applications have to all dump their errors in a single big
error yaml file. Now it's possible to write application/domain specific
error yaml files; they just need to be exported to the same location,
from where elog-gen.py can pick them.
Change-Id: I9418bf0e0b54a7b7f7701b337649cb8eb4c54913
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index f96d2cf..ea96862 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,9 +23,8 @@
logging_test_LDFLAGS = $(SYSTEMD_LIBS)
phosphor_log_manager_LDFLAGS = $(SYSTEMD_LIBS)
-ELOG_YAML ?= xyz/openbmc_project/Example/Elog.errors.yaml
ELOG_MAKO ?= elog-gen-template.mako.hpp
-ELOG_YAML_DIR ?= tools/example/
+ELOG_YAML_DIR ?= tools/example/xyz/openbmc_project/Example/
ELOG_TEMPLATE_DIR ?= tools/phosphor-logging/templates/
REQ_FILES_TO_GEN ?= ${abs_srcdir}/tools/elog-gen.py\
${abs_srcdir}/$(ELOG_YAML_DIR)/$(ELOG_YAML)\
@@ -36,6 +35,6 @@
EXTRA_DIST = $(REQ_FILES_TO_GEN)
elog-gen.hpp: $(REQ_FILES_TO_GEN)
- $(AM_V_at)${abs_srcdir}/tools/elog-gen.py -r ${abs_srcdir}/${ELOG_YAML_DIR} -t ${abs_srcdir}/${ELOG_TEMPLATE_DIR} -e $(ELOG_YAML) -m $(ELOG_MAKO) -o ${abs_srcdir}/elog-gen.hpp
+ $(AM_V_at)${abs_srcdir}/tools/elog-gen.py -y ${abs_srcdir}/${ELOG_YAML_DIR} -t ${abs_srcdir}/${ELOG_TEMPLATE_DIR} -m $(ELOG_MAKO) -o ${abs_srcdir}/elog-gen.hpp
SUBDIRS = test
diff --git a/logging_test.cpp b/logging_test.cpp
index 55d7d45..b781482 100644
--- a/logging_test.cpp
+++ b/logging_test.cpp
@@ -75,21 +75,21 @@
const char *test_string = "/tmp/test_string/";
try
{
- elog<xyz::openbmc_project::Example::Error::TestErrorOne>(
- xyz::openbmc_project::Example::Error::TestErrorOne::
+ elog<example::xyz::openbmc_project::Example::TestErrorOne>(
+ example::xyz::openbmc_project::Example::TestErrorOne::
ERRNUM(number),
- xyz::openbmc_project::Example::Error::TestErrorOne::
+ example::xyz::openbmc_project::Example::TestErrorOne::
FILE_PATH(test_string),
- xyz::openbmc_project::Example::Error::TestErrorOne::
+ example::xyz::openbmc_project::Example::TestErrorOne::
FILE_NAME("elog_test_3.txt"));
}
- catch (elogException<xyz::openbmc_project::Example::Error::TestErrorOne>& e)
+ catch (elogException<example::xyz::openbmc_project::Example::TestErrorOne>& e)
{
std::cout << "elog exception caught: " << e.what() << std::endl;
}
// Reduce our error namespaces
- using namespace xyz::openbmc_project::Example::Error;
+ using namespace example::xyz::openbmc_project::Example;
// Now read back and verify our data made it into the journal
std::stringstream stream;
diff --git a/tools/elog-gen.py b/tools/elog-gen.py
index c72aa98..d10c026 100755
--- a/tools/elog-gen.py
+++ b/tools/elog-gen.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
r"""
-This script will parse the input error log yaml file and generate
+This script will parse error log yaml file(s) and generate
a header file which will then be used by the error logging client and
server to collect and validate the error information generated by the
openbmc software components.
@@ -9,7 +9,6 @@
This code uses a mako template to provide the basic template of the header
file we're going to generate. We then call it with information from the
yaml to generate the header file.
-
"""
from mako.template import Template
@@ -19,6 +18,20 @@
import os
+def get_error_yaml_files(i_yaml_dir):
+ yaml_files = filter(
+ lambda file: file.endswith('.errors.yaml'),
+ os.listdir(i_yaml_dir))
+ return yaml_files
+
+
+def get_meta_yaml_file(i_error_yaml_file):
+ # the meta data will be defined in file name where we replace
+ # <Interface>.errors.yaml with <Interface>.metadata.yaml
+ meta_yaml = i_error_yaml_file.replace("errors", "metadata")
+ return meta_yaml
+
+
def get_cpp_type(i_type):
typeMap = {
'int16': 'int16_t',
@@ -34,31 +47,83 @@
return typeMap[i_type]
-def gen_elog_hpp(i_rootdir, i_elog_yaml, i_elog_meta_yaml,
- i_input_mako, i_output_hpp):
+def gen_elog_hpp(i_yaml_dir, i_output_hpp,
+ i_template_dir, i_elog_mako, i_error_namespace):
r"""
- Read the input yaml file, grab the relevant data and call the mako
- template to generate the header file.
+ Read yaml file(s) under input yaml dir, grab the relevant data and call
+ the mako template to generate the output header file.
Description of arguments:
- i_rootdir base directory to search for yaml files
- i_elog_yaml yaml file describing the error logs
- i_elog_meta_yaml yaml file describing the meta data for elogs
- i_input_mako input mako template file to use
- i_output_hpp header file to output the generated code to
+ i_yaml_dir directory containing error yaml files
+ i_output_hpp name of the to be generated output hpp
+ i_template_dir directory containing error mako templates
+ i_elog_mako error mako template to render
"""
# Input parameters to mako template
- errors = dict() # Main error codes
+ errors = list() # Main error codes
error_msg = dict() # Error msg that corresponds to error code
error_lvl = dict() # Error code log level (debug, info, error, ...)
meta = list() # The meta data names associated (ERRNO, FILE_NAME, ...)
meta_data = dict() # The meta data info (type, format)
- # see elog.yaml for reference
- ifile = yaml.safe_load(open("/".join((i_rootdir, i_elog_yaml))))
+ error_yamls = get_error_yaml_files(i_yaml_dir)
+
+ for error_yaml in error_yamls:
+ # Verify the error yaml file
+ error_yaml = "/".join((i_yaml_dir, error_yaml))
+ if (not (os.path.isfile(error_yaml))):
+ print "Can not find input yaml file " + error_yaml
+ exit(1)
+
+ # Verify the metadata yaml file
+ meta_yaml = get_meta_yaml_file(error_yaml)
+ if (not (os.path.isfile(meta_yaml))):
+ print "Can not find meta yaml file " + meta_yaml
+ exit(1)
+
+ # Verify the input mako file
+ template_path = "/".join((i_template_dir, i_elog_mako))
+ if (not (os.path.isfile(template_path))):
+ print "Can not find input template file " + template_path
+ exit(1)
+
+ get_elog_data(error_yaml,
+ meta_yaml,
+ # 3rd arg is a tuple
+ (errors,
+ error_msg,
+ error_lvl,
+ meta,
+ meta_data))
+
+ # Load the mako template and call it with the required data
+ yaml_dir = i_yaml_dir.strip("./")
+ yaml_dir = yaml_dir.strip("../")
+ template = Template(filename=template_path)
+ f = open(i_output_hpp, 'w')
+ f.write(template.render(
+ errors=errors, error_msg=error_msg,
+ error_lvl=error_lvl, meta=meta,
+ meta_data=meta_data, error_namespace=i_error_namespace))
+ f.close()
+
+
+def get_elog_data(i_elog_yaml,
+ i_elog_meta_yaml,
+ o_elog_data):
+ r"""
+ Parse the error and metadata yaml files in order to pull out
+ error metadata.
+
+ Description of arguments:
+ i_elog_yaml error yaml file
+ i_elog_meta_yaml metadata yaml file
+ o_elog_data error metadata
+ """
+ errors, error_msg, error_lvl, meta, meta_data = o_elog_data
+ ifile = yaml.safe_load(open(i_elog_yaml))
mfile = yaml.safe_load(open(i_elog_meta_yaml))
- err_count = 0
for i in ifile:
match = None
# Find the corresponding meta data for this entry
@@ -70,7 +135,7 @@
print "Error - Did not find meta data for " + i['name']
exit(1)
# Grab the main error and it's info
- errors[err_count] = i['name']
+ errors.append(i['name'])
error_msg[i['name']] = i['description']
error_lvl[i['name']] = match['level']
tmp_meta = []
@@ -83,7 +148,6 @@
meta_data[str_short]['str_short'] = str_short
meta_data[str_short]['type'] = get_cpp_type(j['type'])
meta.append(tmp_meta)
- err_count += 1
# Debug
# for i in errors:
@@ -93,22 +157,10 @@
# print " META: "
# print meta[i]
- # Load the mako template and call it with the required data
- mytemplate = Template(filename=i_input_mako)
- f = open(i_output_hpp, 'w')
- f.write(mytemplate.render(errors=errors, error_msg=error_msg,
- error_lvl=error_lvl, meta=meta,
- meta_data=meta_data, elog_yaml=i_elog_yaml))
- f.close()
-
def main(i_args):
parser = OptionParser()
- parser.add_option("-e", "--elog", dest="elog_yaml",
- default="xyz/openbmc_project/Example/Elog.errors.yaml",
- help="input error yaml file to parse")
-
parser.add_option("-m", "--mako", dest="elog_mako",
default="elog-gen-template.mako.hpp",
help="input mako template file to use")
@@ -117,41 +169,25 @@
default="elog-gen.hpp",
help="output hpp to generate, elog-gen.hpp is default")
- parser.add_option("-r", "--rootdir", dest="rootdir",
- default="example",
+ parser.add_option("-y", "--yamldir", dest="yamldir",
+ default="./example/xyz/openbmc_project/Example",
help="Base directory of yaml files to process")
parser.add_option("-t", "--templatedir", dest="templatedir",
default="phosphor-logging/templates/",
help="Base directory of files to process")
+ parser.add_option("-n", "--namespace", dest="error_namespace",
+ default="example/xyz/openbmc_project/Example",
+ help="Error d-bus namespace")
+
(options, args) = parser.parse_args(i_args)
- # Verify the input yaml file
- yaml_path = "/".join((options.rootdir, options.elog_yaml))
- if (not (os.path.isfile(yaml_path))):
- print "Can not find input yaml file " + yaml_path
- exit(1)
-
- # the meta data will be defined in a similar file name where we replace
- # <Interface>.errors.yaml with <Interface>.metadata.yaml
- meta_file = options.elog_yaml.replace("errors", "metadata")
- meta_file = "/".join((options.rootdir, meta_file))
- if (not (os.path.isfile(meta_file))):
- print "Can not find meta yaml file " + meta_file
- exit(1)
-
- # Verify the input mako file
- template_path = "/".join((options.templatedir, options.elog_mako))
- if (not (os.path.isfile(template_path))):
- print "Can not find input template file " + template_path
- exit(1)
-
- gen_elog_hpp(options.rootdir,
- options.elog_yaml,
- meta_file,
- template_path,
- options.output_hpp)
+ gen_elog_hpp(options.yamldir,
+ options.output_hpp,
+ options.templatedir,
+ options.elog_mako,
+ options.error_namespace)
# Only run if it's a script
if __name__ == '__main__':
diff --git a/tools/example/xyz/openbmc_project/Example/Foo.errors.yaml b/tools/example/xyz/openbmc_project/Example/Foo.errors.yaml
new file mode 100644
index 0000000..73fe62b
--- /dev/null
+++ b/tools/example/xyz/openbmc_project/Example/Foo.errors.yaml
@@ -0,0 +1,2 @@
+- name: Foo
+ description: this is test error Foo
diff --git a/tools/example/xyz/openbmc_project/Example/Foo.metadata.yaml b/tools/example/xyz/openbmc_project/Example/Foo.metadata.yaml
new file mode 100644
index 0000000..2ac0532
--- /dev/null
+++ b/tools/example/xyz/openbmc_project/Example/Foo.metadata.yaml
@@ -0,0 +1,5 @@
+- name: Foo
+ level: INFO
+ meta:
+ - str: "FOO_DATA=%s"
+ type: string
diff --git a/tools/phosphor-logging/templates/elog-gen-template.mako.hpp b/tools/phosphor-logging/templates/elog-gen-template.mako.hpp
index 5c11c1b..1ff9150 100644
--- a/tools/phosphor-logging/templates/elog-gen-template.mako.hpp
+++ b/tools/phosphor-logging/templates/elog-gen-template.mako.hpp
@@ -15,21 +15,22 @@
namespace logging
{
- % for a in errors:
+ % for index, name in enumerate(errors):
<%
- namespaces = elog_yaml.split('/')
- namespaces.pop()
- classname = errors[a]
+ namespaces = error_namespace.split('/')
+ ## In case someone provided a error_namespace ending with '/', remove the
+ ## last split string, which would be an empty string.
+ if not namespaces[-1]:
+ namespaces = namespaces[:-1]
+ classname = name
%>\
% for s in namespaces:
namespace ${s}
{
% endfor
-namespace Error
-{
namespace _${classname}
{
- % for b in meta[a]:
+ % for b in meta[index]:
struct ${b}
{
static constexpr auto str = "${meta_data[b]['str']}";
@@ -41,18 +42,17 @@
% endfor
} // namespace _${classname}
-<% meta_string = ', '.join(meta[a]) %>
+<% meta_string = ', '.join(meta[index]) %>
struct ${classname}
{
- static constexpr auto err_code = "${errors[a]}";
- static constexpr auto err_msg = "${error_msg[errors[a]]}";
- static constexpr auto L = level::${error_lvl[errors[a]]};
- % for b in meta[a]:
+ static constexpr auto err_code = "${name}";
+ static constexpr auto err_msg = "${error_msg[name]}";
+ static constexpr auto L = level::${error_lvl[name]};
+ % for b in meta[index]:
using ${b} = _${classname}::${b};
% endfor
using metadata_types = std::tuple<${meta_string}>;
};
-} // namespace Error
% for s in reversed(namespaces):
} // namespace ${s}
% endfor
diff --git a/tools/phosphor-logging/templates/elog-lookup-template.mako.cpp b/tools/phosphor-logging/templates/elog-lookup-template.mako.cpp
index a96760e..be4ff96 100644
--- a/tools/phosphor-logging/templates/elog-lookup-template.mako.cpp
+++ b/tools/phosphor-logging/templates/elog-lookup-template.mako.cpp
@@ -16,7 +16,7 @@
std::map<std::string,std::vector<std::string>> g_errMetaMap = {
% for a in errors:
<% meta_string = '\",\"'.join(meta[a]) %> \
- {"${errors[a]}",{"${meta_string}"}},
+ {"${a}",{"${meta_string}"}},
% endfor
};