From cfd19b6ec72209e3babe922387cd270dd88cb5b6 Mon Sep 17 00:00:00 2001 From: Jürgen Knödlseder Date: Wed, 3 Aug 2016 11:45:39 +0200 Subject: [PATCH] Add methods for logging in applications (#1828) --- ChangeLog | 11 ++++++----- Makefile.am | 5 +++++ NEWS | 16 ++++++++++++---- README.md | 2 +- include/GApplication.hpp | 13 ++++++++++++- pyext/GApplication.i | 38 +++++++++++++++++++++++++++++++++++--- src/app/GApplication.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- test/data/test_GApplication.par | 8 ++++++++ test/test_GApplication.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/test_GApplication.hpp | 3 ++- 10 files changed, 397 insertions(+), 46 deletions(-) create mode 100644 test/data/test_GApplication.par diff --git a/ChangeLog b/ChangeLog index c92fc80..a50c2ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,12 +1,13 @@ -2016-07-29 +2016-08-03 * Version 1.2.0 released ========================= - Fix removal of Python wrappers after make clean (#1826) - Add GModelSpectralExpInvPlaw class (#1800) - Add GModelSpectralPlawEnergyFlux class (#1790) - Rename GModelSpectralPlaw2 to GModelSpectralPlawPhotonFlux (#1790) + Add methods for logging in applications (#1828) + Fix removal of Python wrappers after make clean (#1826) + Add GModelSpectralExpInvPlaw class (#1800) + Add GModelSpectralPlawEnergyFlux class (#1790) + Rename GModelSpectralPlaw2 to GModelSpectralPlawPhotonFlux (#1790) 2016-07-24 diff --git a/Makefile.am b/Makefile.am index 217009d..dadada3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -163,6 +163,11 @@ sphinx-install: cp -r $(srcdir)/doc/html/_static $(DESTDIR)$(docdir)/html/ ; \ fi +# Add clean wrappers rule +clean-wrappers: + rm -rf $(builddir)/pyext/gammalib/*.py + rm -rf $(builddir)/pyext/gammalib/*_wrap.cpp + # Add documentation rule: doc: doxygen sphinx diff --git a/NEWS b/NEWS index 67cdb5e..93f92e3 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ New Features and Important Changes in GammaLib 1.2.0 -29 July 2016 +3 August 2016 1. Introduction @@ -22,7 +22,11 @@ The following classes have been renamed: - GModelSpectralPlawPhotonFlux, was GModelSpectralPlaw2 The following methods have been added: -- ... +- GApplication::log_string() +- GApplication::log_value() +- GApplication::log_header1() +- GApplication::log_header2() +- GApplication::log_header3() The following methods have been removed: - ... @@ -31,7 +35,7 @@ The following methods have been renamed: - GModelSpectralPlawPhotonFlux::flux(), was GModelSpectralPlaw2::integral() The parameters for the following methods have been changed: -- ... +- GApplication::log_parameters() now has a mandatory GChatter argument The return value of the following methods has been changed: - ... @@ -46,7 +50,11 @@ removed in a "make clean" if they have been built (#1826). 4. Application module --------------------- -None +The GApplication::log_parameters() method now takes a mandatory GChatter +argument to enable displaying of parameters only above a given chattiness +level. This avoids a log-level check in the client code. For the same +purpose, the GApplication methods log_string(), log_value(), log_header1(), +log_header2(), and log_header3() have been introduced (#1828). 5. Base module diff --git a/README.md b/README.md index 997db4c..114f39f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ GammaLib information ==================== -* Version: 1.2.0.dev1 (29 July 2016) +* Version: 1.2.0.dev1 (3 August 2016) * Author: Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu) [![Build Status](https://cta-jenkins.irap.omp.eu/buildStatus/icon?job=gammalib-integrate-os)](https://cta-jenkins.irap.omp.eu/job/gammalib-integrate-os/) diff --git a/include/GApplication.hpp b/include/GApplication.hpp index f91182e..9caaf3a 100644 --- a/include/GApplication.hpp +++ b/include/GApplication.hpp @@ -83,7 +83,18 @@ public: const std::string& log_filename(void) const; void log_header(void); void log_trailer(void); - void log_parameters(void); + void log_string(const GChatter& chatter, + const std::string& string); + void log_value(const GChatter& chatter, + const std::string& name, + const std::string& value); + void log_header1(const GChatter& chatter, + const std::string& header); + void log_header2(const GChatter& chatter, + const std::string& header); + void log_header3(const GChatter& chatter, + const std::string& header); + void log_parameters(const GChatter& chatter); const bool& need_help(void) const; std::string print(const GChatter& chatter = NORMAL) const; diff --git a/pyext/GApplication.i b/pyext/GApplication.i index e450158..c37e06c 100644 --- a/pyext/GApplication.i +++ b/pyext/GApplication.i @@ -76,7 +76,15 @@ public: %rename(_log_filename) log_filename() const; %rename(_log_header) log_header(); %rename(_log_trailer) log_trailer(); - %rename(_log_parameters) log_parameters(); + %rename(_log_string) log_string(const GChatter& chatter, + const std::string& string); + %rename(_log_header1) log_header1(const GChatter& chatter, + const std::string& header); + %rename(_log_header2) log_header2(const GChatter& chatter, + const std::string& header); + %rename(_log_header3) log_header3(const GChatter& chatter, + const std::string& header); + %rename(_log_parameters) log_parameters(const GChatter& chatter); %rename(_need_help) need_help() const; %rename(_log) log; @@ -97,7 +105,18 @@ public: const std::string& log_filename(void) const; void log_header(void); void log_trailer(void); - void log_parameters(void); + void log_string(const GChatter& chatter, + const std::string& string); + void log_value(const GChatter& chatter, + const std::string& name, + const std::string& value); + void log_header1(const GChatter& chatter, + const std::string& header); + void log_header2(const GChatter& chatter, + const std::string& header); + void log_header3(const GChatter& chatter, + const std::string& header); + void log_parameters(const GChatter& chatter); const bool& need_help(void) const; // Public members @@ -106,7 +125,20 @@ public: /***********************************************************************//** - * @brief GApplication class extension + * @brief GApplication Python class extension + ***************************************************************************/ +%pythoncode %{ +# Log the value of a parameter +def _log_value(self, name, value): + self._log.parformat(str(name)) + self._log(str(value)) + self._log('\n') +GApplication._log_value = _log_value +%} + + +/***********************************************************************//** + * @brief GApplication C++ class extension ***************************************************************************/ %extend GApplication { GApplicationPar& __getitem__(const std::string& name) { diff --git a/src/app/GApplication.cpp b/src/app/GApplication.cpp index 81179c4..3428641 100644 --- a/src/app/GApplication.cpp +++ b/src/app/GApplication.cpp @@ -498,50 +498,179 @@ void GApplication::log_trailer(void) /***********************************************************************//** + * @brief Write string in log file + * + * @param[in] chatter Minimum required chattiness + * @param[in] string String + * + * Writes a string into the log file if chattiness is at least @p chatter. + ***************************************************************************/ +void GApplication::log_string(const GChatter& chatter, + const std::string& string) +{ + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); + + // Only write message if chattiness is at least equal to the minimum + // required chattiness + if (chattiness >= chatter) { + log << string; + } + + // Return + return; +} + + +/***********************************************************************//** + * @brief Write parameter value in log file + * + * @param[in] chatter Minimum required chattiness + * @param[in] name Parameter name string + * @param[in] value Value string + * + * Writes a parameter value into the log file if chattiness is at least + * @p chatter. + ***************************************************************************/ +void GApplication::log_value(const GChatter& chatter, + const std::string& name, + const std::string& value) +{ + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); + + // Only write message if chattiness is at least equal to the minimum + // required chattiness + if (chattiness >= chatter) { + log << gammalib::parformat(name); + log << value << std::endl; + } + + // Return + return; +} + + +/***********************************************************************//** + * @brief Write header 1 in log file + * + * @param[in] chatter Minimum required chattiness + * @param[in] header Header string + * + * Writes a header of level 1 into the log file if chattiness is at least + * @p chatter. + ***************************************************************************/ +void GApplication::log_header1(const GChatter& chatter, + const std::string& header) +{ + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); + + // Only write message if chattiness is at least equal to the minimum + // required chattiness + if (chattiness >= chatter) { + log << std::endl; + log.header1(header); + } + + // Return + return; +} + + +/***********************************************************************//** + * @brief Write header 2 in log file + * + * @param[in] chatter Minimum required chattiness + * @param[in] header Header string + * + * Writes a header of level 2 into the log file if chattiness is at least + * @p chatter. + ***************************************************************************/ +void GApplication::log_header2(const GChatter& chatter, + const std::string& header) +{ + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); + + // Only write message if chattiness is at least equal to the minimum + // required chattiness + if (chattiness >= chatter) { + log << std::endl; + log.header2(header); + } + + // Return + return; +} + + +/***********************************************************************//** + * @brief Write header 3 in log file + * + * @param[in] chatter Minimum required chattiness + * @param[in] header Header string + * + * Writes a header of level 3 into the log file if chattiness is at least + * @p chatter. + ***************************************************************************/ +void GApplication::log_header3(const GChatter& chatter, + const std::string& header) +{ + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); + + // Only write message if chattiness is at least equal to the minimum + // required chattiness + if (chattiness >= chatter) { + log << std::endl; + log.header3(header); + } + + // Return + return; +} + + +/***********************************************************************//** * @brief Write application parameters in log file * + * @param[in] chatter Minimum required chattiness + * * Writes all application parameters in the log file. For parameters that * have not yet been queried the method does not write the current value * but signals [not queried]. ***************************************************************************/ -void GApplication::log_parameters(void) +void GApplication::log_parameters(const GChatter& chatter) { - // Write header - log.header1("Parameters"); - - // Count number of written parameters - int written = 0; + // Get chattiness of application + GChatter chattiness = static_cast((&m_pars["chatter"])->integer()); - // Write parameters in logger - for (int i = 0; i < m_pars.size(); ++i) { + // Only write parameters if the chattiness is at least equal to the + // minimum required chattiness + if (chattiness >= chatter) { - // Skip all parameters that still need to be queried as we - // do not yet know their value - //if (m_pars.m_pars[i].is_query()) { - // continue; - //} + // Write header + log.header1("Parameters"); - // Add line feed - if (written > 0) { - log << std::endl; - } + // Write parameters in logger + for (int i = 0; i < m_pars.size(); ++i) { - // Set parameter name - std::string name = " " + m_pars.m_pars[i].name() + " "; - name = name + gammalib::fill(".", 28-name.length()) + ": "; + // Set parameter name + std::string name = " " + m_pars.m_pars[i].name() + " "; + name = name + gammalib::fill(".", 28-name.length()) + ": "; - // Write parameter - if (m_pars.m_pars[i].is_query()) { - log << name << "[not queried]"; - } - else { - log << name << m_pars.m_pars[i].m_value; - } + // Write parameter + if (m_pars.m_pars[i].is_query()) { + log << name << "[not queried]" << std::endl; + } + else { + log << name << m_pars.m_pars[i].m_value << std::endl; + } - // Increment number of written parameters - written++; + } // endfor: looped over all parameters - } + } // endif: chattiness satisfied minimum required level // Return return; @@ -551,7 +680,7 @@ void GApplication::log_parameters(void) /***********************************************************************//** * @brief Print application * - * @param[in] chatter Chattiness (defaults to NORMAL). + * @param[in] chatter Chattiness. * @return String containing application information. ***************************************************************************/ std::string GApplication::print(const GChatter& chatter) const diff --git a/test/data/test_GApplication.par b/test/data/test_GApplication.par new file mode 100644 index 0000000..d242e9e --- /dev/null +++ b/test/data/test_GApplication.par @@ -0,0 +1,8 @@ +# +# Standard parameters +#==================== +chatter, i, h, 2,0,4, "Chattiness of output" +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" +debug, b, h, no,,, "Debugging mode activated" +mode, s, h, ql,,, "Mode of automatic parameters" +logfile, f, h, test_logfile.log,,, "Log filename" diff --git a/test/test_GApplication.cpp b/test/test_GApplication.cpp index 9ca8415..024eab0 100644 --- a/test/test_GApplication.cpp +++ b/test/test_GApplication.cpp @@ -28,6 +28,8 @@ #ifdef HAVE_CONFIG_H #include #endif +#include // setenv +#include #include "test_GApplication.hpp" /* __ Globals ____________________________________________________________ */ @@ -50,6 +52,8 @@ void TestGApplication::set(void) "Test C logger"); append(static_cast(&TestGApplication::test_GApplicationPar), "Test GApplicationPar class"); + append(static_cast(&TestGApplication::test_GApplication), + "Test GApplication class"); // Return return; @@ -355,11 +359,163 @@ void TestGApplication::test_GApplicationPar(void) } +/***********************************************************************//** + * @brief Test GApplication class + **************************************************************************/ +void TestGApplication::test_GApplication(void) +{ + // Allocate application + GApplication app1("test_GApplication", "1.0.0"); + + // Test name and version + test_value(app1.name(), "test_GApplication", "Check application name"); + test_value(app1.version(), "1.0.0", "Check application version"); + + // Open log file + app1.logFileOpen(); + + // Test log filename + test_value(app1.par_filename(), "test_GApplication.par", + "Check application parameter file name"); + test_value(app1.log_filename(), "test_logfile.log", + "Check application log file name"); + + // Write something into the logfile and close it + app1.log_header(); + app1.log_string(SILENT, "Silent"); + app1.log_string(TERSE, "Terse"); + app1.log_string(NORMAL, "Normal"); + app1.log_string(EXPLICIT, "Explicit"); + app1.log_string(VERBOSE, "Verbose"); + app1.log_string(TERSE, "\n"); + app1.log_value(NORMAL, "User parameter", "3.14"); + app1.log_value(VERBOSE, "Verbose parameter", "3.14!!"); + app1.log_header1(NORMAL, "Header 1"); + app1.log_header2(NORMAL, "Header 2"); + app1.log_header3(NORMAL, "Header 3"); + app1.log_header1(VERBOSE, "Verbose header 1"); + app1.log_header2(VERBOSE, "Verbose header 2"); + app1.log_header3(VERBOSE, "Verbose header 3"); + app1.log_parameters(NORMAL); + app1.log_parameters(VERBOSE); + app1.log_trailer(); + app1.logFileClose(); + + // Check if log file exists + char line[200]; + FILE *fp = fopen("test_logfile.log", "r"); + test_assert(fp != NULL, "Check if logfile exists"); + + // If log file exists then check it line by line + if (fp != NULL) { + + // Test header + fgets(line, 100, fp); + test_value(line, "***************************************************" + "*****************************\n", + "Check log file line 1"); + fgets(line, 100, fp); + test_value(line, "* test_GApplication " + " *\n", + "Check log file line 2"); + fgets(line, 100, fp); + test_value(line, "* -------------------------------------------------" + "--------------------------- *\n", + "Check log file line 3"); + fgets(line, 100, fp); + test_value(line, "* Version: 1.0.0 " + " *\n", + "Check log file line 4"); + fgets(line, 100, fp); + test_value(line, "***************************************************" + "*****************************\n", + "Check log file line 5"); + + // Test logging of strings + fgets(line, 100, fp); + test_value(line, "SilentTerseNormal\n", "Check log file line 6"); + + // Test logging of user parameter + fgets(line, 100, fp); + test_value(line, " User parameter ............: 3.14\n", + "Check log file line 7"); + + // Test logging of header 1 + fgets(line, 100, fp); + test_value(line, "\n", "Check log file line 8"); + fgets(line, 100, fp); + test_value(line, "+==========+\n", "Check log file line 9"); + fgets(line, 100, fp); + test_value(line, "| Header 1 |\n", "Check log file line 10"); + fgets(line, 100, fp); + test_value(line, "+==========+\n", "Check log file line 11"); + + // Test logging of header 2 + fgets(line, 100, fp); + test_value(line, "\n", "Check log file line 12"); + fgets(line, 100, fp); + test_value(line, "+----------+\n", "Check log file line 13"); + fgets(line, 100, fp); + test_value(line, "| Header 2 |\n", "Check log file line 14"); + fgets(line, 100, fp); + test_value(line, "+----------+\n", "Check log file line 15"); + + // Test logging of header 3 + fgets(line, 100, fp); + test_value(line, "\n", "Check log file line 16"); + fgets(line, 100, fp); + test_value(line, "=== Header 3 ===\n", "Check log file line 17"); + + // Test logging of parameters + fgets(line, 100, fp); + test_value(line, "+============+\n", "Check log file line 18"); + fgets(line, 100, fp); + test_value(line, "| Parameters |\n", "Check log file line 19"); + fgets(line, 100, fp); + test_value(line, "+============+\n", "Check log file line 20"); + fgets(line, 100, fp); + test_value(line, " chatter ...................: 2\n", + "Check log file line 21"); + fgets(line, 100, fp); + test_value(line, " clobber ...................: yes\n", + "Check log file line 22"); + fgets(line, 100, fp); + test_value(line, " debug .....................: no\n", + "Check log file line 23"); + fgets(line, 100, fp); + test_value(line, " mode ......................: ql\n", + "Check log file line 24"); + fgets(line, 100, fp); + test_value(line, " logfile ...................: test_logfile.log\n", + "Check log file line 25"); + fgets(line, 32, fp); + test_value(line, "Application \"test_GApplication\"", + "Check log file line 26"); + // Empty remaining characters (not checked since they are machine + // dependent) + fgets(line, 200, fp); + fgets(line, 32, fp); + test_value(line, "Application \"test_GApplication\"", + "Check log file line 27"); + + // Close log file + fclose(fp); + + } // endif: log file existed + + // Return + return; +} + + /*************************************************************************** * @brief Main entry point for test executable ***************************************************************************/ int main(void) { + // Set PFILES environment variable + setenv("PFILES", "data", 1); + // Allocate test suit container GTestSuites testsuites("GApplication"); diff --git a/test/test_GApplication.hpp b/test/test_GApplication.hpp index 0015c0d..a243c50 100644 --- a/test/test_GApplication.hpp +++ b/test/test_GApplication.hpp @@ -1,7 +1,7 @@ /*************************************************************************** * test_GApplication.hpp - Test GApplication class * * ----------------------------------------------------------------------- * - * copyright (C) 2012-2013 by Jean-Baptiste Cayrou * + * copyright (C) 2012-2016 by Jean-Baptiste Cayrou * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -51,6 +51,7 @@ public: void test_stream_logger(void); void test_C_logger(void); void test_GApplicationPar(void); + void test_GApplication(void); }; #endif /* TEST_GAPPLICATION_HPP */ -- libgit2 0.21.4