blob: ede916a279a2f51b67bc35f1370547da7b243410 [file] [log] [blame]
Matt Spinlerd9c2fea2020-03-05 16:53:41 -06001#!/usr/bin/env python3
Andrew Geisslerc830e0f2016-10-18 12:51:29 -05002
3r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -06004This script will parse error log yaml file(s) and generate
Andrew Geisslerc830e0f2016-10-18 12:51:29 -05005a 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.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -050012"""
13
14from mako.template import Template
15from optparse import OptionParser
16import yaml
17import sys
18import os
19
Andrew Geissler184690d2016-11-03 08:06:31 -050020
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060021def order_inherited_errors(i_errors, i_parents):
22 # the ordered list of errors
23 errors = list()
24 has_inheritance = False
25 for error in i_errors:
26 if(i_parents[error] is not None):
27 has_inheritance = True
28 break
29
30 if(has_inheritance):
31 # Order the error codes list such that an error is never placed
32 # before it's parent. This way generated code can ensure parent
Gunnar Millsdeae3ca2017-10-25 17:22:22 -050033 # definitions precede child error definitions.
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060034 while(len(errors) < len(i_errors)):
35 for error in i_errors:
36 if(error in errors):
37 # already ordererd
38 continue
39 if((not i_parents[error]) or (i_parents[error] in errors)):
40 # parent present, or has no parent, either way this error
41 # can be added
42 errors.append(error)
43 else:
44 # no inherited errors
45 errors = i_errors
46
47 return errors
48
49
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060050def check_error_inheritance(i_errors, i_parents):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060051 for error in i_errors:
52 if(i_parents[error] and (i_parents[error] not in i_errors)):
Patrick Williams6f299132017-02-16 13:27:39 -060053 print(error + " inherits " + i_parents[error] +
54 " but the latter is not defined")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060055 return False
56 return True
57
58
Adriana Kobylak465aaec2017-02-20 11:58:03 -060059# Return the yaml files with their directory structure plus the file name
60# without the yaml extension, which will be used to set the namespaces.
61# Ex: file xyz/openbmc_project/Error/Callout/Device.errors.yaml
62# will have namespce xyz/openbmc_project/Error/Callout/Device
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060063def get_error_yaml_files(i_yaml_dir, i_test_dir):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060064 yaml_files = dict()
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060065 if i_yaml_dir != "None":
66 for root, dirs, files in os.walk(i_yaml_dir):
Matt Spinlerd9c2fea2020-03-05 16:53:41 -060067 for files in \
68 [file for file in files if file.endswith('.errors.yaml')]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060069 splitdir = root.split(i_yaml_dir)[1] + "/" + files[:-12]
70 if splitdir.startswith("/"):
71 splitdir = splitdir[1:]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060072 yaml_files[(os.path.join(root, files))] = splitdir
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060073 for root, dirs, files in os.walk(i_test_dir):
Matt Spinlerd9c2fea2020-03-05 16:53:41 -060074 for files in [file for file in files if file.endswith('.errors.yaml')]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060075 splitdir = root.split(i_test_dir)[1] + "/" + files[:-12]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060076 yaml_files[(os.path.join(root, files))] = splitdir
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060077 return yaml_files
78
79
80def get_meta_yaml_file(i_error_yaml_file):
81 # the meta data will be defined in file name where we replace
82 # <Interface>.errors.yaml with <Interface>.metadata.yaml
83 meta_yaml = i_error_yaml_file.replace("errors", "metadata")
84 return meta_yaml
85
86
Deepak Kodihalli99161192017-01-16 04:00:07 -060087def get_cpp_type(i_type):
88 typeMap = {
Lei YUcea3f892020-12-03 14:27:10 +080089 'boolean': 'bool',
90 'int8': 'int8_t',
Deepak Kodihalli99161192017-01-16 04:00:07 -060091 'int16': 'int16_t',
92 'int32': 'int32_t',
93 'int64': 'int64_t',
Lei YUcea3f892020-12-03 14:27:10 +080094 'uint8': 'uint8_t',
Deepak Kodihalli99161192017-01-16 04:00:07 -060095 'uint16': 'uint16_t',
96 'uint32': 'uint32_t',
97 'uint64': 'uint64_t',
98 'double': 'double',
99 # const char* aids usage of constexpr
100 'string': 'const char*'}
101
102 return typeMap[i_type]
103
104
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600105def gen_elog_hpp(i_yaml_dir, i_test_dir, i_output_hpp,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600106 i_template_dir, i_elog_mako):
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500107 r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600108 Read yaml file(s) under input yaml dir, grab the relevant data and call
109 the mako template to generate the output header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500110
111 Description of arguments:
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600112 i_yaml_dir directory containing base error yaml files
113 i_test_dir directory containing test error yaml files
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600114 i_output_hpp name of the to be generated output hpp
115 i_template_dir directory containing error mako templates
116 i_elog_mako error mako template to render
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500117 """
118
119 # Input parameters to mako template
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600120 errors = list() # Main error codes
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500121 error_msg = dict() # Error msg that corresponds to error code
122 error_lvl = dict() # Error code log level (debug, info, error, ...)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600123 meta = dict() # The meta data names associated (ERRNO, FILE_NAME, ...)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500124 meta_data = dict() # The meta data info (type, format)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600125 parents = dict()
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600126 metadata_process = dict() # metadata that have the 'process' keyword set
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500127
Patrick Williams7dc8c3b2021-04-17 07:22:48 -0500128 # Verify the input mako file
129 template_path = os.path.join(i_template_dir, i_elog_mako)
130 if (not (os.path.isfile(template_path))):
131 print("Cannot find input template file " + template_path)
132 exit(1)
133 template_path = os.path.abspath(template_path)
134
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600135 error_yamls = get_error_yaml_files(i_yaml_dir, i_test_dir)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600136
137 for error_yaml in error_yamls:
138 # Verify the error yaml file
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600139 if (not (os.path.isfile(error_yaml))):
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500140 print("Cannot find input yaml file " + error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600141 exit(1)
142
143 # Verify the metadata yaml file
144 meta_yaml = get_meta_yaml_file(error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600145
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600146 get_elog_data(error_yaml,
147 meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600148 error_yamls[error_yaml],
149 # Last arg is a tuple
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600150 (errors,
151 error_msg,
152 error_lvl,
153 meta,
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600154 meta_data,
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600155 parents,
156 metadata_process))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600157
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600158 if(not check_error_inheritance(errors, parents)):
Patrick Williams6f299132017-02-16 13:27:39 -0600159 print("Error - failed to validate error inheritance")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600160 exit(1)
161
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600162 errors = order_inherited_errors(errors, parents)
163
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600164 # Load the mako template and call it with the required data
165 yaml_dir = i_yaml_dir.strip("./")
166 yaml_dir = yaml_dir.strip("../")
167 template = Template(filename=template_path)
168 f = open(i_output_hpp, 'w')
169 f.write(template.render(
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600170 errors=errors,
171 error_msg=error_msg,
172 error_lvl=error_lvl,
173 meta=meta,
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600174 meta_data=meta_data,
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600175 parents=parents,
176 metadata_process=metadata_process))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600177 f.close()
178
Patrick Williamsbb6af862021-04-16 13:58:01 -0500179
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600180def get_elog_data(i_elog_yaml,
181 i_elog_meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600182 i_namespace,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600183 o_elog_data):
184 r"""
185 Parse the error and metadata yaml files in order to pull out
186 error metadata.
187
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500188 Use default values if metadata yaml file is not found.
189
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600190 Description of arguments:
191 i_elog_yaml error yaml file
192 i_elog_meta_yaml metadata yaml file
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600193 i_namespace namespace data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600194 o_elog_data error metadata
195 """
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600196 (errors, error_msg, error_lvl, meta,
197 meta_data, parents, metadata_process) = o_elog_data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600198 ifile = yaml.safe_load(open(i_elog_yaml))
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500199
Patrick Williamsbb6af862021-04-16 13:58:01 -0500200 # for all the errors in error yaml file
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500201 for error in ifile:
202 if 'name' not in error:
Patrick Williams4952aa62017-06-03 15:47:55 -0500203 print("Error - Did not find name in entry %s in file %s " % (
204 str(error), i_elog_yaml))
Andrew Geisslere8596302016-11-21 16:06:53 -0600205 exit(1)
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500206 fullname = i_namespace.replace('/', '.') + ('.') + error['name']
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600207 errors.append(fullname)
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500208
209 if 'description' in error:
210 error_msg[fullname] = error['description'].strip()
211
Patrick Williamsbb6af862021-04-16 13:58:01 -0500212 # set default values
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500213 error_lvl[fullname] = "ERR"
214 parents[fullname] = None
215
Patrick Williamsbb6af862021-04-16 13:58:01 -0500216 # check if meta data yaml file is found
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500217 if not os.path.isfile(i_elog_meta_yaml):
218 continue
219 mfile = yaml.safe_load(open(i_elog_meta_yaml))
220
221 # Find the meta data entry
222 match = None
223 for meta_entry in mfile:
224 if meta_entry['name'] == error['name']:
225 match = meta_entry
226 break
227
228 if match is None:
William A. Kennington IIIb17e8762018-10-04 18:58:14 -0700229 print("Error - Did not find error named %s in %s" % (
230 error['name'], i_elog_meta_yaml))
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500231 continue
232
233 error_lvl[fullname] = match.get('level', 'ERR')
234
235 # Get 0th inherited error (current support - single inheritance)
236 if 'inherits' in match:
Patrick Williamsbb6af862021-04-16 13:58:01 -0500237 parents[fullname] = match['inherits'][0]
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500238
Lei YU80aa4762018-07-19 10:29:56 +0800239 # Put all errors in meta[] even the meta is empty
240 # so that child errors could inherits such error without meta
241 tmp_meta = []
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500242 if 'meta' in match:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500243 # grab all the meta data fields and info
244 for i in match['meta']:
245 str_short = i['str'].split('=')[0]
Deepak Kodihalli7924b172017-03-08 00:04:33 -0600246 tmp_meta.append(str_short)
247 meta_data[str_short] = {}
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500248 meta_data[str_short]['str'] = i['str']
Deepak Kodihalli7924b172017-03-08 00:04:33 -0600249 meta_data[str_short]['str_short'] = str_short
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500250 meta_data[str_short]['type'] = get_cpp_type(i['type'])
Patrick Williamsbb6af862021-04-16 13:58:01 -0500251 if ('process' in i) and (i['process'] is True):
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600252 metadata_process[str_short] = fullname + "." + str_short
Lei YU80aa4762018-07-19 10:29:56 +0800253 meta[fullname] = tmp_meta
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500254
255 # Debug
Andrew Geissler184690d2016-11-03 08:06:31 -0500256 # for i in errors:
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600257 # print "ERROR: " + errors[i]
258 # print " MSG: " + error_msg[errors[i]]
259 # print " LVL: " + error_lvl[errors[i]]
260 # print " META: "
261 # print meta[i]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500262
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500263
264def main(i_args):
265 parser = OptionParser()
266
Andrew Geissler184690d2016-11-03 08:06:31 -0500267 parser.add_option("-m", "--mako", dest="elog_mako",
268 default="elog-gen-template.mako.hpp",
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600269 help="input mako template file to use")
Andrew Geissler184690d2016-11-03 08:06:31 -0500270
271 parser.add_option("-o", "--output", dest="output_hpp",
Adriana Kobylakebd59fa2017-02-06 20:55:39 -0600272 default="elog-errors.hpp",
273 help="output hpp to generate, elog-errors.hpp default")
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500274
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600275 parser.add_option("-y", "--yamldir", dest="yamldir",
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600276 default="None",
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600277 help="Base directory of yaml files to process")
278
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600279 parser.add_option("-u", "--testdir", dest="testdir",
280 default="./tools/example/",
281 help="Unit test directory of yaml files to process")
282
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600283 parser.add_option("-t", "--templatedir", dest="templatedir",
284 default="phosphor-logging/templates/",
285 help="Base directory of files to process")
286
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500287 (options, args) = parser.parse_args(i_args)
288
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600289 gen_elog_hpp(options.yamldir,
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600290 options.testdir,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600291 options.output_hpp,
292 options.templatedir,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600293 options.elog_mako)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500294
Patrick Williamsbb6af862021-04-16 13:58:01 -0500295
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500296# Only run if it's a script
297if __name__ == '__main__':
Andrew Geissler184690d2016-11-03 08:06:31 -0500298 main(sys.argv[1:])