diff options
-rw-r--r-- | elog-gen-template.mako.hpp | 48 | ||||
-rw-r--r-- | elog-gen.hpp | 88 | ||||
-rw-r--r-- | elog-gen.py | 96 | ||||
-rw-r--r-- | elog.yaml | 23 | ||||
-rwxr-xr-x | elog_parser.py | 16 | ||||
-rw-r--r-- | logging_test.cpp | 56 |
6 files changed, 254 insertions, 73 deletions
diff --git a/elog-gen-template.mako.hpp b/elog-gen-template.mako.hpp new file mode 100644 index 0000000..8461f70 --- /dev/null +++ b/elog-gen-template.mako.hpp @@ -0,0 +1,48 @@ +## Note that this file is not auto generated, it is what generates the +## elog-gen.hpp file +// This file was autogenerated. Do not edit! +// See elog-gen.py for more details +#pragma once + +#include <tuple> +#include <type_traits> +#include "log.hpp" + +namespace phosphor +{ + +namespace logging +{ + + % for a in errors: +namespace _${errors[a]} +{ + % for b in meta[a]: +struct ${b} +{ + static constexpr auto str = "${meta_data[b]['str']}"; + static constexpr auto str_short = "${meta_data[b]['str_short']}"; + using type = std::tuple<std::decay_t<decltype(str)>,${meta_data[b]['type']}>; + explicit constexpr ${b}(${meta_data[b]['type']} a) : _entry(entry(str, a)) {}; + type _entry; +}; + % endfor + +} // namespace _${errors[a]} +<% meta_string = ', '.join(meta[a]) %> +struct ${errors[a]} +{ + static constexpr auto err_code = "xyz.openbmc_project.logging.${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]: + using ${b} = _${errors[a]}::${b}; + % endfor + using metadata_types = std::tuple<${meta_string}>; +}; + + % endfor + +} // namespace logging + +} // namespace phosphor diff --git a/elog-gen.hpp b/elog-gen.hpp index 3aba8fb..07d0757 100644 --- a/elog-gen.hpp +++ b/elog-gen.hpp @@ -1,4 +1,5 @@ -// this file was autogenerated. do not edit. +// This file was autogenerated. Do not edit! +// See elog-gen.py for more details #pragma once #include <tuple> @@ -11,52 +12,87 @@ namespace phosphor namespace logging { -namespace _file_not_found +namespace _GETSCOM { -struct errnum +struct DEV_ADDR { - static constexpr auto str = "ERRNO=%d"; - static constexpr auto str_short = "ERRNO"; + static constexpr auto str = "DEV_ADDR=0x%.8X"; + static constexpr auto str_short = "DEV_ADDR"; using type = std::tuple<std::decay_t<decltype(str)>,int>; - explicit constexpr errnum(int a) : _entry(entry(str, a)) {}; + explicit constexpr DEV_ADDR(int a) : _entry(entry(str, a)) {}; type _entry; }; +struct DEV_ID +{ + static constexpr auto str = "DEV_ID=%u"; + static constexpr auto str_short = "DEV_ID"; + using type = std::tuple<std::decay_t<decltype(str)>,int>; + explicit constexpr DEV_ID(int a) : _entry(entry(str, a)) {}; + type _entry; +}; +struct DEV_NAME +{ + static constexpr auto str = "DEV_NAME=%s"; + static constexpr auto str_short = "DEV_NAME"; + using type = std::tuple<std::decay_t<decltype(str)>,const char *>; + explicit constexpr DEV_NAME(const char * a) : _entry(entry(str, a)) {}; + type _entry; +}; + +} // namespace _GETSCOM + +struct GETSCOM +{ + static constexpr auto err_code = "xyz.openbmc_project.logging.GETSCOM"; + static constexpr auto err_msg = "Getscom call failed"; + static constexpr auto L = level::ERR; + using DEV_ADDR = _GETSCOM::DEV_ADDR; + using DEV_ID = _GETSCOM::DEV_ID; + using DEV_NAME = _GETSCOM::DEV_NAME; + using metadata_types = std::tuple<DEV_ADDR, DEV_ID, DEV_NAME>; +}; -struct file_path +namespace _FILE_NOT_FOUND +{ +struct ERRNUM +{ + static constexpr auto str = "ERRNUM=0x%.4X"; + static constexpr auto str_short = "ERRNUM"; + using type = std::tuple<std::decay_t<decltype(str)>,int>; + explicit constexpr ERRNUM(int a) : _entry(entry(str, a)) {}; + type _entry; +}; +struct FILE_PATH { static constexpr auto str = "FILE_PATH=%s"; static constexpr auto str_short = "FILE_PATH"; - using type = std::tuple<std::decay_t<decltype(str)>,const char*>; - explicit constexpr file_path(const char *a) : _entry(entry(str,a)) {}; + using type = std::tuple<std::decay_t<decltype(str)>,const char *>; + explicit constexpr FILE_PATH(const char * a) : _entry(entry(str, a)) {}; type _entry; }; - -struct file_name +struct FILE_NAME { - static constexpr auto str = "FILE_NAME=%s"; - static constexpr auto str_short = "FILE_NAME"; - using type = std::tuple<std::decay_t<decltype(str)>,const char*>; - explicit constexpr file_name(const char *a) : _entry(entry(str,a)) {}; - type _entry; + static constexpr auto str = "FILE_NAME=%s"; + static constexpr auto str_short = "FILE_NAME"; + using type = std::tuple<std::decay_t<decltype(str)>,const char *>; + explicit constexpr FILE_NAME(const char * a) : _entry(entry(str, a)) {}; + type _entry; }; -} // namespace _file_not_found +} // namespace _FILE_NOT_FOUND -struct file_not_found +struct FILE_NOT_FOUND { - static constexpr auto err_code = "xyz.openbmc_project.logging.FILE_NOT_FOUND_ERROR"; + static constexpr auto err_code = "xyz.openbmc_project.logging.FILE_NOT_FOUND"; static constexpr auto err_msg = "A required file was not found"; static constexpr auto L = level::INFO; - - using errnum = _file_not_found::errnum; - using file_path = _file_not_found::file_path; - using file_name = _file_not_found::file_name; - - using metadata_types = std::tuple<errnum, file_path, file_name>; + using ERRNUM = _FILE_NOT_FOUND::ERRNUM; + using FILE_PATH = _FILE_NOT_FOUND::FILE_PATH; + using FILE_NAME = _FILE_NOT_FOUND::FILE_NAME; + using metadata_types = std::tuple<ERRNUM, FILE_PATH, FILE_NAME>; }; - } // namespace logging } // namespace phosphor diff --git a/elog-gen.py b/elog-gen.py new file mode 100644 index 0000000..61cceac --- /dev/null +++ b/elog-gen.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +r""" +This script will parse the input error log yaml file 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. + +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 +from optparse import OptionParser +import yaml +import sys +import os + +def gen_elog_hpp(i_elog_yaml, i_output_hpp): + r""" + Read the input yaml file, grab the relevant data and call the mako + template to generate the header file. + + Description of arguments: + i_elog_yaml yaml file describing the error logs + i_output_hpp header file to output the generated code to + """ + + # Input parameters to mako template + errors = dict() # 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(i_elog_yaml)) + err_count = 0; + for i in ifile['SW'].keys(): + # Grab the main error + errors[err_count] = i + # Grab it's sub-items + prop = ifile['SW'][i] + error_msg[i] = prop['msg'] + error_lvl[i] = prop['level'] + tmp_meta=[] + # grab all the meta data fields and info + for j in prop['meta']: + str_short = j['str'].split('=')[0] + tmp_meta.append(str_short) + meta_data[str_short] = {} + meta_data[str_short]['str'] = j['str'] + meta_data[str_short]['str_short'] = str_short + meta_data[str_short]['type'] = j['type'] + meta.append(tmp_meta) + err_count+=1 + + # Debug + #for i in errors: + # print "ERROR: " + errors[i] + # print " MSG: " + error_msg[errors[i]] + # print " LVL: " + error_lvl[errors[i]] + # print " META: " + # print meta[i] + + # Load the mako template and call it with the required data + mytemplate = Template(filename='elog-gen-template.mako.hpp') + 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)) + f.close() + + +def main(i_args): + parser = OptionParser() + + parser.add_option("-e","--elog",dest="elog_yaml",default="elog.yaml", + help="input error yaml file to parse"); + + parser.add_option("-o","--output",dest="output_hpp", default="elog-gen.hpp", + help="output hpp to generate, elog-gen.hpp is default"); + + (options, args) = parser.parse_args(i_args) + + if (not (os.path.isfile(options.elog_yaml))): + print "Can not find input yaml file " + options.elog_yaml + exit(1); + + gen_elog_hpp(options.elog_yaml,options.output_hpp) + +# Only run if it's a script +if __name__ == '__main__': + main(sys.argv[1:])
\ No newline at end of file @@ -1,13 +1,22 @@ --- SW: - FILE_NOT_FOUND_ERROR: + FILE_NOT_FOUND: msg: "A required file was not found" level: INFO - meta_i: [ ERRNUM ] - meta_s: [ FILE_PATH, FILE_NAME ] - GETSCOM_ERROR: + meta: + - str: "ERRNUM=0x%.4X" + type: int + - str: FILE_PATH=%s + type: const char* + - str: FILE_NAME=%s + type: const char* + GETSCOM: msg: "Getscom call failed" level: ERR - meta_i: [ DEV_ADDR, - DEV_ID ] - meta_s: [ DEV_NAME ] + meta: + - str: DEV_ADDR=0x%.8X + type: int + - str: DEV_ID=%u + type: int + - str: DEV_NAME=%s + type: const char*
\ No newline at end of file diff --git a/elog_parser.py b/elog_parser.py deleted file mode 100755 index 4896700..0000000 --- a/elog_parser.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -u - -import uuid -import yaml - -with open('elog.yaml') as f: - ifile = yaml.safe_load(f) - -with open('elog-gen.hpp', 'w') as ofile: - ofile.write('namespace phosphor\n{\n\n') - ofile.write('namespace logging\n{\n\n') - - # TBD - -if __name__ == '__main__': - print "TODO\n" diff --git a/logging_test.cpp b/logging_test.cpp index 9a638c3..c5f622c 100644 --- a/logging_test.cpp +++ b/logging_test.cpp @@ -1,9 +1,11 @@ // A basic unit test that runs on a BMC (qemu or hardware) #include <iostream> -#include <elog.hpp> -#include <log.hpp> #include <systemd/sd-journal.h> +#include <sstream> +#include "elog.hpp" +#include "log.hpp" +#include "elog-gen.hpp" using namespace phosphor; using namespace logging; @@ -44,7 +46,8 @@ int validate_journal(const char *i_entry, const char *i_value) rc = (validated) ? 0 : 1; if(rc) { - std::cerr << "Failed to find " << i_entry << " in journal!" << "\n"; + std::cerr << "Failed to find " << i_entry << " with value " << i_value + <<" in journal!" << "\n"; } return rc; @@ -72,56 +75,61 @@ int main() const char *test_string = "/tmp/test_string/"; try { - elog<file_not_found>(file_not_found::errnum(number), - file_not_found::file_path(test_string), - file_not_found::file_name("elog_test_3.txt")); + elog<FILE_NOT_FOUND>(FILE_NOT_FOUND::ERRNUM(number), + FILE_NOT_FOUND::FILE_PATH(test_string), + FILE_NOT_FOUND::FILE_NAME("elog_test_3.txt")); } - catch (elogException<file_not_found>& e) + catch (elogException<FILE_NOT_FOUND>& e) { std::cout << "elog exception caught: " << e.what() << std::endl; } // Now read back and verify our data made it into the journal - rc = validate_journal(file_not_found::errnum::str_short, - std::to_string(number).c_str()); + std::stringstream stream; + stream << std::hex << number; + rc = validate_journal(FILE_NOT_FOUND::ERRNUM::str_short, + std::string(stream.str()).c_str()); if(rc) return(rc); - rc = validate_journal(file_not_found::file_path::str_short, + rc = validate_journal(FILE_NOT_FOUND::FILE_PATH::str_short, test_string); if(rc) return(rc); - rc = validate_journal(file_not_found::file_name::str_short, + rc = validate_journal(FILE_NOT_FOUND::FILE_NAME::str_short, "elog_test_3.txt"); if(rc) return(rc); // TEST 4 - Create error log with previous entry use - number = 0xFEDC; + number = 0x9876; try { - elog<file_not_found>(file_not_found::errnum(number), - prev_entry<file_not_found::file_path>(), - file_not_found::file_name("elog_test_4.txt")); + elog<FILE_NOT_FOUND>(FILE_NOT_FOUND::ERRNUM(number), + prev_entry<FILE_NOT_FOUND::FILE_PATH>(), + FILE_NOT_FOUND::FILE_NAME("elog_test_4.txt")); } catch (elogExceptionBase& e) { std::cout << "elog exception caught: " << e.what() << std::endl; } + // Now read back and verify our data made it into the journal - rc = validate_journal(file_not_found::errnum::str_short, - std::to_string(number).c_str()); + stream.str(""); + stream << std::hex << number; + rc = validate_journal(FILE_NOT_FOUND::ERRNUM::str_short, + std::string(stream.str()).c_str()); if(rc) return(rc); // This should just be equal to what we put in test 3 - rc = validate_journal(file_not_found::file_path::str_short, + rc = validate_journal(FILE_NOT_FOUND::FILE_PATH::str_short, test_string); if(rc) return(rc); - rc = validate_journal(file_not_found::file_name::str_short, + rc = validate_journal(FILE_NOT_FOUND::FILE_NAME::str_short, "elog_test_4.txt"); if(rc) return(rc); @@ -129,13 +137,13 @@ int main() // Compile fail tests // Simple test to prove we fail to compile due to missing param - //elog<file_not_found>(file_not_found::errnum(1), - // file_not_found::file_path("test")); + //elog<FILE_NOT_FOUND>(FILE_NOT_FOUND::ERRNUM(1), + // FILE_NOT_FOUND::FILE_PATH("test")); // Simple test to prove we fail to compile due to invalid param - //elog<file_not_found>(file_not_found::errnum(1), - // file_not_found::file_path("test"), - // file_not_found::file_name(1)); + //elog<FILE_NOT_FOUND>(FILE_NOT_FOUND::ERRNUM(1), + // FILE_NOT_FOUND::FILE_PATH("test"), + // FILE_NOT_FOUND::FILE_NAME(1)); return 0; } |