Formatted Logging with parameters not working - visual-c++

I'm writing in VC++ with VS2012 pro and trying to get my logger to output something like this
03/26/2013 Registry()+
03/26/2013 Registry::LoadDWORD("VersionNumber")+;
03/26/2013 Registry(3)-
with the following lines of code
RegistryHelper::RegistryHelper()
{
LogWriter::WriteStart("Registry");
}
bool RegistryHelper::LoadDWORDValue(char* entry, UINT defaultValue, UINT& returnValue)
{
LogWriter::WriteStart("Registry::LoadDWORD", entry);
//Code to get DWORD
LogWriter::WriteEnd("Registry::LoadDWORD", returnValue);
return true;
}
The code I have thus far is this
void LogWriter::WriteStart(const char* log, ...)
{
tcout << log << "(";
va_list argptr;
va_start(argptr, log);
vfprintf(stderr, log, argptr);
va_end(argptr);
std::wcout << ")+" << EOL;
}
as a test I wrote this.
LogWriter::WriteStart("Registry", "Something", "else", "Start", "STop");
char* entry = "VersionNumber";
LogWriter::WriteStart("Registry", entry);
LogWriter::WriteStart("Registry");
but i am only getting back
2013-03-26.11:41:15 Registry()+
2013-03-26.11:41:15 Registry()+
2013-03-26.11:41:15 Registry()+
but i am expecting back
2013-03-26.11:41:15 Registry(Something, else, Start, STop)+
2013-03-26.11:41:15 Registry(VersionNumber)+
2013-03-26.11:41:15 Registry()+
With some playing around with it (mainly grabbing code from online and try a few different things) I've been able to make it say Registry(Registry)+ but is about as close as I've come. (I was using a while loop and checking for NULL) I'm somewhat new to VC++ and very new to using params (sorry i'm a C# guy). This is as far as I've gotten in about 1 hour of playing around with it. What am I doing wrong?

You are attempting to use variable-number-of-arguments feature on top of *printf function, but you are not passing any format specifier (like %d, %s) when you are calling WriteStart.
A call should be like:
LogWriter::WriteStart("Registry %s", entry);
Also, you need not to hard-code the function name to indate from where the log is being generated. The statement:
LogWriter::WriteStart("Registry::LoadDWORD", entry);
Can easily be replaced with:
LogWriter::WriteStart(__FUNCTION__, entry); // I am ignoring the format-specifier here
__FUNCTION__ will be replaced by fully-qualified function name by the preprocessor.
Moreover, you can also craft a macro that will take care of all this:
#define WRITE_LOG(_smsg) \
LogWriter::WriteStart(__FUNCTION__ , _smsg);
And use it:
WRITE_LOG("Your log message"); // Again, I ignore format-specifier here and in macro.
If you are using macro, and using variable-argument function with format specifier, you can use __VA_ARGS__ along with macro itself.

Try
std::cout << log << "(";
va_list argptr;
va_start(argptr, log);
vfprintf(stdout, log, argptr); // use same stream here!
va_end(argptr);
std::cout << ")+" << EOL;

Better - just pass whatever output stream you wish to use as an argument:
void LogWriter::WriteStart(FILE *fp, const char* log, ...)
{
fprintf (fp, "(");
va_list argptr;
va_start(argptr, log);
vfprintf(fp, log, argptr);
va_end(argptr);
fprintf (fp, ")\n");
}

Related

Calling a templated funtion using a thread object [duplicate]

Well I have an issue with passing data into a thread using std::thread. I thought I understood the general semantics of copy constructors, etc. but it seems I don't quite grasp the problem. I have a simple class called Log that has hidden it's copy constructor thusly:
class Log
{
public:
Log(const char filename[], const bool outputToConsole = false);
virtual ~Log(void);
//modify behavior
void appendStream(std::ostream *);
//commit a new message
void commitStatus(const std::string str);
private:
//members
std::ofstream fileStream;
std::list<std::ostream *> listOfStreams;
//disable copy constructor and assignment operator
Log(const Log &);
Log & operator=(const Log &);
}
now I have a main based heavily on http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cpp
int main()
{
static int portNumber = 10000;
Log logger("ServerLog.txt", true);
logger.commitStatus("Log Test String");
try {
boost::asio::io_service ioService;
server(ioService, portNumber, logger);
}
catch (std::exception &e)
{
std::cerr << "Exception " << e.what() << std::endl;
logger.commitStatus(e.what());
}
return 0;
}
You can see that main calls the function server and passes the IOService, portNumber and logger. The logger is passed by reference, thusly:
using boost::asio::ip::tcp;
void server(boost::asio::io_service &ioService, unsigned int port, Log &logger)
{
logger.commitStatus("Server Start");
tcp::acceptor acc(ioService, tcp::endpoint(tcp::v4(), port));
while(true)
{
tcp::socket sock(ioService);
acc.accept(sock);
std::thread newThread(session, &sock, logger);
newThread.detach();
}
logger.commitStatus("Server closed");
}
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference, but I do not get the error when passing it to the session() by reference
static void session(tcp::socket *sock, Log &logger)
{
std::cout << " session () " << std::endl;
}
Now I thought that I understood correctly that a reference is the same as passing a pointer. That is, it does not call the copy constructor, it simply passes the pointer, which it lets you syntactically treat like it's not a pointer.
error C2248: 'Log::Log' : cannot access private member declared in class 'Log'
1> \log.h(55) : see declaration of 'Log::Log'
1> \log.h(28) : see declaration of 'Log'
...
: see reference to function template instantiation 'std::thread::thread(_Fn,_V0_t &&,_V1_t)' being compiled
1> with
1> [
1> Fn=void (_cdecl *)(boost::asio::ip::tcp::socket *,Log &),
1> _V0_t=boost::asio::ip::tcp::socket *,
1> _V1_t=Log &
1> ]
However if I modify it to pass a pointer, everything is happy
...
std::thread newThread(session, &sock, &logger);
...
static void session(tcp::socket *sock, Log *logger)
{
std::cout << " session () " << std::endl;
}
Why is passing by reference calling my copy constructor. Is there something special happening here because of std::thread? Did I misunderstand the copy constructor and pass by reference?
I get a different but equally baffling error if I try to use std::move() as it is done in the example. Is it possible my VS2012 is not implementing C++11 correctly?
std::thread takes its arguments by value. You can get reference semantics back by using std::reference_wrapper:
std::thread newThread(session, &sock, std::ref(logger));
Obviously you must make sure that logger outlives the thread.
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference
It is not sufficient for the thread's entrypoint function to take a reference type: the thread object itself takes its arguments by value. This is because you usually want a copy of objects in a separate thread.
To get around this, you may pass std::ref(logger), which is a reference wrapper hiding reference semantics under a copyable object.

C++ Locking stream operators with mutex

I need to lock stdout in my logging application to prevent string interleaving in multi-thread applications logging to stdout. Can't figure out how to use move constructor or std::move or sth else to move unique_lock to another object.
I created objects for setting configs and encapsulation and figured out how to lock stdout with static std::mutex to lock from these objects (called shards).
Something like this works for me:
l->log(1, "Test message 1");
While that is fine and could be implemented with templates and variable number of parameters I would like to approach more stream-like possibilities. I am looking for something like this:
*l << "Module id: " << 42 << "value: " << 42 << std::endl;
I dont want to force users to precompute string with concatenation and to_string(42) I just want to find a way to lock stdout.
My approach so far was to create operator << and another object locked stream, as was suggested in other answers. Things is I can't figure how to move mutex to another object. My code:
locked_stream& shard::operator<<(int num)
{
static std::mutex _out_mutex;
std::unique_lock<std::mutex> lock(_out_mutex);
//std::lock_guard<std::mutex> lock (_out_mutex);
std::cout << std::to_string(num) << "(s)";
locked_stream s;
return s;
}
After outputting input to std::cout I woould like to move lock into object stream.
In this case, I would be careful not to use static locks in functions, as you will get a different lock for each stream operator you create.
What you need is to lock some "output lock" when a stream is created, and unlock it when the stream is destroyed. You can piggie back on existing stream operations if you're just wrapping std::ostream. Here's a working implementation:
#include <mutex>
#include <iostream>
class locked_stream
{
static std::mutex s_out_mutex;
std::unique_lock<std::mutex> lock_;
std::ostream* stream_; // can't make this reference so we can move
public:
locked_stream(std::ostream& stream)
: lock_(s_out_mutex)
, stream_(&stream)
{ }
locked_stream(locked_stream&& other)
: lock_(std::move(other.lock_))
, stream_(other.stream_)
{
other.stream_ = nullptr;
}
friend locked_stream&& operator << (locked_stream&& s, std::ostream& (*arg)(std::ostream&))
{
(*s.stream_) << arg;
return std::move(s);
}
template <typename Arg>
friend locked_stream&& operator << (locked_stream&& s, Arg&& arg)
{
(*s.stream_) << std::forward<Arg>(arg);
return std::move(s);
}
};
std::mutex locked_stream::s_out_mutex{};
locked_stream locked_cout()
{
return locked_stream(std::cout);
}
int main (int argc, char * argv[])
{
locked_cout() << "hello world: " << 1 << 3.14 << std::endl;
return 0;
}
Here it is on ideone: https://ideone.com/HezJBD
Also, forgive me, but there will be a mix of spaces and tabs up there because of online editors being awkward.

Transform an operation to generic method

I am working in visual c++, usually I do it on .NET, because I need a method which is available only on this language. What I want to do is obtain the frames per second of a video file. The best I could make was creating a project with this main() method, in which (after Debug) I could see the result is saving fine in the res variable.
void main()
{
// initialize the COM library
CoInitialize(NULL);
// get a property store for the video file
IPropertyStore* store = NULL;
SHGetPropertyStoreFromParsingName(L"C:\\Users\\Public\\Videos\\Sample Videos\\Wildlife.wmv",
NULL, GPS_READWRITE, __uuidof(IPropertyStore), (void**)&store);
// get the frame rate
PROPVARIANT variant;
store->GetValue(PKEY_Video_FrameRate, &variant);
int res = variant.intVal;
store->Release();
}
Now, I want to create this method generic, in order to obtain the frameRate of any video. For example, if the method's name is frameRate:
char* path = "C:\\Users\\Public\\Videos\\Sample Videos\\Wildlife.wmv";
int fps = frameRate(path);
Thanks
Does this not work?
int getFrameRate(std::wstring path)
{
// initialize the COM library
CoInitialize(NULL);
// get a property store for the video file
IPropertyStore* store = NULL;
SHGetPropertyStoreFromParsingName(path.c_str(),
NULL, GPS_READWRITE, __uuidof(IPropertyStore), (void**)&store);
// get the frame rate
PROPVARIANT variant;
store->GetValue(PKEY_Video_FrameRate, &variant);
int res = variant.intVal;
store->Release();
return res;
}
The assumption here is that SHGetPropertyStoreFromParsingName takes a string as its first parameter. In C++ I recommend staying away from char*, std::string is preferable in almost all situations. The only difficulty I see is making sure path is the correct type.
If you don't want to recompile your code for every video path, then you can read the path from the program parameters. To do that, modify you main() as follows:
int main(int argc, char* argv[])
{
if (argc != 2)
{
std::cout << "You have to specify the video path!" << std::endl;
return 1;
}
const char* path = arg[1];
// Rest of the program logic
return 0;
}
You can pass more than one parameter, if you want to. Note that there is always at least 1 argument (arg[0] is the program name). For further reading on the topic go here.

Create MFC DLL from C/C++ (VS 2010) code to be used by C# WCF web service

I have a third party component written in C/C++ (on VS 2010) which can be downloaded here.
This component accepts 3 parameters as input (a filename and two numbers) and outputs a result in the console, and then outputs a file.
I've used Process and ProcessStartInfo in a C# WinForm project to consume this component which works fine. However, now I want to consume this in a WCF C# RESTful service, in which case the solution I thought with WinForm will not work.
It was suggested that I instead convert this to a MFC DLL and then use InterOp to call the unmanaged DLL through my C# web service (other suggestions are welcome).
Unfortunately, I have no idea on how to do that and my knowledge on C/C++ is fairly average. So my question is: How do I create a DLL from that component which accepts these 3 parameters (taken from main()):
cin >> fname;
cin >> minA;
cin >> minO;
then does whatever calculations it's supposed to do and return this (again taken from main()):
cout << "\nNumber is: " << num;
(and obviously still output the file it's supposed to output) ?
Any help would be HIGHLY appreciated.
Thanks in advance!
UPDATE: As a point of reference, here is my WinForm implementation mentioned above.
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
Process cmdProcess = new Process();
BackgroundWorker BWorker = new BackgroundWorker();
//is able to report progress
BWorker.WorkerReportsProgress = true;
//is able to be cancelled
BWorker.WorkerSupportsCancellation = true;
//attach events
BWorker.DoWork += worker_DoWork;
BWorker.RunWorkerCompleted += worker_RunWorkerCompleted;
BWorker.RunWorkerAsync();
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (firstTimeLoaded)
{
cmdStartInfo.FileName = Path.GetFullPath("../../Resources/thirdparty.exe");
cmdStartInfo.WorkingDirectory = Path.GetFullPath("../../Resources/");
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.SynchronizingObject = this;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.Exited += cmd_Exited;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginErrorReadLine();
firstTimeLoaded = false;
}
while (!cmdProcess.HasExited)
{
if (use)
{
if (BWorker.CancellationPending)
{
e.Cancel = true;
}
StringBuilder builder = new StringBuilder();
//read unbuffered output
while (cmdProcess.StandardOutput.Peek() != -1)
{
char inputChar = (char)cmdProcess.StandardOutput.Read();
if (inputChar != '\r' && inputChar != '\n')
{
builder.Append(inputChar);
}
if (inputChar == '\n')
{
break;
}
}
if (cmdProcess.StandardOutput.Peek() == -1)
{
cmdProcess.StandardOutput.DiscardBufferedData();
}
//process the output
string output = builder.ToString();
//determine appropriate action
switch (output)
{
case "Enter file name: ":
cmdProcess.StandardInput.WriteLine(textBox1.Text);
break;
case "Enter minimum size of A: ":
cmdProcess.StandardInput.WriteLine(textBox2.Text);
break;
case "Enter minimum size of O: ":
cmdProcess.StandardInput.WriteLine(textBox3.Text);
break;
}
if (output.Contains("Number: "))
{
MessageBox.Show("Number is: " + output.Substring(output.LastIndexOf(" ") + 1));
use = false;
}
}
}
}
Let's give this a try.
In VS2010, create a Win32 Project under Visual C++/Win32. For this purpose, call it MyWin32Lib.
Add the thirdparty.cpp file to the project and compile. You should get some warnings, but it's ok.
Create a new header file called thirdparty.h so we can export the function signature.
In the thirdparty.h file, do:
#pragma once
// This will be the interface for third party file
int concepts(char* szFileName, int nMinIntent, int nMinExtent);
In the thirdparty.cpp file, add #include "stdafx.h" right before #include
Change the main function signature to match the one in the header:
//int main()
// Instead of getting input from console, we're passing it the values
int concepts(char* szFileName, int nMinIntent, int nMinExtent)
Comment out all input requests, and just copy the args to the local vars:
//cout << "\n\n***** In-Close 3.0 Concept Miner *****";
//cout << "\n\nEnter cxt file name including extension: ";
//cin >> fname;
//cout << "\nEnter minimum size of intent (no. attributes): ";
//cin >> minIn;
//cout << "\nEnter minimum size of extent (no. objects): ";
//cin >> minEx;
strcpy_s(fname, _countof(fname), szFileName);
minIn = nMinIntent;
minEx = nMinExtent;
Comment out cout << "\nNumber... (this is no longer needed)
At the end of the function, do:
break;
}
//cout << "\n\nHit <enter> to finish";
//while ( !_kbhit());
return numcons;
}
I don't know why there's a while(1) since there's no way to get out of it, but assume we'll doing it only once.
Make sure you compile ok.
Create a new CPP file, call it "Concepts.cpp"
In Concepts.cpp, enter:
#include "stdafx.h"
#include "thirdparty.h"
extern "C"
{
__declspec(dllexport) int GetConcepts(char* szFileName, int nMinIntent, int nMinExtent)
{
return concepts(szFileName, nMinIntent, nMinExtent);
}
}
*You should now have a Win32 DLL that performs the work using arguments instead.
Create a C# Class Library project.
Create a C# class called "Concepts.cs"
In this class, enter:
public class Concepts
{
// Link to the Win32 library through InterOp
[DllImport("MyWin32Lib.dll")]
public static extern int GetConcepts(
[MarshalAs( UnmanagedType.LPStr )] string fileName, int minIntent, int minExtent );
}
*You have to marshal the filename input as ANSI since that's what thirdparty.cpp uses.
I think I got all of it. You can now reference your C# library from a web service.

open existing sqlite3 database under QT

I am very new to QT and SQLite DBMS. I am trying to open an existing database created using "sqlite3" command-line program under ubuntu Linux. The same database I am trying to access under QT using the following code :
void MainWindow::func()
{
QSqlQuery query;
accounts_db = new QSqlDatabase();
*accounts_db = QSqlDatabase::addDatabase("QSQLITE");
perror("? ");
accounts_db->setDatabaseName("/home/user/xyz.db");
QSqlError *a = new QSqlError();
*a = accounts_db->lastError();
perror(a->text().toLatin1());
if (!accounts_db->open()) {
perror("database open error :");
}
if ( !accounts_db->isOpen() ) {
perror("database is not open");
}
query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts");
while(query.next()) {
QString str = query.value(0).toString();
std::cerr << qPrintable(str) << std::endl;
}
end:
;
}
This fails with the following errors...
No such file or directory
: Invalid argument
QSqlQuery::exec: database not open
Notice that I get "No such file or directory" after adddatabase(), have no clue whatsoever which file is it talking about. Also notice that isOpen() and open() are returning "true" (???). The "database not open" error is from db.exec() call (...I suppose...).
In desperate need of guidance...
The constructor of QSqlQuery with no parameters uses the default database for your application. Maybe it is not set yet. Use the constructor specifying the database the query is required to use:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection_name");
// Open db...
QSqlQuery query(db);
if (!query.exec(...)) {
// ...
}
// ...
Pay attention to how you close the connection afterwards.
EDIT: This is a test I just wrote and is working on my system. You might want to try.
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>
int main(int argc, char *argv[])
{
// Create database.
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "Connection");
db.setDatabaseName("/tmp/test.db");
if (!db.open()) {
qDebug("Error occurred opening the database.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Insert table.
QSqlQuery query(db);
query.prepare("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, text TEXT)");
if (!query.exec()) {
qDebug("Error occurred creating table.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Insert row.
query.prepare("INSERT INTO test VALUES (null, ?)");
query.addBindValue("Some text");
if (!query.exec()) {
qDebug("Error occurred inserting.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Query.
query.prepare("SELECT * FROM test");
if (!query.exec()) {
qDebug("Error occurred querying.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
while (query.next()) {
qDebug("id = %d, text = %s.", query.value(0).toInt(),
qPrintable(query.value(1).toString()));
}
return 0;
}
This is mostly guessing, since your code is wrong on quite a few things, including the error reporting.
The most likely problem is that your file path is simply not right, or the user you're running your application with does not have the appropriate permissions on the file and/or directory. (Note: files and directory are case sensitive in Linux.)
perror should only be used after calling a system function that actually failed and that sets errno when it does. Qt doesn't do that.
Please try running this, and update your question if you still cannot resolve your issue:
void MainWindow::func()
{
// Note: no pointer!
QSqlDatabase accounts_db = QSqlDatabase::addDatabase("QSQLITE");
accounts_db.setDatabaseName("/home/user/xyz.db");
if (!accounts_db.open())
{
qDebug() << "Could not open database file:";
qDebug() << accounts_db.lastError();
return;
}
// Note: don't construct queries before you have a database!
QSqlQuery query;
if (!query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts"))
{
qDebug() << "Query failed:";
qDebug() << query.lastError();
return;
}
while(query.next()) {
QString str = query.value(0).toString();
std::cerr << qPrintable(str) << std::endl;
}
}
(I haven't even tried to compile this, so YMMV.)
Have a look at the SQL examples also, and look at how they handle all this there.
Alright, I created a brand new database file using sqlite3 command, now the same program in my question is working !!!.
I had also tried this before, but that time it did not work (...I hate it when that happens). I guess the previous file may be corrupted. But the previous database file could be accessed from cmdline sqlite3 program, so I was assuming that file was ok,...but apparently not.
Anyway, thanks a lot guys for giving me time, and very sorry if I wasted it :( .
I am marking this as an answer just for the sake of clarity that this question is answered. But its not exactly an answer (...because I still don't understand what was happening !? )
Thanks again...
EDIT :
Here is the code
QSqlError *a = new QSqlError();
accounts_db = new QSqlDatabase();
*accounts_db = QSqlDatabase::addDatabase("QSQLITE");
accounts_db->setDatabaseName("/home/user/test.db");
if ( !accounts_db->open() ) {
qDebug() << accounts_db->lastError();
qDebug() << "Could not open database file:";
}
QSqlQuery query;
if ( !(accounts_db->isOpen()) ) {
qDebug() << accounts_db->lastError();
qDebug() << ": Could not open database file:";
goto end; // quit if not successful
}
query.exec("select * from accounts");
while(query.next()) {
// loop for i columns
QString str = query.value(i).toString();
std::cerr << qPrintable(str) << std::endl ;
// loop
}
end:
;

Resources