From 839c3d398aee352dc44ebbe6fd5b4853c301e940 Mon Sep 17 00:00:00 2001 From: Master Date: Sat, 20 Jun 2020 20:09:32 -0400 Subject: [PATCH] logging reflow --- CMakeLists.txt | 2 +- examplar.cpp | 87 +++++------ src/Logger/Logger.cpp | 51 +++++++ src/Logger/Logger.h | 35 +++++ src/{sproc => Sproc}/Sproc.cpp | 0 src/{sproc => Sproc}/Sproc.h | 0 src/loaders/{ => abstract}/Conf.cpp | 27 ++-- src/loaders/{ => abstract}/Conf.h | 12 +- src/loaders/{ => abstract}/Plan.cpp | 47 +++--- src/loaders/{ => abstract}/Plan.h | 17 ++- src/loaders/{ => abstract}/Suite.cpp | 67 ++++----- src/loaders/{ => abstract}/Suite.h | 20 ++- src/loaders/{ => abstract}/Task.cpp | 158 ++++++-------------- src/loaders/{ => abstract}/Task.h | 17 ++- src/loaders/{ => abstract}/Unit.cpp | 7 +- src/loaders/{ => abstract}/Unit.h | 11 +- src/loaders/{ => abstract}/loaders.cpp | 0 src/loaders/{ => abstract}/loaders.h | 2 +- src/loaders/{ => low_level}/JSON_Loader.cpp | 108 ++++++------- src/loaders/{ => low_level}/JSON_Loader.h | 18 ++- src/loaders/{ => misc}/helpers.cpp | 14 ++ src/loaders/{ => misc}/helpers.h | 2 + 22 files changed, 370 insertions(+), 332 deletions(-) create mode 100644 src/Logger/Logger.cpp create mode 100644 src/Logger/Logger.h rename src/{sproc => Sproc}/Sproc.cpp (100%) rename src/{sproc => Sproc}/Sproc.h (100%) rename src/loaders/{ => abstract}/Conf.cpp (89%) rename src/loaders/{ => abstract}/Conf.h (91%) rename src/loaders/{ => abstract}/Plan.cpp (84%) rename src/loaders/{ => abstract}/Plan.h (83%) rename src/loaders/{ => abstract}/Suite.cpp (78%) rename src/loaders/{ => abstract}/Suite.h (76%) rename src/loaders/{ => abstract}/Task.cpp (62%) rename src/loaders/{ => abstract}/Task.h (85%) rename src/loaders/{ => abstract}/Unit.cpp (97%) rename src/loaders/{ => abstract}/Unit.h (94%) rename src/loaders/{ => abstract}/loaders.cpp (100%) rename src/loaders/{ => abstract}/loaders.h (96%) rename src/loaders/{ => low_level}/JSON_Loader.cpp (80%) rename src/loaders/{ => low_level}/JSON_Loader.h (79%) rename src/loaders/{ => misc}/helpers.cpp (81%) rename src/loaders/{ => misc}/helpers.h (94%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66ed214..4ad927f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 3.5) project(examplar) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1z -O0 -DDEBUG=1") -set(SOURCE_FILES examplar.cpp src/loaders/loaders.cpp src/loaders/loaders.h src/json/jsoncpp.cpp src/loaders/JSON_Loader.cpp src/loaders/JSON_Loader.h src/loaders/helpers.cpp src/loaders/helpers.h src/loaders/Suite.cpp src/loaders/Suite.h src/loaders/Plan.cpp src/loaders/Plan.h src/loaders/Conf.cpp src/loaders/Conf.h src/loaders/Unit.cpp src/loaders/Unit.h src/loaders/Task.cpp src/loaders/Task.h src/sproc/Sproc.cpp src/sproc/Sproc.h) +set(SOURCE_FILES examplar.cpp src/loaders/abstract/loaders.cpp src/loaders/abstract/loaders.h src/json/jsoncpp.cpp src/loaders/low_level/JSON_Loader.cpp src/loaders/low_level/JSON_Loader.h src/loaders/misc/helpers.cpp src/loaders/misc/helpers.h src/loaders/abstract/Suite.cpp src/loaders/abstract/Suite.h src/loaders/abstract/Plan.cpp src/loaders/abstract/Plan.h src/loaders/abstract/Conf.cpp src/loaders/abstract/Conf.h src/loaders/abstract/Unit.cpp src/loaders/abstract/Unit.h src/loaders/abstract/Task.cpp src/loaders/abstract/Task.h src/Sproc/Sproc.cpp src/Sproc/Sproc.h src/Logger/Logger.cpp src/Logger/Logger.h) add_executable(examplar ${SOURCE_FILES}) \ No newline at end of file diff --git a/examplar.cpp b/examplar.cpp index f0c4342..7f2c73c 100644 --- a/examplar.cpp +++ b/examplar.cpp @@ -19,28 +19,22 @@ */ #include -#include "src/json/json.h" -#include "src/loaders/loaders.h" #include #include -#include -#include "src/loaders/helpers.h" -/* - * TODO Commandline switches - */ +#include "src/json/json.h" +#include "src/loaders/abstract/loaders.h" +#include "src/Logger/Logger.h" +#include "src/loaders/misc/helpers.h" void print_usage() { printf("examplar [ -h | --help ] [ -v | --verbose ] [ -e | --execution-context EXECUTION_CONTEXT ][ -c | --config CONFIG_PATH ]\n\n"); } - - - int main( int argc, char * argv[] ) { - int flags, opt; + int opt; bool verbose = false; bool show_help = false; @@ -70,15 +64,15 @@ int main( int argc, char * argv[] ) int option_index = 0; - opt = getopt_long (argc, argv, "vhec:", long_options, &option_index); + opt = getopt_long( argc, argv, "vhec:", long_options, &option_index ); - if (opt == -1) + if ( opt == -1 ) break; - switch (opt) + switch ( opt ) { case 0: - if (long_options[option_index].flag !=0) + if ( long_options[option_index].flag !=0 ) break; case 'h': show_help = true; @@ -86,80 +80,81 @@ int main( int argc, char * argv[] ) verbose = true; break; case 'c': - config_path = std::string(optarg); + config_path = std::string( optarg ); break; case '?': print_usage(); - exit(1); + exit( 1 ); case 'e': cli_context_supplied = true; - execution_context = std::string(optarg); + execution_context = std::string( optarg ); break; default: break; } } - if ( show_help == true ) + if ( show_help ) { print_usage(); - exit(0); + exit( 0 ); } - setlogmask( LOG_UPTO( LOG_INFO ) ); + int L_LEVEL = E_INFO; + if ( verbose ) + { + L_LEVEL = E_DEBUG; + } else { + L_LEVEL = E_INFO; + } - openlog( "Examplar", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_PERROR | LOG_LOCAL1 ); + Logger slog = Logger( L_LEVEL, "Examplar" ); // A Plan is made up of Tasks, and a Suite is made up of Units. // A Plan declares what units are executed and a Suite declares the definitions of those units. - Conf configuration = Conf(config_path, verbose ); - - // if the user set this option as a commandline argument - if ( cli_context_supplied == true ) - { - // override the conf file's specified execution context - configuration.set_execution_context( execution_context ); - } + Conf configuration = Conf(config_path, L_LEVEL ); // check if context override + if ( configuration.has_context_override() ) { // if so, set the CWD. chdir( configuration.get_execution_context().c_str() ); - std::ostringstream infostring; - infostring << "Execution context: " << get_working_path() << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + slog.log( E_DEBUG, "Set execution context: " + get_working_path() ); } + // if the user set this option as a commandline argument + if ( cli_context_supplied ) + { + // override the conf file's specified execution context + configuration.set_execution_context( execution_context ); + slog.log( E_DEBUG, "Set execution context from commandline: " + execution_context ); + } // load the filepaths to definitions of a plan and definitions of units. std::string definitions_file = configuration.get_units_path(); std::string plan_file = configuration.get_plan_path(); - Suite available_definitions; - available_definitions.load_units_file( definitions_file, verbose ); + Suite available_definitions = Suite( L_LEVEL ); + available_definitions.load_units_file( definitions_file ); - Plan plan( &configuration ); - plan.load_plan_file( plan_file, verbose ); + Plan plan = Plan( &configuration, L_LEVEL ); + plan.load_plan_file( plan_file ); - plan.load_definitions( available_definitions, verbose ); + plan.load_definitions( available_definitions ); - std::cout << "Ready to execute all tasks in Plan." << std::endl; + slog.log( E_DEBUG, "Ready to execute all tasks in Plan." ); try { - plan.execute( verbose ); + plan.execute(); } catch ( std::exception& e) { - std::cerr << e.what() << std::endl; - syslog( LOG_ERR, e.what() ); - closelog(); + slog.log( E_FATAL, e.what() ); return 1; } - closelog(); return 0; -} +} \ No newline at end of file diff --git a/src/Logger/Logger.cpp b/src/Logger/Logger.cpp new file mode 100644 index 0000000..7add3d4 --- /dev/null +++ b/src/Logger/Logger.cpp @@ -0,0 +1,51 @@ +// +// Created by bagira on 6/13/20. +// + +#include "Logger.h" + +Logger::Logger( int LOG_LEVEL, std::string mask ) +{ + this->LOG_LEVEL = LOG_LEVEL; + this->mask = mask.c_str(); + + setlogmask( LOG_UPTO( this->LOG_LEVEL ) ); + openlog( this->mask, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_PERROR | LOG_LOCAL1 ); + +} + +void Logger::log( int LOG_LEVEL, std::string msg ) +{ + std::string ERR = "XXXX"; + + if ( LOG_LEVEL <= this->LOG_LEVEL ) + { + switch ( LOG_LEVEL ) + { + case E_DEBUG: ERR = "DBUG"; break; + case E_FATAL: ERR = "FATL"; break; + case E_INFO: ERR = "INFO"; break; + case E_WARN: ERR = "WARN"; break; + } + + std::string s_msg = "[" + ERR + "] " + msg; + syslog( this->LOG_LEVEL, s_msg.c_str() ); + + if ( LOG_LEVEL == E_FATAL | LOG_LEVEL == E_WARN ) + { + std::cerr << "[" << this->get_8601() << "]\t[" << this->mask << "]\t[" << ERR << "]\t" << msg.c_str() << std::endl; + } else { + std::cout << "[" << this->get_8601() << "]\t[" << this->mask << "]\t[" << ERR << "]\t" << msg.c_str() << std::endl; + } + } +} + +std::string Logger::get_8601() +{ + auto now = std::chrono::system_clock::now(); + auto itt = std::chrono::system_clock::to_time_t(now); + std::ostringstream ss; + // ss << std::put_time(gmtime(&itt), "%FT%TZ"); + ss << std::put_time(localtime(&itt), "%Y-%m-%d_%H:%M:%S"); + return ss.str(); +} \ No newline at end of file diff --git a/src/Logger/Logger.h b/src/Logger/Logger.h new file mode 100644 index 0000000..d2005bf --- /dev/null +++ b/src/Logger/Logger.h @@ -0,0 +1,35 @@ +// +// Created by bagira on 6/13/20. +// + +#ifndef EXAMPLAR_LOGGER_H +#define EXAMPLAR_LOGGER_H + +#include +#include +#include +#include +#include +#include + +enum L_LVL { + E_INFO, + E_FATAL, + E_WARN, + E_DEBUG +}; + +class Logger { +public: + Logger( int LOG_LEVEL, std::string mask ); + void log( int LOG_LEVEL, std::string msg ); + +private: + int LOG_LEVEL; + const char * mask; + std::string get_8601(); +}; + + + +#endif //EXAMPLAR_LOGGER_H diff --git a/src/sproc/Sproc.cpp b/src/Sproc/Sproc.cpp similarity index 100% rename from src/sproc/Sproc.cpp rename to src/Sproc/Sproc.cpp diff --git a/src/sproc/Sproc.h b/src/Sproc/Sproc.h similarity index 100% rename from src/sproc/Sproc.h rename to src/Sproc/Sproc.h diff --git a/src/loaders/Conf.cpp b/src/loaders/abstract/Conf.cpp similarity index 89% rename from src/loaders/Conf.cpp rename to src/loaders/abstract/Conf.cpp index 4dae71c..61f7c53 100644 --- a/src/loaders/Conf.cpp +++ b/src/loaders/abstract/Conf.cpp @@ -66,21 +66,23 @@ protected: /// TODO Expand to detect when a directory path is supplied for units_path or plan_path and import all Tasks and Units. /// /// \param filename - The filename to load the configuration from. -Conf::Conf( std::string filename, bool verbose ): JSON_Loader() +Conf::Conf( std::string filename, int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::conf" ) { + this->LOG_LEVEL = LOG_LEVEL; + // prepare context spaghetti this->override_context = false; - try { // load the conf file. - this->load_json_file( filename, verbose ); + this->load_json_file( filename ); } catch (std::exception) { - throw ConfigLoadException("Could not find '" + filename + "'."); + this->slog.log( E_FATAL, "Unable to locate configuration file: '" + filename + "'." ); + throw ConfigLoadException("Config file not found."); } - if (this->get_serialized(this->config_version, "config_version" ,true) != 0) + if (this->get_serialized(this->config_version, "config_version" ) != 0) { throw ConfigLoadException("config_version string is not set in the config file supplied: " + filename); } @@ -90,38 +92,36 @@ Conf::Conf( std::string filename, bool verbose ): JSON_Loader() } // find the path to the plan file - if (this->get_serialized(this->plan_path, "plan_path", true) != 0 ) + if (this->get_serialized(this->plan_path, "plan_path" ) != 0 ) { throw ConfigLoadException("plan_path string is not set in the config file supplied:" + filename); } // find the path to the unit definitions file - if (this->get_serialized(this->units_path, "units_path", true) != 0 ) + if (this->get_serialized(this->units_path, "units_path" ) != 0 ) { throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename); } - if ( this->get_serialized(this->override_execution_context, "execution_context_override", true) != 0 ) + if ( this->get_serialized(this->override_execution_context, "execution_context_override" ) != 0 ) { throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename); } else { this->override_context = true; } - if ( this->get_serialized(this->execution_context, "execution_context", true) != 0 ) + if ( this->get_serialized(this->execution_context, "execution_context" ) != 0 ) { throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename); } else { this->execution_context_literal = this->execution_context.asString(); } - if ( this->get_serialized(this->env_vars_file, "env_vars_file", true) != 0 ) + if ( this->get_serialized(this->env_vars_file, "env_vars_file" ) != 0 ) { throw ConfigLoadException("env_vars_file is not set in the config file supplied: " + filename); } - - }; /// Conf::has_context_override - Specifies whether or not the override context function is enabled in the conf file. @@ -137,7 +137,6 @@ std::string Conf::get_execution_context() { /// Conf::get_plan_path - Retrieves the path to the Plan definition file from the application configuration file. std::string Conf::get_plan_path() { return this->plan_path.asString(); } - /// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file. std::string Conf::get_units_path() { return this->units_path.asString(); } @@ -150,4 +149,4 @@ void Conf::set_execution_context( std::string execution_context ) std::string Conf::get_env_vars_file() { return this->env_vars_file.asString(); -} \ No newline at end of file +} diff --git a/src/loaders/Conf.h b/src/loaders/abstract/Conf.h similarity index 91% rename from src/loaders/Conf.h rename to src/loaders/abstract/Conf.h index 44598b6..c41b31d 100644 --- a/src/loaders/Conf.h +++ b/src/loaders/abstract/Conf.h @@ -20,8 +20,9 @@ #ifndef FTESTS_CONF_H #define FTESTS_CONF_H -#include "JSON_Loader.h" +#include "../low_level/JSON_Loader.h" #include +#include "../../Logger/Logger.h" #define STRINGIZE2(s) #s @@ -47,17 +48,20 @@ private: std::string execution_context_literal; public: - Conf( std::string filename, bool verbose ); - std::string get_plan_path(); - std::string get_units_path(); + Conf( std::string filename, int LOG_LEVEL ); bool has_context_override(); + std::string get_plan_path(); + std::string get_units_path(); std::string get_execution_context(); void set_execution_context( std::string ); std::string get_env_vars_file(); +private: + int LOG_LEVEL; + Logger slog; }; diff --git a/src/loaders/Plan.cpp b/src/loaders/abstract/Plan.cpp similarity index 84% rename from src/loaders/Plan.cpp rename to src/loaders/abstract/Plan.cpp index fd22ddf..947cf50 100644 --- a/src/loaders/Plan.cpp +++ b/src/loaders/abstract/Plan.cpp @@ -120,40 +120,39 @@ protected: /// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference /// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those /// definitions to execute, and if Units together form a Suite, Tasks together form a Plan. -Plan::Plan( Conf * configuration ): JSON_Loader() +Plan::Plan( Conf * configuration, int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::plan" ) { this->configuration = configuration; -}; + this->LOG_LEVEL = LOG_LEVEL; +} /// Plan::load_plan_file - Uses the json_root buffer on each run to append intact Units as they're deserialized from /// the provided file. /// /// \param filename - The filename to load the plan from. /// \param verbose - Whether to print verbose output to STDOUT. -void Plan::load_plan_file(std::string filename, bool verbose) +void Plan::load_plan_file( std::string filename ) { // plan always loads from file - this->load_json_file( filename, verbose ); + this->load_json_file( filename ); // staging buffer Json::Value jbuff; // fill the jbuff staging buffer wih a json::value object in the supplied filename - if ( this->get_serialized( jbuff, "plan", verbose ) == 0 ) + if ( this->get_serialized( jbuff, "plan" ) == 0 ) { this->json_root = jbuff; } // iterate through the json::value members that have been loaded. append to this->tasks vector // buffer for tasks to append: - Task tmp_T; + Task tmp_T = Task( this->LOG_LEVEL ); for ( int index = 0; index < this->json_root.size(); index++ ) { - tmp_T.load_root( this->json_root[ index ], verbose ); + tmp_T.load_root( this->json_root[ index ] ); this->tasks.push_back( tmp_T ); - if ( verbose ) { - std::cout << "Added task \"" << tmp_T.get_name() << "\" to Plan." << std::endl; - } + this->slog.log( LOG_INFO, "Added task \"" + tmp_T.get_name() + "\" to Plan." ); } } @@ -177,10 +176,10 @@ void Plan::get_task(Task & result, int index ) /// /// \param unit_definitions - The Suite to load definitions from. /// \param verbose - Whether to print verbose information to STDOUT. -void Plan::load_definitions( Suite unit_definitions, bool verbose ) +void Plan::load_definitions( Suite unit_definitions ) { // placeholder Unit - Unit tmp_U; + Unit tmp_U = Unit( this->LOG_LEVEL ); // for every task in the plan: for (int i = 0; i < this->tasks.size(); i++ ) @@ -189,7 +188,7 @@ void Plan::load_definitions( Suite unit_definitions, bool verbose ) unit_definitions.get_unit( tmp_U, this->tasks[i].get_name() ); // then have that task attach a copy of tmp_U - this->tasks[i].load_definition( tmp_U, verbose ); + this->tasks[i].load_definition( tmp_U ); } } @@ -213,7 +212,7 @@ void Plan::get_task(Task & result, std::string provided_name ) } if (! foundMatch ) { - std::cerr << "Task name \"" << provided_name << "\" was referenced but not defined!" << std::endl; + this->slog.log( E_FATAL, "Task name \"" + provided_name + "\" was referenced but not defined!" ); throw Plan_InvalidTaskName(); } } @@ -226,14 +225,14 @@ void Plan::get_task(Task & result, std::string provided_name ) bool Plan::all_dependencies_complete(std::string name) { // get the task by name - Task named_task; + Task named_task = Task( this->LOG_LEVEL ); this->get_task( named_task, name ); // get the dependencies of that task std::vector deps = named_task.get_dependencies(); // create an empty task to assign values to during iteration - Task tmpTask; + Task tmpTask = Task( this->LOG_LEVEL ); // iterate through its dependencies for ( int i = 0; i < deps.size(); i++ ) { @@ -250,26 +249,26 @@ bool Plan::all_dependencies_complete(std::string name) /// Plan::execute() - Iterates through all tasks in a plan and executes them. /// /// \param verbose -void Plan::execute( bool verbose ) +void Plan::execute() { // for each task in this plan for ( int i = 0; i < this->tasks.size(); i++ ) { if (this->all_dependencies_complete(this->tasks[i].get_name()) ) { - if ( verbose ) - { - std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl; - } + + this->slog.log( E_INFO, "Executing task \"" + this->tasks[i].get_name() + "\"." ); try { - this->tasks[i].execute( this->configuration, verbose ); + this->tasks[i].execute( this->configuration ); } catch (std::exception& e) { - throw Plan_Task_GeneralExecutionException( "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() ); + this->slog.log( E_FATAL, "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() ); + throw Plan_Task_GeneralExecutionException("Could not execute task."); } } else { // not all deps met for this task - throw Plan_Task_Missing_Dependency( "Plan Task \"" + this->tasks[i].get_name() + "\" was specified in the Plan but not executed due to missing dependencies. Please revise your plan." ); + this->slog.log( E_FATAL, "Plan Task \"" + this->tasks[i].get_name() + "\" was specified in the Plan but not executed due to missing dependencies. Please revise your plan." ); + throw Plan_Task_Missing_Dependency( "Unmet dependency for task." ); } } } diff --git a/src/loaders/Plan.h b/src/loaders/abstract/Plan.h similarity index 83% rename from src/loaders/Plan.h rename to src/loaders/abstract/Plan.h index fb482a4..4c0bee7 100644 --- a/src/loaders/Plan.h +++ b/src/loaders/abstract/Plan.h @@ -22,10 +22,11 @@ #define FTESTS_PLAN_H #include -#include "../json/json.h" -#include "JSON_Loader.h" +#include "../../json/json.h" +#include "../low_level/JSON_Loader.h" #include "Task.h" #include "Conf.h" +#include "../../Logger/Logger.h" class Plan: public JSON_Loader { @@ -35,10 +36,10 @@ class Plan: public JSON_Loader Conf * configuration; public: - Plan( Conf * configuration ); + Plan( Conf * configuration, int LOG_LEVEL ); // append this->tasks from JSON file - void load_plan_file( std::string filename, bool verbose ); + void load_plan_file( std::string filename ); // fetch a task from this->tasks void get_task( Task & result, std::string provided_name ); @@ -47,15 +48,19 @@ class Plan: public JSON_Loader void get_task( Task & result, int index ); // load unit definitions from a provided suite and import them into individual tasks - void load_definitions( Suite unit_definitions, bool verbose ); + void load_definitions( Suite unit_definitions ); // fetch a corresponding Unit to a Task // void get_definition_from_task(Unit & result, Task input, bool verbose ); // execute all tasks in this plan - void execute( bool verbose ); + void execute(); bool all_dependencies_complete(std::string name); + +private: + int LOG_LEVEL; + Logger slog; }; #endif //FTESTS_PLAN_H diff --git a/src/loaders/Suite.cpp b/src/loaders/abstract/Suite.cpp similarity index 78% rename from src/loaders/Suite.cpp rename to src/loaders/abstract/Suite.cpp index c710341..0738b0e 100644 --- a/src/loaders/Suite.cpp +++ b/src/loaders/abstract/Suite.cpp @@ -79,24 +79,13 @@ protected: /// human processes to allow modularly developed profiles of test suites. As inferred, Unit is expected to be one of /// the two types that are only instantiated once per application run, though it is designed to be used more than once /// if the implementor so desires. -Suite::Suite(): JSON_Loader() {}; - - -bool is_file( std::string path) +Suite::Suite( int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::suite" ) { - struct stat buf; - stat( path.c_str(), &buf ); - return S_ISREG(buf.st_mode); + this->LOG_LEVEL; } -bool is_dir( std::string path ) -{ - struct stat buf; - stat( path.c_str(), &buf ); - return S_ISDIR(buf.st_mode); -} -void get_units_from_dir( std::vector * files, std::string path ) +void Suite::get_units_from_dir( std::vector * files, std::string path ) { DIR* dirFile = opendir( path.c_str() ); if ( dirFile ) @@ -107,11 +96,20 @@ void get_units_from_dir( std::vector * files, std::string path ) errno = 0; while (( hFile = readdir( dirFile )) != NULL ) { - if ( !strcmp( hFile->d_name, "." )) continue; - if ( !strcmp( hFile->d_name, ".." )) continue; + if ( !strcmp( hFile->d_name, "." )) + { + continue; + } + if ( !strcmp( hFile->d_name, ".." )) + { + continue; + } // hidden files - if ( hFile->d_name[0] == '.' ) continue; + if ( hFile->d_name[0] == '.' ) + { + continue; + } // dirFile.name is the name of the file. Do whatever string comparison // you want here. Something like: @@ -123,18 +121,17 @@ void get_units_from_dir( std::vector * files, std::string path ) } closedir( dirFile ); } else { - std::cout << "file not found" << std::endl; + this->slog.log( E_DEBUG, "File not found: " + path ); } } - /// Suite::load_units_file - Uses the json_root buffer on each run to append intact Units as they're /// deserialized from the provided file. /// /// \param units_path - The file to pull the JSON-formatted units from. /// \param verbose - Whether to print verbose output to STDOUT. -void Suite::load_units_file( std::string units_path, bool verbose ) +void Suite::load_units_file( std::string units_path ) { std::vector unit_files; @@ -149,28 +146,26 @@ void Suite::load_units_file( std::string units_path, bool verbose ) unit_files.push_back( units_path ); } - std::ostringstream infostring; - infostring << "Unit files found: " << unit_files.size() << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cerr << infostring.str(); + this->slog.log( E_INFO, "Unit files found: " + std::to_string( unit_files.size() ) ); for ( int i = 0; i < unit_files.size(); i++ ) { // will use json_root buffer on each run to append to this->units vector as valid units are found. - this->load_json_file( unit_files[i], verbose ); + this->load_json_file( unit_files[i] ); // staging buffer Json::Value jbuff; // fill the jbuff staging buffer with a json::value object in the supplied units_path - if ( this->get_serialized( jbuff, "units", verbose ) == 0) + if ( this->get_serialized( jbuff, "units" ) == 0) { this->json_root = jbuff; } // iterate through the json::value members that have been loaded. append to this->units vector // buffer for units to append: - Unit tmp_U; + Unit tmp_U = Unit( this->LOG_LEVEL ); + for ( int index = 0; index < this->json_root.size(); index++ ) { // assemble the unit from json_root using the built-in value operator @@ -178,20 +173,13 @@ void Suite::load_units_file( std::string units_path, bool verbose ) if ( tmp_U.get_active() ) { // append to this->units this->units.push_back( tmp_U ); - if ( verbose ) { - std::ostringstream infostring; - infostring << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - } + this->slog.log( E_INFO, "Added unit \"" + tmp_U.get_name() + "\" to Suite."); } } } - - - } + /// Suite::get_unit - returns a contained Unit identified by name attribute. /// /// \param result - the unit type receiving the unit's value @@ -213,11 +201,8 @@ void Suite::get_unit(Unit & result, std::string provided_name) if (! foundMatch ) { - std::ostringstream infostring; - infostring << "Unit name \"" << provided_name << "\" was referenced but not defined!" << std::endl; - syslog(LOG_ERR, infostring.str().c_str() ); - std::cerr << infostring.str(); - throw SuiteException( infostring.str() ); + this->slog.log( E_FATAL, "Unit name \"" + provided_name + "\" was referenced but not defined!" ); + throw SuiteException( "Undefined unit in use." ); } } diff --git a/src/loaders/Suite.h b/src/loaders/abstract/Suite.h similarity index 76% rename from src/loaders/Suite.h rename to src/loaders/abstract/Suite.h index d8aa78e..78c9adc 100644 --- a/src/loaders/Suite.h +++ b/src/loaders/abstract/Suite.h @@ -22,9 +22,11 @@ #define FTESTS_UNITS_H #include -#include "../json/json.h" -#include "JSON_Loader.h" +#include "../../json/json.h" +#include "../low_level/JSON_Loader.h" #include "Unit.h" +#include "../../Logger/Logger.h" +#include "../misc/helpers.h" class Suite: public JSON_Loader @@ -34,14 +36,22 @@ class Suite: public JSON_Loader std::vector units; public: - // constructor, empty - Suite(); + // constructor + Suite( int LOG_LEVEL ); // load a unit definitions file and add valid unit definitions to this->units - void load_units_file( std::string filename, bool verbose ); + void load_units_file( std::string filename ); // returns the unit identified by name void get_unit(Unit & result, std::string provided_name); + + private: + void get_units_from_dir( std::vector * files, std::string path ); + + +private: + int LOG_LEVEL; + Logger slog; }; #endif //FTESTS_UNITS_H diff --git a/src/loaders/Task.cpp b/src/loaders/abstract/Task.cpp similarity index 62% rename from src/loaders/Task.cpp rename to src/loaders/abstract/Task.cpp index f717078..d3b5441 100644 --- a/src/loaders/Task.cpp +++ b/src/loaders/abstract/Task.cpp @@ -19,10 +19,7 @@ */ #include "Task.h" -#include -#include -#include "../sproc/Sproc.h" -#include "helpers.h" + /// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON. class Task_InvalidDataStructure: public std::runtime_error { @@ -82,20 +79,24 @@ protected: /// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to /// execute, and its dependencies on other units to have already been completed successfully. -Task::Task() +Task::Task( int LOG_LEVEL ): + slog( LOG_LEVEL, "examplar::task" ), + definition( LOG_LEVEL ) { // it hasn't executed yet. this->complete = false; // it hasn't been matched with a definition yet. this->defined = false; + + this->LOG_LEVEL = LOG_LEVEL; } /// Task::load_root() - loads json values to private members /// /// \param loader_root - the Json::Value to populate from. /// \param verbose - Whether to print verbose information to STDOUT. -void Task::load_root(Json::Value loader_root, bool verbose ) +void Task::load_root(Json::Value loader_root ) { if ( loader_root.isMember("name") ) { this->name = loader_root.get("name", "?").asString(); @@ -110,16 +111,10 @@ void Task::load_root(Json::Value loader_root, bool verbose ) // iterate through each member of that obj for ( int i = 0; i < des_dep_root.size(); i++ ) { // add each string to dependencies - if ( des_dep_root[i].asString() != "" ) { + if ( des_dep_root[i].asString() != "" ) + { this->dependencies.push_back( des_dep_root[i].asString() ); - if ( verbose ) { - std::ostringstream infostring; - infostring << "Added dependency \"" << des_dep_root[i].asString() << "\" to task \"" - << this->get_name() << "\"." << std::endl; - - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - } + this->slog.log( E_INFO, "Added dependency \"" + des_dep_root[i].asString() + "\" to task \"" + this->get_name() + "\"." ); } } } @@ -134,17 +129,10 @@ std::string Task::get_name() /// /// \param selected_unit - The unit to attach. /// \param verbose - Whether to print to STDOUT. -void Task::load_definition( Unit selected_unit, bool verbose ) +void Task::load_definition( Unit selected_unit ) { this->definition = selected_unit; - if ( verbose ) { - std::ostringstream infostring; - infostring << "Loaded definition \"" << selected_unit.get_name() << "\" for task \"" - << this->get_name() << "\"." << std::endl; - - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - } + this->slog.log( E_INFO, "Loaded definition \"" + selected_unit.get_name() + "\" for task \"" + this->get_name() + "\"."); this->defined = true; } @@ -177,7 +165,7 @@ bool Task::has_definition() /// Task::execute - execute a task's unit definition. /// See the design document for what flow control needs to look like here. /// \param verbose - Verbosity level - not implemented yet. -void Task::execute( Conf * configuration, bool verbose ) +void Task::execute( Conf * configuration ) { // DUFFING - If Examplar is broken it's probably going to be in this block. // Somebody come clean this up, eh? @@ -192,40 +180,26 @@ void Task::execute( Conf * configuration, bool verbose ) // get the name std::string task_name = this->definition.get_name(); + this->slog.log( E_DEBUG, "\tUsing unit: \"" + task_name + "\"." ); // END PREWORK // get the target execution command std::string target_command = this->definition.get_target(); - // if we're in verbose mode, do some verbose things - if ( verbose ) + // check if context override + if ( configuration->has_context_override() ) { -/* - infostring = std::ostringstream(); - infostring << "\tUsing unit \"" << task_name << "\"." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); -*/ - - // check if context override - if ( configuration->has_context_override() ) - { - // if so, set the CWD. - chdir( configuration->get_execution_context().c_str() ); - infostring = std::ostringstream(); - infostring << "\tExecution context: " << get_working_path() << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - } - - infostring = std::ostringstream(); - infostring << "\tExecuting target \"" << target_command << "\"." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + // if so, set the CWD. + chdir( configuration->get_execution_context().c_str() ); + this->slog.log( E_INFO, "Setting execution context: " + get_working_path() ); } + // a[0] execute target // TODO revise variable sourcing strategy + + this->slog.log( E_DEBUG, "Loading environment variable file: " + configuration->get_env_vars_file() ); + this->slog.log( E_INFO, "Executing target: \"" + target_command + "\"." ); int return_code = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + target_command ); // ********************************************** @@ -234,13 +208,8 @@ void Task::execute( Conf * configuration, bool verbose ) if ( return_code == 0 ) { // d[0].0 ZERO + this->slog.log( E_INFO, "Target \"" + task_name + "\" succeeded. Marking as complete." ); - if ( verbose ) { - infostring = std::ostringstream(); - infostring << "\tTarget " << task_name << " succeeded. Marking as complete." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - } this->mark_complete(); // a[1] NEXT @@ -250,12 +219,7 @@ void Task::execute( Conf * configuration, bool verbose ) if ( return_code != 0 ) { // d[0].1 NON-ZERO - - infostring = std::ostringstream(); - infostring << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl; - - syslog(LOG_ERR, infostring.str().c_str() ); - std::cerr << infostring.str(); + this->slog.log( E_WARN, "Target \"" + task_name + "\" failed with exit code " + std::to_string( return_code ) + "." ); // ********************************************** // d[1] Rectify Check @@ -271,18 +235,13 @@ void Task::execute( Conf * configuration, bool verbose ) { // d[2].0 FALSE // a[2] NEXT - infostring = std::ostringstream(); - infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." ); return; - } - - if ( this->definition.get_required() ) - { + } else { // d[2].1 TRUE // a[3] EXCEPTION - throw TaskException("Task \"" + task_name + "\" is required, and failed, and rectification is not enabled."); + this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, and failed, and rectification is not enabled." ); + throw TaskException( "Task failed: " + task_name ); } // ********************************************** // end - d[2] Required Check @@ -293,18 +252,12 @@ void Task::execute( Conf * configuration, bool verbose ) if ( this->definition.get_rectify() ) { // d[1].1 TRUE (Rectify Check) - infostring = std::ostringstream(); - infostring << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "Rectification pattern is enabled for \"" + task_name + "\"." ); // a[4] Execute RECTIFIER std::string rectifier_command = this->definition.get_rectifier(); - infostring = std::ostringstream(); - infostring << "\tExecuting rectification: " << rectifier_command << "." << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "Executing rectification: " + rectifier_command + "." ); int rectifier_error = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + rectifier_command ); @@ -314,12 +267,7 @@ void Task::execute( Conf * configuration, bool verbose ) if ( rectifier_error != 0 ) { // d[3].1 Non-Zero - infostring = std::ostringstream(); - infostring << "\tRectification of \"" << task_name << "\" failed with exit code " - << rectifier_error << "." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - - std::cout << infostring.str(); + this->slog.log( E_WARN, "Rectification of \"" + task_name + "\" failed with exit code " + std::to_string( rectifier_error ) + "." ); // ********************************************** // d[4] Required Check @@ -327,10 +275,7 @@ void Task::execute( Conf * configuration, bool verbose ) if ( ! this->definition.get_required() ) { // d[4].0 FALSE // a[5] NEXT - infostring = std::ostringstream(); - infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." ); return; } @@ -338,7 +283,8 @@ void Task::execute( Conf * configuration, bool verbose ) { // d[4].1 TRUE // a[6] EXCEPTION - throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectification failed."); + this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, it failed, and then rectification failed. Lost cause." ); + throw TaskException( "Lost cause, task failure." ); } // ********************************************** // end - d[4] Required Check @@ -349,16 +295,10 @@ void Task::execute( Conf * configuration, bool verbose ) if ( rectifier_error == 0 ) { // d[3].0 Zero - infostring = std::ostringstream(); - infostring << "\tRectification returned successfully." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "Rectification returned successfully." ); // a[7] Re-execute Target - infostring = std::ostringstream(); - infostring << "\tRe-Executing target \"" << this->definition.get_target() << "\"." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "Re-Executing target \"" + this->definition.get_target() + "\"." ); int retry_code = Sproc::execute( "source " + configuration->get_env_vars_file() + " && " + target_command ); @@ -369,20 +309,11 @@ void Task::execute( Conf * configuration, bool verbose ) { // d[5].0 ZERO // a[8] NEXT - infostring = std::ostringstream(); - infostring << "\tRe-execution was successful." << std::endl; - syslog( LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); + this->slog.log( E_INFO, "Re-execution was successful." ); return; - } - - if ( retry_code != 0 ) - { + } else { // d[5].1 NON-ZERO - infostring = std::ostringstream(); - infostring << "\tRe-execution failed with exit code " << retry_code << "." << std::endl; - syslog(LOG_ERR, infostring.str().c_str() ); - std::cerr << infostring.str(); + this->slog.log( E_WARN, "Re-execution failed with exit code " + std::to_string( retry_code ) + "." ); // ********************************************** // d[6] Required Check @@ -391,11 +322,7 @@ void Task::execute( Conf * configuration, bool verbose ) { // d[6].0 FALSE // a[9] NEXT - infostring = std::ostringstream(); - infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl; - syslog(LOG_INFO, infostring.str().c_str() ); - std::cout << infostring.str(); - + this->slog.log( E_INFO, "This task is not required to continue the plan. Moving on." ); return; } @@ -403,7 +330,8 @@ void Task::execute( Conf * configuration, bool verbose ) { // d[6].1 TRUE // a[10] EXCEPTION - throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectifier did not heal the condition causing the target to fail. Cannot proceed with Plan."); + this->slog.log( E_FATAL, "Task \"" + task_name + "\" is required, and failed, then rectified but rectifier did not heal the condition causing the target to fail. Cannot proceed with Plan." ); + throw TaskException( "Lost cause, task failure." ); } // ********************************************** // end - d[6] Required Check diff --git a/src/loaders/Task.h b/src/loaders/abstract/Task.h similarity index 85% rename from src/loaders/Task.h rename to src/loaders/abstract/Task.h index 4ae90cc..e10970f 100644 --- a/src/loaders/Task.h +++ b/src/loaders/abstract/Task.h @@ -22,10 +22,13 @@ #define FTESTS_TASK_H #include #include -#include "../json/json.h" +#include "../../json/json.h" #include "Unit.h" #include "Suite.h" #include "Conf.h" +#include +#include "../../Sproc/Sproc.h" +#include "../misc/helpers.h" class Task { @@ -49,13 +52,13 @@ class Task public: // constructor - Task(); + Task( int LOG_LEVEL ); // load a json::value into task members (second stage deserialization) - void load_root( Json::Value loader_root, bool verbose ); + void load_root( Json::Value loader_root ); // appends definition unit as child member - void load_definition( Unit definition, bool verbose ); + void load_definition( Unit definition ); bool is_complete(); bool has_definition(); @@ -64,12 +67,16 @@ class Task std::string get_name(); // execute this task's definition - void execute( Conf * configuration, bool verbose ); + void execute( Conf * configuration ); void mark_complete(); // returns a pointer to the dependencies vector std::vector get_dependencies(); + +private: + Logger slog; + int LOG_LEVEL; }; #endif //FTESTS_TASK_H diff --git a/src/loaders/Unit.cpp b/src/loaders/abstract/Unit.cpp similarity index 97% rename from src/loaders/Unit.cpp rename to src/loaders/abstract/Unit.cpp index 6546d09..6079622 100644 --- a/src/loaders/Unit.cpp +++ b/src/loaders/abstract/Unit.cpp @@ -48,7 +48,10 @@ class Unit_DataStructureException: public std::runtime_error { public: /// required, which is used as a flag to halt or continue if rectifier does not heal the system in such a way that /// target can run successfully. /// rectify, which is used as a flag to determine in the rectifier runs. -Unit::Unit() {} +Unit::Unit( int LOG_LEVEL ): JSON_Loader( LOG_LEVEL ), slog( LOG_LEVEL, "examplar::unit" ) +{ + this->LOG_LEVEL; +} /// Unit::load_root - Takes a JSON::Value and assigns the members to the Unit being populated. /// @@ -92,7 +95,7 @@ int Unit::load_root(Json::Value loader_root) int Unit::load_string(std::string json_val) { // serialize - this->load_json_string( json_val, true ); + this->load_json_string( json_val ); // deserialize this->load_root( this->json_root ); diff --git a/src/loaders/Unit.h b/src/loaders/abstract/Unit.h similarity index 94% rename from src/loaders/Unit.h rename to src/loaders/abstract/Unit.h index 12bcdc0..6a48e62 100644 --- a/src/loaders/Unit.h +++ b/src/loaders/abstract/Unit.h @@ -26,8 +26,9 @@ #ifndef FTESTS_UNIT_H #define FTESTS_UNIT_H #include -#include "../json/json.h" -#include "JSON_Loader.h" +#include "../../json/json.h" +#include "../low_level/JSON_Loader.h" +#include "../../Logger/Logger.h" class Unit: JSON_Loader { @@ -59,7 +60,7 @@ private: bool rectify; public: - Unit(); + Unit( int LOG_LEVEL ); // loads a serialized jason::value object as a unit int load_root( Json::Value loader_root ); @@ -75,6 +76,10 @@ public: bool get_active(); bool get_required(); bool get_rectify(); + +private: + int LOG_LEVEL; + Logger slog; }; #endif //FTESTS_UNIT_H diff --git a/src/loaders/loaders.cpp b/src/loaders/abstract/loaders.cpp similarity index 100% rename from src/loaders/loaders.cpp rename to src/loaders/abstract/loaders.cpp diff --git a/src/loaders/loaders.h b/src/loaders/abstract/loaders.h similarity index 96% rename from src/loaders/loaders.h rename to src/loaders/abstract/loaders.h index 3c79c2e..6bf7c33 100644 --- a/src/loaders/loaders.h +++ b/src/loaders/abstract/loaders.h @@ -20,7 +20,7 @@ #ifndef FTESTS_LOADERS_H #define FTESTS_LOADERS_H -#include "JSON_Loader.h" +#include "../low_level/JSON_Loader.h" #include "Suite.h" #include "Plan.h" #include "Conf.h" diff --git a/src/loaders/JSON_Loader.cpp b/src/loaders/low_level/JSON_Loader.cpp similarity index 80% rename from src/loaders/JSON_Loader.cpp rename to src/loaders/low_level/JSON_Loader.cpp index 05269c3..57e49c1 100644 --- a/src/loaders/JSON_Loader.cpp +++ b/src/loaders/low_level/JSON_Loader.cpp @@ -19,8 +19,6 @@ */ #include "JSON_Loader.h" -#include "helpers.h" -#include /// JSON_Loader_NotReady - Exception thrown when a member function is called before data is populated. class JSON_Loader_NotReady: public std::runtime_error { public: @@ -40,51 +38,10 @@ class JSON_Loader_InvalidJSON: public std::runtime_error { public: /// JSON_Loader::JSON_Loader - Constructor for JSON_Loader base class. Simply inits to an unpopulated state. /// /// The JSON_Loader type is a base type. It is meant to provide the functionalities shared between Suite and Plan. -JSON_Loader::JSON_Loader() +JSON_Loader::JSON_Loader( int LOG_LEVEL ): slog( LOG_LEVEL, "examplar::json_loader" ) { this->populated = false; -} - -/// JSON_Loader::load_json_file - Loads JSON from a filepath into a serialized representation assigned as a local member -/// intended to be used as a buffer for further operations by base methods and derived class methods. -/// -/// \param filename - -/// \param verbose -void JSON_Loader::load_json_file( std::string filename, bool verbose ) -{ - // reads from a file into a Json::Value type. - Json::Reader json_reader; - - // the a deserialized json type to contain what's read by the reader - Json::Value json_root; - - // first, check if the file exists - if (! exists( filename ) ) - { - std::cerr << "File '" << filename << "' does not exist." << std::endl; - throw JSON_Loader_FileNotFound(); - } - - // create the ifstream file handle - std::ifstream json_file_ifstream( filename, std::ifstream::binary ); - - // use the reader to parse the ifstream to the local property - bool parsingSuccessful = json_reader.parse( json_file_ifstream, this->json_root ); - - if (! parsingSuccessful ) - { - std::cerr << "Failed to parse '" << filename << "':\n\t" << json_reader.getFormattedErrorMessages(); - throw JSON_Loader_InvalidJSON(); - - } else { - // if in verbose mode, give the user an "it worked" message - if (verbose) - { - std::cout << "Parsed '" << filename << "' with " << this->json_root.size() << " element(s)." << std::endl; - } - } - // Flag as ready for consumption. - this->populated = true; + this->LOG_LEVEL = LOG_LEVEL; } /// JSON_Loader::load_json_string - loads json from std::string into a json::value type and sets to protected member @@ -92,7 +49,7 @@ void JSON_Loader::load_json_file( std::string filename, bool verbose ) /// /// \param input - The JSON-formatted string to serialize /// \param verbose - Whether or not to print verbose information to STDOUT. -void JSON_Loader::load_json_string( std::string input, bool verbose ) +void JSON_Loader::load_json_string( std::string input ) { // reads from a string into a Json::Value type. Json::Reader json_reader; @@ -108,18 +65,52 @@ void JSON_Loader::load_json_string( std::string input, bool verbose ) if (! parsingSuccessful ) { - std::cerr << "Failed to parse adhoc JSON value." << std::endl << input << std::endl << std::endl << json_reader.getFormattedErrorMessages(); + this->slog.log( E_FATAL, "Failed to parse adhoc JSON value: " + json_reader.getFormattedErrorMessages() ); + throw JSON_Loader_InvalidJSON(); + + } else { + this->slog.log( E_DEBUG, "Successfully parsed JSON string with " + std::to_string( this->json_root.size() ) + "elements. Value: '" + input + "'." ); + } + // flag as ready for consumption + this->populated = true; +} + +/// JSON_Loader::load_json_file - Loads JSON from a filepath into a serialized representation assigned as a local member +/// intended to be used as a buffer for further operations by base methods and derived class methods. +/// +/// \param filename - +/// \param verbose +void JSON_Loader::load_json_file( std::string filename ) +{ + // reads from a file into a Json::Value type. + Json::Reader json_reader; + + // the a deserialized json type to contain what's read by the reader + Json::Value json_root; + + // first, check if the file exists + if (! exists( filename ) ) + { + this->slog.log( E_FATAL, "File '" + filename + "' does not exist." ); + throw JSON_Loader_FileNotFound(); + } + + // create the ifstream file handle + std::ifstream json_file_ifstream( filename, std::ifstream::binary ); + + // use the reader to parse the ifstream to the local property + bool parsingSuccessful = json_reader.parse( json_file_ifstream, this->json_root ); + + if (! parsingSuccessful ) + { + this->slog.log( E_FATAL, "Failed to parse file '" + filename + "': " + json_reader.getFormattedErrorMessages() ); throw JSON_Loader_InvalidJSON(); } else { // if in verbose mode, give the user an "it worked" message - if ( verbose ) - { - std::cout << "Successfully parsed JSON string with " << this->json_root.size() << " elements. Value:" << std::endl; - std::cout << input << std::endl << std::endl; - } + this->slog.log( E_DEBUG, "Parsed '" + filename + "' with " + std::to_string( this->json_root.size() ) + " element(s)." ); } - // flag as ready for consumption + // Flag as ready for consumption. this->populated = true; } @@ -138,7 +129,7 @@ std::string JSON_Loader::as_string() /// \param key - The JSON key name to assign the value to (the root of the json::value object by name) /// \param verbose - Whether or not to print verbose output to STDOUT. /// \return - Boolean indicator of success or failure (0|1) -int JSON_Loader::get_serialized(Json::Value &input, std::string key, bool verbose) +int JSON_Loader::get_serialized(Json::Value &input, std::string key ) { // throw if the class is not ready to be used. if ( ! this->populated ) { throw JSON_Loader_NotReady(); } @@ -151,11 +142,10 @@ int JSON_Loader::get_serialized(Json::Value &input, std::string key, bool verbos } // key was not found - if ( verbose ) - { - // verbose mode tells the user what key we were looking for. - std::cerr << "Failed to find key '" << key << "'." << std::endl; - } + + // verbose mode tells the user what key we were looking for. + this->slog.log( E_FATAL, "Failed to find key '" + key + "'." ); + // exit code for failure return 1; } \ No newline at end of file diff --git a/src/loaders/JSON_Loader.h b/src/loaders/low_level/JSON_Loader.h similarity index 79% rename from src/loaders/JSON_Loader.h rename to src/loaders/low_level/JSON_Loader.h index 42b9bfd..0cbf262 100644 --- a/src/loaders/JSON_Loader.h +++ b/src/loaders/low_level/JSON_Loader.h @@ -19,11 +19,13 @@ */ #ifndef FTESTS_JLOADER_H #define FTESTS_JLOADER_H -#include "../json/json.h" +#include "../../json/json.h" #include #include #include - +#include +#include "../misc/helpers.h" +#include "../../Logger/Logger.h" class JSON_Loader { @@ -33,13 +35,13 @@ class JSON_Loader public: // constructor - JSON_Loader(); + JSON_Loader( int LOG_LEVEL ); // load from json file - void load_json_file( std::string filename, bool verbose ); + void load_json_file( std::string filename ); // load from std::string json - void load_json_string( std::string input, bool verbose ); + void load_json_string( std::string input ); // return as a JSONCPP serialized object // deprecated -- these aren't really used. @@ -47,6 +49,10 @@ class JSON_Loader std::string as_string(); // safely handle deserialized type retrieval (if we want it to be safe) - int get_serialized(Json::Value &input, std::string key, bool verbose); + int get_serialized(Json::Value &input, std::string key ); + +private: + Logger slog; + int LOG_LEVEL; }; #endif //FTESTS_JLOADER_H diff --git a/src/loaders/helpers.cpp b/src/loaders/misc/helpers.cpp similarity index 81% rename from src/loaders/helpers.cpp rename to src/loaders/misc/helpers.cpp index 5176b39..16223cd 100644 --- a/src/loaders/helpers.cpp +++ b/src/loaders/misc/helpers.cpp @@ -30,4 +30,18 @@ std::string get_working_path() { char temp[MAXPATHLEN]; return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") ); +} + +bool is_file( std::string path) +{ + struct stat buf; + stat( path.c_str(), &buf ); + return S_ISREG(buf.st_mode); +} + +bool is_dir( std::string path ) +{ + struct stat buf; + stat( path.c_str(), &buf ); + return S_ISDIR(buf.st_mode); } \ No newline at end of file diff --git a/src/loaders/helpers.h b/src/loaders/misc/helpers.h similarity index 94% rename from src/loaders/helpers.h rename to src/loaders/misc/helpers.h index d4956cf..13f4e9e 100644 --- a/src/loaders/helpers.h +++ b/src/loaders/misc/helpers.h @@ -29,5 +29,7 @@ bool exists (const std::string& name); std::string get_working_path(); +bool is_file( std::string ); +bool is_dir( std::string ); #endif //FTESTS_HELPERS_H