xref: /openbmc/phosphor-logging/tools/elog-gen.py (revision 160d3e0b810f6c5f582c7daf906ce0c99cd4194e)
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
70    error_yamls = get_error_yaml_files(i_yaml_dir)
71
72    for error_yaml in error_yamls:
73        # Verify the error yaml file
74        error_yaml = "/".join((i_yaml_dir, error_yaml))
75        if (not (os.path.isfile(error_yaml))):
76            print "Can not find input yaml file " + error_yaml
77            exit(1)
78
79        # Verify the metadata yaml file
80        meta_yaml = get_meta_yaml_file(error_yaml)
81        if (not (os.path.isfile(meta_yaml))):
82            print "Can not find meta yaml file " + meta_yaml
83            exit(1)
84
85        # Verify the input mako file
86        template_path = "/".join((i_template_dir, i_elog_mako))
87        if (not (os.path.isfile(template_path))):
88            print "Can not find input template file " + template_path
89            exit(1)
90
91        get_elog_data(error_yaml,
92                      meta_yaml,
93                      # 3rd arg is a tuple
94                      (errors,
95                       error_msg,
96                       error_lvl,
97                       meta,
98                       meta_data))
99
100    # Load the mako template and call it with the required data
101    yaml_dir = i_yaml_dir.strip("./")
102    yaml_dir = yaml_dir.strip("../")
103    template = Template(filename=template_path)
104    f = open(i_output_hpp, 'w')
105    f.write(template.render(
106            errors=errors, error_msg=error_msg,
107            error_lvl=error_lvl, meta=meta,
108            meta_data=meta_data, error_namespace=i_error_namespace))
109    f.close()
110
111
112def get_elog_data(i_elog_yaml,
113                  i_elog_meta_yaml,
114                  o_elog_data):
115    r"""
116    Parse the error and metadata yaml files in order to pull out
117    error metadata.
118
119    Description of arguments:
120    i_elog_yaml                 error yaml file
121    i_elog_meta_yaml            metadata yaml file
122    o_elog_data                 error metadata
123    """
124    errors, error_msg, error_lvl, meta, meta_data = o_elog_data
125    ifile = yaml.safe_load(open(i_elog_yaml))
126    mfile = yaml.safe_load(open(i_elog_meta_yaml))
127    for i in ifile:
128        match = None
129        # Find the corresponding meta data for this entry
130        for m in mfile:
131            if m['name'] == i['name']:
132                match = m
133                break
134        if (match is None):
135            print "Error - Did not find meta data for " + i['name']
136            exit(1)
137        # Grab the main error and it's info
138        errors.append(i['name'])
139        error_msg[i['name']] = i['description']
140        error_lvl[i['name']] = match['level']
141        tmp_meta = []
142        # grab all the meta data fields and info
143        for j in match['meta']:
144            str_short = j['str'].split('=')[0]
145            tmp_meta.append(str_short)
146            meta_data[str_short] = {}
147            meta_data[str_short]['str'] = j['str']
148            meta_data[str_short]['str_short'] = str_short
149            meta_data[str_short]['type'] = get_cpp_type(j['type'])
150        meta.append(tmp_meta)
151
152    # Debug
153    # for i in errors:
154    #   print "ERROR: " + errors[i]
155    #   print " MSG:  " + error_msg[errors[i]]
156    #   print " LVL:  " + error_lvl[errors[i]]
157    #   print " META: "
158    #   print meta[i]
159
160
161def main(i_args):
162    parser = OptionParser()
163
164    parser.add_option("-m", "--mako", dest="elog_mako",
165                      default="elog-gen-template.mako.hpp",
166                      help="input mako template file to use")
167
168    parser.add_option("-o", "--output", dest="output_hpp",
169                      default="elog-gen.hpp",
170                      help="output hpp to generate, elog-gen.hpp is default")
171
172    parser.add_option("-y", "--yamldir", dest="yamldir",
173                      default="./example/xyz/openbmc_project/Example",
174                      help="Base directory of yaml files to process")
175
176    parser.add_option("-t", "--templatedir", dest="templatedir",
177                      default="phosphor-logging/templates/",
178                      help="Base directory of files to process")
179
180    parser.add_option("-n", "--namespace", dest="error_namespace",
181                      default="example/xyz/openbmc_project/Example",
182                      help="Error d-bus namespace")
183
184    (options, args) = parser.parse_args(i_args)
185
186    gen_elog_hpp(options.yamldir,
187                 options.output_hpp,
188                 options.templatedir,
189                 options.elog_mako,
190                 options.error_namespace)
191
192# Only run if it's a script
193if __name__ == '__main__':
194    main(sys.argv[1:])
195