How to log line number of coder in boost log 2.0? - boost-log

Can I use LineID attribute for this?
I hope I could use sink::set_formatter to do this instead of using
__LINE__
and
__FILE__
in each log statement.

I struggled with this, until I found this snippet
#define LFC1_LOG_TRACE(logger) \
BOOST_LOG_SEV(logger, trivial::trace) << "(" << __FILE__ << ", " << __LINE__ << ") "
Works like a charm

The LineID attribute is a sequential number that is incremented for each logging message. So you can't use that.
You can use attributes to log the line numbers etc. This allows you flexible formatting using the format string, whereas using Chris' answer your format is fixed.
Register global attributes in your logging initialization function:
using namespace boost::log;
core::get()->add_global_attribute("Line", attributes::mutable_constant<int>(5));
core::get()->add_global_attribute("File", attributes::mutable_constant<std::string>(""));
core::get()->add_global_attribute("Function", attributes::mutable_constant<std::string>(""));
Setting these attributes in your logging macro:
#define logInfo(methodname, message) do { \
LOG_LOCATION; \
BOOST_LOG_SEV(_log, boost::log::trivial::severity_level::info) << message; \
} while (false)
#define LOG_LOCATION \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<int>>(boost::log::core::get()->get_global_attributes()["Line"]).set(__LINE__); \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["File"]).set(__FILE__); \
boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["Function"]).set(__func__);
Not exactly beautiful, but it works and it was a long way for me. It's a pity boost doesn't offer this feature out of the box.
The do {... } while(false) is to make the macro semantically neutral.

The solution shown by Chris works, but if you want to customize the format or choose which information appears in each sink, you need to use mutable constant attributes:
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));
Then, you make a custom macro that includes these new attributes:
// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
BOOST_LOG_STREAM_WITH_PARAMS( \
(logger), \
(set_get_attrib("File", path_to_filename(__FILE__))) \
(set_get_attrib("Line", __LINE__)) \
(::boost::log::keywords::severity = (boost::log::trivial::sev)) \
)
// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
attr.set(value);
return attr.get();
}
// Convert file path to only the filename
std::string path_to_filename(std::string path) {
return path.substr(path.find_last_of("/\\")+1);
}
The next complete source code create two sinks. The first uses File and Line attributes, the second not.
#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace expr = boost::log::expressions;
namespace src = boost::log::sources;
namespace keywords = boost::log::keywords;
// New macro that includes severity, filename and line number
#define CUSTOM_LOG(logger, sev) \
BOOST_LOG_STREAM_WITH_PARAMS( \
(logger), \
(set_get_attrib("File", path_to_filename(__FILE__))) \
(set_get_attrib("Line", __LINE__)) \
(::boost::log::keywords::severity = (boost::log::trivial::sev)) \
)
// Set attribute and return the new value
template<typename ValueType>
ValueType set_get_attrib(const char* name, ValueType value) {
auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_global_attributes()[name]);
attr.set(value);
return attr.get();
}
// Convert file path to only the filename
std::string path_to_filename(std::string path) {
return path.substr(path.find_last_of("/\\")+1);
}
void init() {
// New attributes that hold filename and line number
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0));
// A file log with time, severity, filename, line and message
logging::add_file_log (
keywords::file_name = "sample.log",
keywords::format = (
expr::stream
<< expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f")
<< ": <" << boost::log::trivial::severity << "> "
<< '[' << expr::attr<std::string>("File")
<< ':' << expr::attr<int>("Line") << "] "
<< expr::smessage
)
);
// A console log with only time and message
logging::add_console_log (
std::clog,
keywords::format = (
expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
<< " | " << expr::smessage
)
);
logging::add_common_attributes();
}
int main(int argc, char* argv[]) {
init();
src::severity_logger<logging::trivial::severity_level> lg;
CUSTOM_LOG(lg, debug) << "A regular message";
return 0;
}
The statement CUSTOM_LOG(lg, debug) << "A regular message"; generates two outputs, writing a log file with this format...
2015-10-15_15:25:12.743153: <debug> [main.cpp:61] A regular message
...and outputs to the console this:
2015-10-15 16:58:35 | A regular message

Another possibility is to add line and file attributes to each log record after they are created. This is possible since in newer releases. Attributes added later do not participate in filtering.
Assuming severity_logger identified with variable logger:
boost::log::record rec = logger.open_record(boost::log::keywords::severity = <some severity value>);
if (rec)
{
rec.attribute_values().insert(boost::log::attribute_name("Line"),
boost::log::attributes::constant<unsigned int>(__LINE__).get_value());
... other stuff appended to record ...
}
The above would, of course, get wrapped into convenient macro.
Later you can show this attribute using custom formatter for the sink:
sink->set_formatter( ...other stuff... << expr::attr<unsigned int>("Line") << ...other stuff... );
Unlike previous answer, this approach requires more custom code and can't use off-the-shelf boost logging macros.

For posterity's sake - I made this set of macros for very simple logging needs, which has served me well - for simple logging needs. But they illustrate how to do this in general, and the concept easily works with Boost. They are meant to be local to one file (which is running in multiple processes, sometimes in multiple threads in multiple processes). They are made for relative simplicity, not speed. They are safe to put in if statements etc. to not steal the else. At the beginning of a function in which one wants to log, one calls
GLogFunc("function name");
Then one can do this to log a complete line:
GLogL("this is a log entry with a string: " << some_string);
They are as so -
#define GLogFunc(x) std::stringstream logstr; \
std::string logfunc; \
logfunc = x
#define GLog(x) do { logstr << x; } while(0)
#define GLogComplete do { \
_log << "[PID:" << _my_process << " L:" << __LINE__ << "] ((" << logfunc << ")) " << logstr.str() << endl; \
logstr.str(""); \
_log.flush(); \
} while(0)
#define GLogLine(x) do { GLog(x); GLogComplete; } while(0)
#define GLogL(x) GLogLine(x)
#define GLC GLogComplete
One can also build up a log over a few lines...
GLog("I did this.");
// later
GLog("One result was " << some_number << " and then " << something_else);
// finally
GLog("And now I'm done!");
GLogComplete;
Whatever stream _log is (I open it as a file in the class constructor, which is guaranteed to be safe in this instance) gets ouput like this:
[PID:4848 L:348] ((SetTextBC)) ERROR: bad argument row:0 col:-64
And they can be conditionally turned off and all performance penalty negated by a symbol at compilation time like so:
#ifdef LOGGING_ENABLED
... do the stuff above ...
#else
#define GLogFunc(x)
#define GLog(x)
#define GLogComplete
#define GLogLine(x)
#define GLogL(x)
#endif

Here is my solution.
Setup code
auto formatter =
expr::format("[ %3% %1%:%2% :: %4%]")
% expr::attr< std::string >("File")
% expr::attr< uint32_t >("Line")
% expr::attr< boost::posix_time::ptime >("TimeStamp")
% expr::smessage
;
/* stdout sink*/
boost::shared_ptr< sinks::text_ostream_backend > backend =
boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(&std::clog, NullDeleter()));
// Enable auto-flushing after each log record written
backend->auto_flush(true);
// Wrap it into the frontend and register in the core.
// The backend requires synchronization in the frontend.
typedef sinks::synchronous_sink< sinks::text_ostream_backend > sink2_t;
boost::shared_ptr< sink2_t > sink_text(new sink2_t(backend));
logging::add_common_attributes();
sink_text->set_formatter(formatter);
The log usage code (short version):
rec.attribute_values().insert("File", attrs::make_attribute_value(std::string(__FILE__))); \
full version :
#define LOG(s, message) { \
src::severity_logger< severity_level > slg; \
logging::record rec = slg.open_record(keywords::severity = s); \
if (rec) \
{ \
rec.attribute_values().insert("File", attrs::make_attribute_value(boost::filesystem::path(__FILE__).filename().string())); \
rec.attribute_values().insert("Line", attrs::make_attribute_value(uint32_t(__LINE__))); \
logging::record_ostream strm(rec); \
strm << message; \
strm.flush(); \
slg.push_record(boost::move(rec)); \
} \
}\
If I define global attribute (like people adviced before), i.e.
logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>(""));
then I get empty files/stiring.

Related

systemtap userspace function tracing

I have a simple c++ program
main.cpp
#include <iostream>
using namespace std;
int addition (int a, int b)
{
int r;
r=a+b;
return r;
}
int main ()
{
int z;
z = addition (5,3);
cout << "The result is " << z;
}
I want to generate the function tracing for this
- print function names and its input output and return types
My systemtap script : para-callgraph.stp
#! /usr/bin/env stap
function trace(entry_p, extra) {
%( $# > 1 %? if (tid() in trace) %)
printf("%s%s%s %s\n",
thread_indent (entry_p),
(entry_p>0?"->":"<-"),
probefunc (),
extra)
}
probe $1.call { trace(1, $$parms) }
probe $1.return { trace(-1, $$return) }
My C++ Exec is called : a ( compiled as g++ -g main.cpp)
Command I run
stap para-callgraph.stp 'process("a").function("*")' -c "./a > /dev/null"
0 a(15119):->_GLOBAL__I__Z8additionii
27 a(15119): ->__static_initialization_and_destruction_0 __initialize_p=0x0 __priority=0x0
168 a(15119): <-__static_initialization_and_destruction_0
174 a(15119):<-_GLOBAL__I__Z8additionii
0 a(15119):->main
18 a(15119): ->addition a=0x0 b=0x400895
30 a(15119): <-addition return=0x8
106 a(15119):<-main return=0x0
Here ->addition a=0x0 b=0x400895 : its address and not actual values ie 5, 3 which I want.
How to modify my stap script?
This appears to be a systemtap bug. It should print the value of b, not its address. Please report it to the systemtap#sourceware.org mailing list (with compiler/etc. versions and other info, as outlined in man error::reporting.
As to changing the script, the $$parms part is where the local variables are being transformed into a pretty-printed string. It could be changed to something like...
trace(1, $$parms . (#defined($foobar) ? (" foobar=".$foobar$) : ""))
to append foobar=XYZ to the trace record, whereever a parameter foobar is available. To work around the systemtap bug in question, you could try
trace(1, $$parms . (#defined($b) ? (" *b=".user_int($b)) : ""))
to dereference the b variable as if it were an int *.

c++ File IO, html conversion

Here is a brief discription of the books programming project I am trying to do...
Write a program that reads in a C++ source file and converts all ‘<’ symbols to “<” and all ‘>’ symbols to “>” . Also add the tag <PRE> to the beginning of the file and </PRE> to the end of the file. This tag preserves whitespace and formatting in the HTML document. Your program should create a new file with the converted output. To implement this, you should write a function ‘convert’ that takes the input and output streams as parameters.
I am having issues trying to get the program to work correctly. What's happening is the program will create a new file with .html but it is not converting anything in the file. (i.e. adding <PRE> to the beginning and </PRE> to the end and converting all '<' symbols to &lt and '>' to &gt).
I've been messing with it for a while now and I'm honestly not sure where I am going wrong. I'm super new to programming in general and even more new to c++ so please be nice haha.
Here is my code, any help is greatly appreciated!!
Thanks!
Scott
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <cstdlib>
using namespace std;
// main function
int main() {
// Input file to convert
string filename;
// Output file with .html on the end
string outputname;
char c;
int i;
ifstream inStream;
ofstream outStream;
cout << "Enter filename you woudl like to convert: " << endl;
cin >> filename;
// Open the input file
inStream.open(filename.c_str());
if (inStream.fail()) {
cout << "I/O failure opening file." << endl;
exit(1);
}
// Create the output file
outputname = filename + ".html";
outStream.open(outputname.c_str());
// First, output the <PRE> tag
outStream << "<PRE>" << endl;
// Loop through the input file intil nothing else to get
while (!inStream.eof()) {
inStream.get(c); // Get one character
// Output < or > or original char
if (c == '<') {
outStream << "<";
}
else if (c=='>') {
outStream << ">";
}
else outStream << c;
}
// Output end /PRE tag
outStream << "</PRE>" << endl;
inStream.close();
outStream.close();
cout << "Conversion done. Results are in file " << outputname << endl;
}

Downloaded page source is different than the rendered page source

I'm planning to get data from this website
http://www.gpw.pl/akcje_i_pda_notowania_ciagle
(it's a site of the main stock market in Poland)
I've got a program written in C++ that downloads source of the site to the file.
But the problem is that it doesn't contain thing I'm interested in
(stocks' value of course).
If you compare this source of the site to the option "View element" ( RMB -> View element)
you can see that "View element" does contain the stocks' values.
<td>75.6</td>
<tr class="even red">
etc etc...
The downloaded source of the site doesn't have this information.
So we've got 2 questions
1) Why does source of the site is different from the "View element" option?
2) How to transfer my program so that it can download the right code?
#include <string>
#include <iostream>
#include "curl/curl.h"
#include <cstdlib>
using namespace std;
// Write any errors in here
static char errorBuffer[CURL_ERROR_SIZE];
// Write all expected data in here
static string buffer;
// This is the writer call back function used by curl
static int writer(char *data, size_t size, size_t nmemb,
string *buffer)
{
// What we will return
int result = 0;
// Is there anything in the buffer?
if (buffer != NULL)
{
// Append the data to the buffer
buffer->append(data, size * nmemb);
// How much did we write?
result = size * nmemb;
}
return result;
}
// You know what this does..
void usage()
{
cout <<"curltest: \n" << endl;
cout << "Usage: curltest url\n" << endl;
}
/*
* The old favorite
*/
int main(int argc, char* argv[])
{
if (argc > 1)
{
string url(argv[1]);
cout<<"Retrieving "<< url << endl;
// Our curl objects
CURL *curl;
CURLcode result;
// Create our curl handle
curl = curl_easy_init();
if (curl)
{
// Now set up all of the curl options
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
// Attempt to retrieve the remote page
result = curl_easy_perform(curl);
// Always cleanup
curl_easy_cleanup(curl);
// Did we succeed?
if (result == CURLE_OK)
{
cout << buffer << "\n";
exit(0);
}
else
{
cout << "Error: [" << result << "] - " << errorBuffer;
exit(-1);
}
}
}
return 0;
}
Because the values are filled in using JavaScript.
"View source" shows you the raw source for the page, while "View Element" shows you the state the document tree is in at the moment.
There's no simple way to fix it, because you need to either execute the JavaScript or port it to C++ (and it would probably make you unpopular at the exchange).
When I save the page as an html file (file/save as), I get a file containing all data displayed in browser and which was not found in page source (I use Chrome).
So I suggest that you add one step in your code:
Download page from a javascript enabled browser that support command line or some sort of API (If curl can't do it, maybe wget or lynx/links/links2/elinks on linux can help you?).
Parse data.

std::find with type T** vs T*[N]

I prefer to work with std::string but I like to figure out what is going wrong here.
I am unable to understand out why std::find isn't working properly for type T** even though pointer arithmetic works on them correctly. Like -
std::cout << *(argv+1) << "\t" <<*(argv+2) << std::endl;
But it works fine, for the types T*[N].
#include <iostream>
#include <algorithm>
int main( int argc, const char ** argv )
{
std::cout << *(argv+1) << "\t" <<*(argv+2) << std::endl;
const char ** cmdPtr = std::find(argv+1, argv+argc, "Hello") ;
const char * testAr[] = { "Hello", "World" };
const char ** testPtr = std::find(testAr, testAr+2, "Hello");
if( cmdPtr == argv+argc )
std::cout << "String not found" << std::endl;
if( testPtr != testAr+2 )
std::cout << "String found: " << *testPtr << std::endl;
return 0;
}
Arguments passed: Hello World
Output:
Hello World
String not found
String found: Hello
Thanks.
Comparing types of char const* amounts to pointing to the addresses. The address of "Hello" is guaranteed to be different unless you compare it to another address of the string literal "Hello" (in which case the pointers may compare equal). Your compare() function compares the characters being pointed to.
In the first case, you're comparing the pointer values themselves and not what they're pointing to. And the constant "Hello" doesn't have the same address as the first element of argv.
Try using:
const char ** cmdPtr = std::find(argv+1, argv+argc, std::string("Hello")) ;
std::string knows to compare contents and not addresses.
For the array version, the compiler can fold all literals into a single one, so every time "Hello" is seen throughout the code it's really the same pointer. Thus, comparing for equality in
const char * testAr[] = { "Hello", "World" };
const char ** testPtr = std::find(testAr, testAr+2, "Hello");
yields the correct result

Parsing with Boost::Spirit (V2.4) into container

I just started to dig into Boost::Spirit, latest version by now -- V2.4.
The essense of my problem is following:
I would like to parse strings like "1a2" or "3b4".
So the rule I use is:
(double_ >> lit('b') >> double_)
| (double_ >> lit('a') >> double_);
The attribute of the rule must be "vector <double>". And I'm reading it into the container.
The complete code:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cstring>
int main(int argc, char * argv[])
{
using namespace std;
using namespace boost::spirit;
using namespace boost::spirit::qi;
using boost::phoenix::arg_names::arg1;
char const * first = "1a2";
char const * last = first + std::strlen(first);
vector<double> h;
rule<char const *, vector<double>()> or_test;
or_test %= (double_ >> lit('b') >> double_)
| (double_ >> lit('a') >> double_);
if (parse(first, last, or_test,h)) {
cout << "parse success: ";
for_each(h.begin(), h.end(), (cout << arg1 << " "));
cout << "end\n";
} else cout << "parse error\n" << endl;
return 0;
}
I'm compiling it with g++ 4.4.3. And it returns "1 1 2". While I expect "1 2".
As far as I understand this happens because parser:
goes to the first alternative
reads a double_ and stores it in the container
then stops at "a", while expecting lit("b")
goes to the second alternative
reads two more doubles
My question is -- Is this a correct behavior, and if yes -- why?
That's expected behavior. During backtracking Spirit does not 'unmake' changes to attributes. Therefore, you should use the hold[] directive explicitly forcing the parser to hold on to a copy of the attribute (allowing to roll back any attribute change):
or_test =
hold[double_ >> lit('b') >> double_)]
| (double_ >> lit('a') >> double_)
;
This directive needs to be applied to all alternatives modifying the attribute, except the last one.