xref: /openbmc/phosphor-logging/tools/elog-gen.py (revision 82b7de7e3211659a3dd323d7a986cfec7a3751ff)
1#!/usr/bin/env python
2
3r"""
4This script will parse error log yaml file(s) and generate
5a header file which will then be used by the error logging client and
6server to collect and validate the error information generated by the
7openbmc software components.
8
9This code uses a mako template to provide the basic template of the header
10file we're going to generate.  We then call it with information from the
11yaml to generate the header file.
12"""
13
14from mako.template import Template
15from optparse import OptionParser
16import yaml
17import sys
18import os
19
20
21def get_error_yaml_files(i_yaml_dir):
22    yaml_files = filter(
23        lambda file: file.endswith('.errors.yaml'),
24        os.listdir(i_yaml_dir))
25    return yaml_files
26
27
28def get_meta_yaml_file(i_error_yaml_file):
29    # the meta data will be defined in file name where we replace
30    # <Interface>.errors.yaml with <Interface>.metadata.yaml
31    meta_yaml = i_error_yaml_file.replace("errors", "metadata")
32    return meta_yaml
33
34
35def get_cpp_type(i_type):
36    typeMap = {
37        'int16': 'int16_t',
38        'int32': 'int32_t',
39        'int64': 'int64_t',
40        'uint16': 'uint16_t',
41        'uint32': 'uint32_t',
42        'uint64': 'uint64_t',
43        'double': 'double',
44        # const char* aids usage of constexpr
45        'string': 'const char*'}
46
47    return typeMap[i_type]
48
49
50def gen_elog_hpp(i_yaml_dir, i_output_hpp,
51                 i_template_dir, i_elog_mako, i_error_namespace):
52    r"""
53    Read  yaml file(s) under input yaml dir, grab the relevant data and call
54    the mako template to generate the output header file.
55
56    Description of arguments:
57    i_yaml_dir                  directory containing error yaml files
58    i_output_hpp                name of the to be generated output hpp
59    i_template_dir              directory containing error mako templates
60    i_elog_mako                 error mako template to render
61    """
62
63    # Input parameters to mako template
64    errors = list()  # Main error codes
65    error_msg = dict()  # Error msg that corresponds to error code
66    error_lvl = dict()  # Error code log level (debug, info, error, ...)
67    meta = list()  # The meta data names associated (ERRNO, FILE_NAME, ...)
68    meta_data = dict()  # The meta data info (type, format)
69    parents = list()
70
71    error_yamls = get_error_yaml_files(i_yaml_dir)
72
73    for error_yaml in error_yamls:
74        # Verify the error yaml file
75        error_yaml = "/".join((i_yaml_dir, error_yaml))
76        if (not (os.path.isfile(error_yaml))):
77            print "Can not find input yaml file " + error_yaml
78            exit(1)
79
80        # Verify the metadata yaml file
81        meta_yaml = get_meta_yaml_file(error_yaml)
82        if (not (os.path.isfile(meta_yaml))):
83            print "Can not find meta yaml file " + meta_yaml
84            exit(1)
85
86        # Verify the input mako file
87        template_path = "/".join((i_template_dir, i_elog_mako))
88        if (not (os.path.isfile(template_path))):
89            print "Can not find input template file " + template_path
90            exit(1)
91
92        get_elog_data(error_yaml,
93                      meta_yaml,
94                      # 3rd arg is a tuple
95                      (errors,
96                       error_msg,
97                       error_lvl,
98                       meta,
99                       meta_data,
100                       parents))
101
102    # Load the mako template and call it with the required data
103    yaml_dir = i_yaml_dir.strip("./")
104    yaml_dir = yaml_dir.strip("../")
105    template = Template(filename=template_path)
106    f = open(i_output_hpp, 'w')
107    f.write(template.render(
108            errors=errors, error_msg=error_msg,
109            error_lvl=error_lvl, meta=meta,
110            meta_data=meta_data, error_namespace=i_error_namespace))
111    f.close()
112
113
114def get_elog_data(i_elog_yaml,
115                  i_elog_meta_yaml,
116                  o_elog_data):
117    r"""
118    Parse the error and metadata yaml files in order to pull out
119    error metadata.
120
121    Description of arguments:
122    i_elog_yaml                 error yaml file
123    i_elog_meta_yaml            metadata yaml file
124    o_elog_data                 error metadata
125    """
126    errors, error_msg, error_lvl, meta, meta_data, parents = o_elog_data
127    ifile = yaml.safe_load(open(i_elog_yaml))
128    mfile = yaml.safe_load(open(i_elog_meta_yaml))
129    for i in ifile:
130        match = None
131        # Find the corresponding meta data for this entry
132        for m in mfile:
133            if m['name'] == i['name']:
134                match = m
135                break
136        if (match is None):
137            print "Error - Did not find meta data for " + i['name']
138            exit(1)
139        # Grab the main error and it's info
140        errors.append(i['name'])
141        parent = None
142        if('inherits' in i):
143            # xyz.openbmc.Foo, we need Foo
144            # Get 0th inherited error (current support - single inheritance)
145            parent = i['inherits'][0].split(".").pop()
146        parents.append(parent)
147        error_msg[i['name']] = i['description']
148        error_lvl[i['name']] = match['level']
149        tmp_meta = []
150        # grab all the meta data fields and info
151        for j in match['meta']:
152            str_short = j['str'].split('=')[0]
153            tmp_meta.append(str_short)
154            meta_data[str_short] = {}
155            meta_data[str_short]['str'] = j['str']
156            meta_data[str_short]['str_short'] = str_short
157            meta_data[str_short]['type'] = get_cpp_type(j['type'])
158        meta.append(tmp_meta)
159
160    # Debug
161    # for i in errors:
162    #   print "ERROR: " + errors[i]
163    #   print " MSG:  " + error_msg[errors[i]]
164    #   print " LVL:  " + error_lvl[errors[i]]
165    #   print " META: "
166    #   print meta[i]
167
168
169def main(i_args):
170    parser = OptionParser()
171
172    parser.add_option("-m", "--mako", dest="elog_mako",
173                      default="elog-gen-template.mako.hpp",
174                      help="input mako template file to use")
175
176    parser.add_option("-o", "--output", dest="output_hpp",
177                      default="elog-gen.hpp",
178                      help="output hpp to generate, elog-gen.hpp is default")
179
180    parser.add_option("-y", "--yamldir", dest="yamldir",
181                      default="./example/xyz/openbmc_project/Example",
182                      help="Base directory of yaml files to process")
183
184    parser.add_option("-t", "--templatedir", dest="templatedir",
185                      default="phosphor-logging/templates/",
186                      help="Base directory of files to process")
187
188    parser.add_option("-n", "--namespace", dest="error_namespace",
189                      default="example/xyz/openbmc_project/Example",
190                      help="Error d-bus namespace")
191
192    (options, args) = parser.parse_args(i_args)
193
194    gen_elog_hpp(options.yamldir,
195                 options.output_hpp,
196                 options.templatedir,
197                 options.elog_mako,
198                 options.error_namespace)
199
200# Only run if it's a script
201if __name__ == '__main__':
202    main(sys.argv[1:])
203