Logging
Contents
Logging
Logging is a critical part of any mature software. It is used to keep human-readable records of the execution of the software. If something happens - e.g., a regular event marking up the progress of s subroutine, a critical/erroneous event, or even a corruption, library developers and users could read the logging records and make diagnosis.
For scientific computation, the importance of logging system is usually underestimated, because most scientific executables are developed quick-and-dirty. Without enough logging, the maintainers, possibly the young students, easily get lost on the destructive errors.
HIPP provides a easy-to-use logging system to produce human-readable logging records. The utilities include
The logger class
PLogStream. It is very likePStream, except that more methods are provided to control the logging behavior.The global static variable,
plog. It is a instance ofPLogStream, which allows direct logging into the standard output.
The examples in this section assume the following inclusion and namespace declaration:
#include <hippcntl.h>
using namespace HIPP;
This includes and exposes all the declarations in the CNTL module. For
detailed compilation guide, see the API-ref CNTL Module Overview.
All the example codes in this section can be downloaded at cntl/logging.cpp.
Basic Logging
To put log records into the standard output, use plog.
It can be used like the PStream class introduced
in the tutorial Printing Anything With the Pretty Stream:
vector<int> v{1,2,3,4};
plog << "Begin computing the sum of {", v, "}", endl;
auto sum = std::accumulate(v.begin(), v.end(), 0);
plog << "Done. Get ", sum, endl;
Elementary types, standard containers and utils, and anything with overloaded
operator<< can be streamed into plog.
The output is:
Begin computing the sum of {1,2,3,4}
Done. Get 10
There is nothing special. But a real program would be more complex -
functions on the calling chain are nested as a stack structure. For example,
the above “summation of vector” can be written as a separate function and
called by the main function. In this case, use push_g()
to indicate the entrance of a new stack level:
int find_sum(const vector<double> &v) {
auto _ = plog.push_g(emFF);
plog << "Begin computing the sum of {", v, "}", endl;
auto sum = std::accumulate(v.begin(), v.end(), 0);
plog << "Done. Get ", sum, endl;
return sum;
}
int main(int argc, char const *argv[])
{
auto sum1 = find_sum({1,2,3}),
sum2 = find_sum({4,5,6});
plog << "Get sums ", sum1, " and ", sum2, endl;
return 0;
}
Here, push_g() accepts a list of printable arguments,
prints them, and return a guard object. The macro emFF is a list
of predefined strings indicating the current file and function.
We name the returned guard as “_” because
we do not direct use it. At the end of the function find_sum, the guard
is destructed and the stack level is restored to the caller.
The output indents more for higher stack level:
[file] logging.cpp, [func] find_sum
|- Begin computing the sum of {1,2,3}
|- Done. Get 6
[file] logging.cpp, [func] find_sum
|- Begin computing the sum of {4,5,6}
|- Done. Get 15
Get sums 6 and 15
Controlling the Priority Level
Each PLogStream instance has a “current priority level” and
a “used priority level”.
Each message you print to the stream has its priority level equal to the
“current priority level” of the stream. If it is lower than the
“use priority level”, the message does not show. With this feature,
you can easily filter out undesired messages.
The default current and used priority levels are LV_NOTICE.
When entering a new scope, you may change the current priority level by calling
push_at(). This method is similar to push_g(),
but with an additional first argument specifying the desired level. For example:
void priority_level() {
plog << "A NOTICE", endl;
{
auto _ = plog.push_at(plog.LV_INFO, "A new scope with INFO priority");
plog << "An INFO", endl;
plog << "Another INFO", endl;
}
plog << "Another NOTICE", endl;
}
Here, in the inner scope (formed by the pair of braces, {}),
we set the level to LV_INFO, which is lower
than the NOTICE level.
Then, a call of the function priority_level():
priority_level();
outputs only
A NOTICE
Another NOTICE
where the INFO level messages in the inner scope do not appear.
You can set the “used priority level” with set_level_used().
For example, set it to a INFO level:
plog.set_level_used(plog.LV_INFO);
priority_level();
This time, the output includes the lower-level messages:
A NOTICE
A new scope with INFO priority
|- An INFO
|- Another INFO
Another NOTICE