Boost Log Time Zone - c++

I've been learning the Boost Log library
http://www.boost.org/doc/libs/develop/libs/log/doc/html/index.html
but I've been unable to figure out how to display the user's time zone. There is a %q and %Q format option that looks promising but doesn't seem to work (I'm using MSVC++ 2013). Using this format "%Y-%m-%d %H:%M:%S.%f%Q", I get the following output:
1 [2015-08-18 21:27:16.860724] main.cpp#11, Test App Started.
but I would have expected
1 [2015-08-18 21:27:16.860724-08.00] main.cpp#11, Test App Started.
as explained in:
http://www.boost.org/doc/libs/develop/libs/log/doc/html/log/detailed/expressions.html#log.detailed.expressions.formatters
Here's the code I've been trying and a few commented out lines that I have also tried with no luck:
void Log::init() const
{
boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::utc_clock());
// boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock());
boost::log::register_simple_formatter_factory<Severity, char>("Severity");
// boost::log::register_formatter_factory("TimeStamp", boost::make_shared<timestamp_formatter_factory>());
boost::log::add_common_attributes();
boost::log::add_file_log
(
boost::log::keywords::file_name = "appname_%N.log",
boost::log::keywords::rotation_size = 10 * 1024 * 1024,
boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
boost::log::keywords::format =
boost::log::expressions::stream
<< boost::log::expressions::attr<unsigned>("LineID") << " "
<< "[" << boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f%Q"<< "]" << " "
<< "<" << boost::log::expressions::attr<Severity>("Severity") << _NSTR(">") << _NSTR(" ")
<< boost::log::expressions::smessage
// "%LineID% [%TimeStamp(format=\"%Y-%m-%d %H:%M:%S.%f%Q\")%] <%Severity%>: %%Message%"
);
const auto severity = boost::log::expressions::attr<Severity>("Severity");
boost::log::core::get()->set_filter
(
severity >= severityThreshold_
);
}
Any suggestions on what I might be doing wrong?

Both utc_clock and local_clock produce values of type boost::posix_time::ptime, which do not have information of a time zone. The difference between the clocks is what time ptime represents - UTC or local time according to the time zone set on the machine. The formatter has no use for %Q and %q and replaces them with an empty string.
The time zone is present in the boost::local_time::local_date_time type, the %Q and %q placeholders will work for it. The library does not have a clock attribute that produces local_date_time, so you will have to write one yourself. See here for an example.

Related

Running arbitrary SQL commands MySQL C++ (X DevAPI)?

I've connected my C++ project to MySQL and successfully created a session. I was able to create a Schema. My issue is that when I try to run simple arbitrary queries like USE testSchema SHOW tables; using the MySQL/C++ api, I run into SQL syntax errors. When I run the function directly in the MySQL shell, the query runs perfectly fine.
Here is the full code
const char* url = (argc > 1 ? argv[1] : "mysqlx://pct#127.0.0.1");
cout << "Creating session on " << url << " ..." << endl;
Session sess(url);
{
cout << "Connected!" << endl;
// Create the Schema "testSchema"; This code creates a schema without issue
cout << "Creating Schema..." << endl;
sess.dropSchema("testSchema");
Schema mySchema = sess.createSchema("testSchema");
cout << "Schema Created!" << endl;
// Create the Table "testTable"; This code runs like normal, but the schema doesn't show
cout << "Creating Table with..." << endl;
SqlStatement sqlcomm = sess.sql("USE testSchema SHOW tables;");
sqlcomm.execute();
}
Here is the console output:
Creating session on mysqlx://pct#127.0.0.1 ...
Connected!
Creating Schema...
Schema Created!
Creating Table with...
MYSQL ERROR: CDK Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1
The error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SHOW tables' at line 1 is a MySQL error that means I have a syntax error in the query, but when I take a closer look at a query, I see there is nothing wrong with it.
I've copied and pasted the code directly from the cpp file into the mysql shell and it runs perfectly. This tells me that something is up with the formatting of how I'm entering the query in the sql() function. But the documentation for the sql() function is really terse and.
Here is the reference to the sql() function: https://dev.mysql.com/doc/dev/connector-cpp/8.0/class_session.html#a2e625b5223acd2a3cbc5c02d653a1426
Can someone please give me some insight on where I'm going wrong? Also here here is the full cpp code for more context:https://pastebin.com/3kQY8THC
Windows 10
Visual Studio 2019
MySQL 8.0 with Connect/C++ X DevAPI
You can do it in two steps:
sess.sql("USE testSchema").execute();
SqlStatement sqlcomm = sess.sql("SHOW tables");
SqlResult res = sqlcomm.execute();
for(auto row : res)
{
std::cout << row.get(0).get<std::string>() << std::endl;
}
Also, you can use the Schema::getTables():
for(auto table : mySchema.getTables())
{
std::cout << table.getName() << std::endl;
}
Keep in mind that the Schema::getTables() doesn't show the Collections created by Schema::createCollection(). There is also a Schema::getCollections():
for(auto collection : mySchema.getCollections())
{
std::cout << collection.getName() << std::endl;
}

How to write mongocxx (v3) query with Date data type?

I have a collection and I need to extract only most recent data based on field updateDate (with data type Date).
I use c++ driver (mongocxx (v3) ).
mongocxx::cursor cursor =
collection.find(document{} << "updateDate" <<
open_document << "$gt" <<
(date parameter) << close_document <<
finalize);
for(auto doc : cursor) {
std::cout << bsoncxx::to_json(doc) << "\n";
}
How can I write my query for instance:
what format, data type I need to pass as day?
Thank you.
You can do something like this :
replace (date parameter) with bsoncxx::types::b_date{<value>}

boost log format single attribute with logging::init_from_stream

When I set up format params in code, to format date time output I can use something like this
logging::formatter simpleFormat(expr::format("%1% %2%") %
expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S") %
expr::smessage
);
But when I initialize logger with a config file, I can specify format only in attributes position notation, not their format details.
so, this line in a boost log config file
Format="[%TimeStamp%]: %Message%"
produces output:
[2015-Feb-06 09:32:27.401496]: blah blah blah
I want to reduce timestamp to something like this
[06.02.2015 09:32:27]
How can it be described in boost log config file, ot it cant be done at all?
Preamble
My answer is valid for boost 1.55 (haven't tested with latest one). And it was only tested with MSVC 2013 compiler.
Answer
Looks like you need custom formatter_factory for TimeStamp attribute to be able to specify it's format. This works for me:
#include <fstream>
#include "boost/shared_ptr.hpp"
#include "boost/log/trivial.hpp"
#include "boost/log/expressions.hpp"
#include "boost/log/utility/setup.hpp"
#include "boost/log/support/date_time.hpp"
class timestamp_formatter_factory :
public boost::log::basic_formatter_factory<char, boost::posix_time::ptime>
{
public:
formatter_type create_formatter(boost::log::attribute_name const& name, args_map const& args)
{
args_map::const_iterator it = args.find("format");
if (it != args.end())
return boost::log::expressions::stream << boost::log::expressions::format_date_time<boost::posix_time::ptime>(boost::log::expressions::attr<boost::posix_time::ptime>(name), it->second);
else
return boost::log::expressions::stream << boost::log::expressions::attr<boost::posix_time::ptime>(name);
}
};
int main()
{
// Initializing logging
boost::log::register_formatter_factory("TimeStamp", boost::make_shared<timestamp_formatter_factory>());
boost::log::add_common_attributes();
std::ifstream file("settings.ini");
boost::log::init_from_stream(file);
// Testing
BOOST_LOG_TRIVIAL(info) << "Test";
return 0;
}
And now it your settings file you can specify format argument for TimeStamp attribute. Like this:
[Sinks.ConsoleOut]
Destination=Console
AutoFlush=true
Format="[%TimeStamp(format=\"%Y.%m.%d %H:%M:%S\")%]: %Message%"
You should be able to use set_formatter as documented here
sink->set_formatter
(
expr::stream << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
);

Set severity filter for sinks of a Boost.Log severity logger instance

I am using Boost.Log 1.55.0 in a project and I do want to change the severity filter for all sinks of a boost::log::sources::severity_logger instance.
Here's an example how-to setup one sink with an initial severity filter:
void InitializeLogging(LogLevels const kLogLevel) const {
auto line_id = boost::log::expressions::attr<unsigned int>("LineID");
auto severity = boost::log::expressions::attr<LogLevels>("Severity");
auto timestamp = boost::log::expressions::format_date_time<boost::posix_time::ptime>(
"TimeStamp",
"%Y-%m-%d %H:%M:%S");
boost::log::formatter const kFormatter{
boost::log::expressions::stream
<< std::setw(6) << std::setfill('0') << line_id
<< std::setfill(' ')
<< ": " << timestamp
<< " [" << severity << "] "
<< boost::log::expressions::smessage};
using TextSink = boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>;
boost::shared_ptr<TextSink> sink = boost::make_shared<TextSink>();
boost::shared_ptr<std::ostream> stream(&std::clog, boost::empty_deleter());
sink->locked_backend()->add_stream(stream);
sink->set_filter(severity >= kLogLevel);
sink->set_formatter(kFormatter);
boost::log::core::get()->add_sink(sink);
boost::log::add_common_attributes();
}
So I am able to setup the filtering when I create the sink via the member function set_filter, but I want to know how-to modify the filter of one/more/all sinks that are configured for the core of Boost.Log.
Is there any function I did not see yet to modify existing sinks?
If not, do I have to remove the sinks from the core and "re-create" them?
I found out the solution by myself. Therefore I will answer my two questions here:
Such a function does not exist, or I am unable to find it.
No, it is possible to set the filter for all sinks by calling the function set_filter on the core of Boost.Log. I am using the following function for my custom severity log levels:
void log_level(LogLevels const kLogLevel) {
boost::log::core::get()->set_filter(boost::log::expressions::attr<CustomLogLevels>("Severity") >= kLogLevel);
}
Sidenote: Removing all sinks from the core is possible by calling boost::log::core::get()->remove_all_sinks(), but not necessary in my use case.
I found the following to be a simple way to change the filter:
Given the following setup performed during log initialization:
boost::shared_ptr<file_sink> mSink;
mSink(new file_sink(keywords::file_name = "BoostLog_%Y%m%d_%3N.txt", keywords::rotation_size = 500 * 1024))
mSink->set_filter(severity >= error);
I logged lots of messages with the original filter, then I changed the filter to a new severity level with the following:
mSink->reset_filter();
mSink->set_filter(severity >= warning);
The logging then payed attention to the new filter setting.

c++ convert postgres timestamp without time zone to time_t

I'm connecting from c++ to postgreSQL using libpq library. I request and obtain the date (timestamp without time zone) from postgreSQL, but the result has an offset that I don't know how to fix.
Postgres table:
id date
integer timestamp without time zone
29996 2014-02-28 23:59:00
result in C++ code:
id: 29996, Date: Sat Mar 01 10:59:00 2014
You can see that the date has the offset. Below is the code that I'm using. Any help will be greatly appreciated
PGconn *m_connection;
PGresult *res;
string strConn = "dbname=test host=localhost user=username password=secret";
m_connection = PQconnectdb(strConn.c_str());
string query = "SELECT id, extract(epoch from date)::bigint ";
query += "FROM table_test ORDER BY id DESC LIMIT 1";
// send query
res = PQexecParams(m_connection, query.c_str(), 0, 0, 0, 0, 0, 0);
string id = PQgetvalue(res, 0, 0);
unsigned char *data = (unsigned char*)PQgetvalue( res, 0, 1 );
unsigned int length = PQgetlength( res, 0 , 1 );
time_t time = _atoi64( (char*)data );
PQclear(res);
std::cout << "id:"<< id << ", Date: " << ctime(&time) << "\n";
The issue is that ctime uses localtime, so that ends up in the offset.
If you want GMT, then you should use asctime(gmtime(&time)), which will give you a date/time without localtime influences.
ctime is the equivalent of asctime(localtime(&time))