blob: 2b7fc49f5e23c0b169de2d9681d6d1c1fe9ebd59 [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
Andrew Geisslerc830e0f2016-10-18 12:51:29 -050014import os
Patrick Williamsd27675d2022-12-08 06:18:00 -060015import sys
16from optparse import OptionParser
17
18from mako.template import Template
19
20import yaml
Andrew Geisslerc830e0f2016-10-18 12:51:29 -050021
Andrew Geissler184690d2016-11-03 08:06:31 -050022
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060023def order_inherited_errors(i_errors, i_parents):
24 # the ordered list of errors
25 errors = list()
26 has_inheritance = False
27 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050028 if i_parents[error] is not None:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060029 has_inheritance = True
30 break
31
Patrick Williamse6555f52022-08-04 13:56:17 -050032 if has_inheritance:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060033 # Order the error codes list such that an error is never placed
34 # before it's parent. This way generated code can ensure parent
Gunnar Millsdeae3ca2017-10-25 17:22:22 -050035 # definitions precede child error definitions.
Patrick Williamse6555f52022-08-04 13:56:17 -050036 while len(errors) < len(i_errors):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060037 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050038 if error in errors:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060039 # already ordererd
40 continue
Patrick Williamse6555f52022-08-04 13:56:17 -050041 if (not i_parents[error]) or (i_parents[error] in errors):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060042 # parent present, or has no parent, either way this error
43 # can be added
44 errors.append(error)
45 else:
46 # no inherited errors
47 errors = i_errors
48
49 return errors
50
51
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060052def check_error_inheritance(i_errors, i_parents):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060053 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050054 if i_parents[error] and (i_parents[error] not in i_errors):
55 print(
56 error
57 + " inherits "
58 + i_parents[error]
59 + " but the latter is not defined"
60 )
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060061 return False
62 return True
63
64
Adriana Kobylak465aaec2017-02-20 11:58:03 -060065# Return the yaml files with their directory structure plus the file name
66# without the yaml extension, which will be used to set the namespaces.
67# Ex: file xyz/openbmc_project/Error/Callout/Device.errors.yaml
68# will have namespce xyz/openbmc_project/Error/Callout/Device
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060069def get_error_yaml_files(i_yaml_dir, i_test_dir):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060070 yaml_files = dict()
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060071 if i_yaml_dir != "None":
72 for root, dirs, files in os.walk(i_yaml_dir):
Patrick Williamse6555f52022-08-04 13:56:17 -050073 for files in [
74 file for file in files if file.endswith(".errors.yaml")
75 ]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060076 splitdir = root.split(i_yaml_dir)[1] + "/" + files[:-12]
77 if splitdir.startswith("/"):
78 splitdir = splitdir[1:]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060079 yaml_files[(os.path.join(root, files))] = splitdir
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060080 for root, dirs, files in os.walk(i_test_dir):
Patrick Williamse6555f52022-08-04 13:56:17 -050081 for files in [file for file in files if file.endswith(".errors.yaml")]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060082 splitdir = root.split(i_test_dir)[1] + "/" + files[:-12]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060083 yaml_files[(os.path.join(root, files))] = splitdir
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060084 return yaml_files
85
86
87def get_meta_yaml_file(i_error_yaml_file):
88 # the meta data will be defined in file name where we replace
89 # <Interface>.errors.yaml with <Interface>.metadata.yaml
90 meta_yaml = i_error_yaml_file.replace("errors", "metadata")
91 return meta_yaml
92
93
Deepak Kodihalli99161192017-01-16 04:00:07 -060094def get_cpp_type(i_type):
95 typeMap = {
Patrick Williamse6555f52022-08-04 13:56:17 -050096 "boolean": "bool",
97 "int8": "int8_t",
98 "int16": "int16_t",
99 "int32": "int32_t",
100 "int64": "int64_t",
101 "uint8": "uint8_t",
102 "uint16": "uint16_t",
103 "uint32": "uint32_t",
104 "uint64": "uint64_t",
105 "double": "double",
Deepak Kodihalli99161192017-01-16 04:00:07 -0600106 # const char* aids usage of constexpr
Patrick Williamse6555f52022-08-04 13:56:17 -0500107 "string": "const char*",
108 }
Deepak Kodihalli99161192017-01-16 04:00:07 -0600109
110 return typeMap[i_type]
111
112
Patrick Williamse6555f52022-08-04 13:56:17 -0500113def gen_elog_hpp(
114 i_yaml_dir, i_test_dir, i_output_hpp, i_template_dir, i_elog_mako
115):
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500116 r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600117 Read yaml file(s) under input yaml dir, grab the relevant data and call
118 the mako template to generate the output header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500119
120 Description of arguments:
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600121 i_yaml_dir directory containing base error yaml files
122 i_test_dir directory containing test error yaml files
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600123 i_output_hpp name of the to be generated output hpp
124 i_template_dir directory containing error mako templates
125 i_elog_mako error mako template to render
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500126 """
127
128 # Input parameters to mako template
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600129 errors = list() # Main error codes
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500130 error_msg = dict() # Error msg that corresponds to error code
131 error_lvl = dict() # Error code log level (debug, info, error, ...)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600132 meta = dict() # The meta data names associated (ERRNO, FILE_NAME, ...)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500133 meta_data = dict() # The meta data info (type, format)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600134 parents = dict()
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600135 metadata_process = dict() # metadata that have the 'process' keyword set
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500136
Patrick Williams7dc8c3b2021-04-17 07:22:48 -0500137 # Verify the input mako file
138 template_path = os.path.join(i_template_dir, i_elog_mako)
Patrick Williamse6555f52022-08-04 13:56:17 -0500139 if not (os.path.isfile(template_path)):
Patrick Williams7dc8c3b2021-04-17 07:22:48 -0500140 print("Cannot find input template file " + template_path)
141 exit(1)
142 template_path = os.path.abspath(template_path)
143
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600144 error_yamls = get_error_yaml_files(i_yaml_dir, i_test_dir)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600145
146 for error_yaml in error_yamls:
147 # Verify the error yaml file
Patrick Williamse6555f52022-08-04 13:56:17 -0500148 if not (os.path.isfile(error_yaml)):
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500149 print("Cannot find input yaml file " + error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600150 exit(1)
151
152 # Verify the metadata yaml file
153 meta_yaml = get_meta_yaml_file(error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600154
Patrick Williamse6555f52022-08-04 13:56:17 -0500155 get_elog_data(
156 error_yaml,
157 meta_yaml,
158 error_yamls[error_yaml],
159 # Last arg is a tuple
160 (
161 errors,
162 error_msg,
163 error_lvl,
164 meta,
165 meta_data,
166 parents,
167 metadata_process,
168 ),
169 )
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600170
Patrick Williamse6555f52022-08-04 13:56:17 -0500171 if not check_error_inheritance(errors, parents):
Patrick Williams6f299132017-02-16 13:27:39 -0600172 print("Error - failed to validate error inheritance")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600173 exit(1)
174
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600175 errors = order_inherited_errors(errors, parents)
176
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600177 # Load the mako template and call it with the required data
178 yaml_dir = i_yaml_dir.strip("./")
179 yaml_dir = yaml_dir.strip("../")
180 template = Template(filename=template_path)
Patrick Williamse6555f52022-08-04 13:56:17 -0500181 f = open(i_output_hpp, "w")
182 f.write(
183 template.render(
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600184 errors=errors,
185 error_msg=error_msg,
186 error_lvl=error_lvl,
187 meta=meta,
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600188 meta_data=meta_data,
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600189 parents=parents,
Patrick Williamse6555f52022-08-04 13:56:17 -0500190 metadata_process=metadata_process,
191 )
192 )
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600193 f.close()
194
Patrick Williamsbb6af862021-04-16 13:58:01 -0500195
Patrick Williamse6555f52022-08-04 13:56:17 -0500196def get_elog_data(i_elog_yaml, i_elog_meta_yaml, i_namespace, o_elog_data):
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600197 r"""
198 Parse the error and metadata yaml files in order to pull out
199 error metadata.
200
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500201 Use default values if metadata yaml file is not found.
202
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600203 Description of arguments:
204 i_elog_yaml error yaml file
205 i_elog_meta_yaml metadata yaml file
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600206 i_namespace namespace data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600207 o_elog_data error metadata
208 """
Patrick Williamse6555f52022-08-04 13:56:17 -0500209 (
210 errors,
211 error_msg,
212 error_lvl,
213 meta,
214 meta_data,
215 parents,
216 metadata_process,
217 ) = o_elog_data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600218 ifile = yaml.safe_load(open(i_elog_yaml))
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500219
Patrick Williamsbb6af862021-04-16 13:58:01 -0500220 # for all the errors in error yaml file
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500221 for error in ifile:
Patrick Williamse6555f52022-08-04 13:56:17 -0500222 if "name" not in error:
223 print(
224 "Error - Did not find name in entry %s in file %s "
225 % (str(error), i_elog_yaml)
226 )
Andrew Geisslere8596302016-11-21 16:06:53 -0600227 exit(1)
Patrick Williamsd27675d2022-12-08 06:18:00 -0600228 fullname = i_namespace.replace("/", ".") + "." + error["name"]
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600229 errors.append(fullname)
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500230
Patrick Williamse6555f52022-08-04 13:56:17 -0500231 if "description" in error:
232 error_msg[fullname] = error["description"].strip()
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500233
Patrick Williamsbb6af862021-04-16 13:58:01 -0500234 # set default values
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500235 error_lvl[fullname] = "ERR"
236 parents[fullname] = None
237
Patrick Williamsbb6af862021-04-16 13:58:01 -0500238 # check if meta data yaml file is found
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500239 if not os.path.isfile(i_elog_meta_yaml):
240 continue
241 mfile = yaml.safe_load(open(i_elog_meta_yaml))
242
243 # Find the meta data entry
244 match = None
245 for meta_entry in mfile:
Patrick Williamse6555f52022-08-04 13:56:17 -0500246 if meta_entry["name"] == error["name"]:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500247 match = meta_entry
248 break
249
250 if match is None:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500251 continue
252
Patrick Williamse6555f52022-08-04 13:56:17 -0500253 error_lvl[fullname] = match.get("level", "ERR")
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500254
255 # Get 0th inherited error (current support - single inheritance)
Patrick Williamse6555f52022-08-04 13:56:17 -0500256 if "inherits" in match:
257 parents[fullname] = match["inherits"][0]
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500258
Lei YU80aa4762018-07-19 10:29:56 +0800259 # Put all errors in meta[] even the meta is empty
260 # so that child errors could inherits such error without meta
261 tmp_meta = []
Patrick Williamse6555f52022-08-04 13:56:17 -0500262 if "meta" in match:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500263 # grab all the meta data fields and info
Patrick Williamse6555f52022-08-04 13:56:17 -0500264 for i in match["meta"]:
265 str_short = i["str"].split("=")[0]
Deepak Kodihalli7924b172017-03-08 00:04:33 -0600266 tmp_meta.append(str_short)
267 meta_data[str_short] = {}
Patrick Williamse6555f52022-08-04 13:56:17 -0500268 meta_data[str_short]["str"] = i["str"]
269 meta_data[str_short]["str_short"] = str_short
270 meta_data[str_short]["type"] = get_cpp_type(i["type"])
271 if ("process" in i) and (i["process"] is True):
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600272 metadata_process[str_short] = fullname + "." + str_short
Lei YU80aa4762018-07-19 10:29:56 +0800273 meta[fullname] = tmp_meta
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500274
275 # Debug
Andrew Geissler184690d2016-11-03 08:06:31 -0500276 # for i in errors:
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600277 # print "ERROR: " + errors[i]
278 # print " MSG: " + error_msg[errors[i]]
279 # print " LVL: " + error_lvl[errors[i]]
280 # print " META: "
281 # print meta[i]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500282
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500283
284def main(i_args):
285 parser = OptionParser()
286
Patrick Williamse6555f52022-08-04 13:56:17 -0500287 parser.add_option(
288 "-m",
289 "--mako",
290 dest="elog_mako",
291 default="elog-gen-template.mako.hpp",
292 help="input mako template file to use",
293 )
Andrew Geissler184690d2016-11-03 08:06:31 -0500294
Patrick Williamse6555f52022-08-04 13:56:17 -0500295 parser.add_option(
296 "-o",
297 "--output",
298 dest="output_hpp",
299 default="elog-errors.hpp",
300 help="output hpp to generate, elog-errors.hpp default",
301 )
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500302
Patrick Williamse6555f52022-08-04 13:56:17 -0500303 parser.add_option(
304 "-y",
305 "--yamldir",
306 dest="yamldir",
307 default="None",
308 help="Base directory of yaml files to process",
309 )
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600310
Patrick Williamse6555f52022-08-04 13:56:17 -0500311 parser.add_option(
312 "-u",
313 "--testdir",
314 dest="testdir",
315 default="./tools/example/",
316 help="Unit test directory of yaml files to process",
317 )
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600318
Patrick Williamse6555f52022-08-04 13:56:17 -0500319 parser.add_option(
320 "-t",
321 "--templatedir",
322 dest="templatedir",
323 default="phosphor-logging/templates/",
324 help="Base directory of files to process",
325 )
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600326
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500327 (options, args) = parser.parse_args(i_args)
328
Patrick Williamse6555f52022-08-04 13:56:17 -0500329 gen_elog_hpp(
330 options.yamldir,
331 options.testdir,
332 options.output_hpp,
333 options.templatedir,
334 options.elog_mako,
335 )
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500336
Patrick Williamsbb6af862021-04-16 13:58:01 -0500337
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500338# Only run if it's a script
Patrick Williamse6555f52022-08-04 13:56:17 -0500339if __name__ == "__main__":
Andrew Geissler184690d2016-11-03 08:06:31 -0500340 main(sys.argv[1:])