Trying to derive from wfilebuf (filebuf) for logging - c++

I'm basically trying to derive from wfilebuf so I can both output to a file and intercept the output to print it to the console/debug window as well as illustrated here:
http://savingyoutime.wordpress.com/2009/04/21/ and/or here: http://savingyoutime.wordpress.com/2009/04/22/40/
(ancient supporting ideas here: http://www.horstmann.com/cpp/streams.txt)
I've almost got it, but I can't seem to be able to both write to the underlying file AND peek at the input.
I overrode the sync() function similar to the second example but it seems that pbase() and pptr() are always NULL unless I set a buffer with setp(...), but this seems to break the file output. The file is always empty!
My crude attempt at this is below:
class LoggerBuffer : public wfilebuf {
// Functions
public:
LoggerBuffer();
~LoggerBuffer();
void open(const wchar_t loggerFile[]);
void close();
int sync();
int_type overflow(int_type c = EOF);
void setState(int newState);
// Variables
private:
int currentState;
static const int BUFFER_SIZE = 10;
wchar_t buffer[BUFFER_SIZE];
};
class LoggerStream : public wostream {
// Functions
public:
LoggerStream();
~LoggerStream();
void open(const wchar_t loggerFile[] = 0);
void close();
void setState(int newState);
};
LoggerBuffer::LoggerBuffer() {
wfilebuf::open("NUL", wios::out); currentState = 1;
}
LoggerBuffer::~LoggerBuffer() {
wcout << "Destruction of LoggerBuffer" << endl;
}
void LoggerBuffer::open(const wchar_t loggerFile[]) {
wcout << "LoggerBuffer Opening " << loggerFile << endl;
close();
wfilebuf* temp = wfilebuf::open(loggerFile, wios::out); //ios::out | ios::app | ios::trunc
setp (buffer, buffer+(BUFFER_SIZE-1));
}
void LoggerBuffer::close() {
wfilebuf::close();
}
int LoggerBuffer::sync() {
wcout << " Syncing ";
int out_waiting = pptr() - pbase();
wcout << out_waiting << " characters!";
wcout << endl;
wcout << "pptr(): " << (unsigned int)pptr() << endl;
return wfilebuf::sync();
}
LoggerBuffer::int_type LoggerBuffer::overflow(int_type c) {
wcout << "overflow! (" << (wchar_t)c << ")" << endl;
if (c == EOF)
return EOF;
if (sync() == EOF)
return EOF;
return wfilebuf::overflow(c);
}
void LoggerBuffer::setState(int newState) {
wcout << "New buffer state = " << newState << endl;
currentState = newState;
}
LoggerStream::LoggerStream() : wostream(new LoggerBuffer), wios(0) {
}
LoggerStream::~LoggerStream() {
delete rdbuf();
}
void LoggerStream::open(const wchar_t loggerFile[]) {
wcout << "LoggerStream Opening " << loggerFile << endl;
((LoggerBuffer*)rdbuf())->open(loggerFile);
}
void LoggerStream::close() {
((LoggerBuffer*)rdbuf())->close();
}
void LoggerStream::setState(int newState) {
wcout << "New stream state = " << newState << endl;
((LoggerBuffer*)rdbuf())->setState(newState);
}
Full disclosure: I asked a question regarding something similar earlier: Simple wostream logging class (with custom stream manipulators)
I think I have solved that problem though.
Any help is greatly appreciated! Thanks!

I'd use a filtering streambuf, that does no buffering of its own, instead passing data through to a real streambuf (i.e., one that does real buffering) for each of the destinations. This should simplify your code quite a bit and let you concentrate on the parts you really care about.

Related

Making my function which calls async_read asynchronous Boost::asio

I am building an networking application, and being a newbie to Boost asio and networking as a whole had this doubt which might be trivial. I have this application which reads from a file and calls apis accordingly. I am reading json (example):
test.json
{
"commands":
[
{
"type":"login",
"Username": 0,
"Password": "kk"
}
]
}
My main program looks like this :
int main() {
ba::io_service ios;
tcp::socket s(ios);
s.connect({{},8080});
IO io;
io.start_read(s);
io.interact(s);
ios.run();
}
void start_read(tcp::socket& socket) {
char buffer_[MAX_LEN];
socket.async_receive(boost::asio::null_buffers(),
[&](const boost::system::error_code& ec, std::size_t bytes_read) {
(void)bytes_read;
if (likely(!ec)) {
boost::system::error_code errc;
int br = 0;
do {
br = socket.receive(boost::asio::buffer(buffer_, MAX_LEN), 0, errc);
if (unlikely(errc)) {
if (unlikely(errc != boost::asio::error::would_block)) {
if (errc != boost::asio::error::eof)
std::cerr << "asio async_receive: error " << errc.value() << " ("
<< errc.message() << ")" << std::endl;
interpret_read(socket,nullptr, -1);
//close(as);
return;
}
break; // EAGAIN
}
if (unlikely(br <= 0)) {
std::cerr << "asio async_receive: error, read " << br << " bytes" << std::endl;
interpret_read(socket,nullptr, br);
//close(as);
return;
}
interpret_read(socket,buffer_, br);
} while (br == (int)MAX_LEN);
} else {
if (socket.is_open())
std::cerr << "asio async_receive: error " << ec.value() << " (" << ec.message() << ")"
<< std::endl;
interpret_read(socket,nullptr, -1);
//close(as);
return;
}
start_read(socket);
});
}
void interpret_read(tcp::socket& s,const char* buf, int len) {
if(len<0)
{
std::cout<<"some error occured in reading"<<"\n";
}
const MessageHeaderOutComp *obj = reinterpret_cast<const MessageHeaderOutComp *>(buf);
int tempId = obj->TemplateID;
//std::cout<<tempId<<"\n";
switch(tempId)
{
case 10019: //login
{
//const UserLoginResponse *obj = reinterpret_cast<const UserLoginResponse *>(buf);
std::cout<<"*********[SERVER]: LOGIN ACKNOWLEDGEMENT RECEIVED************* "<<"\n";
break;
}
}
std::cout << "RX: " << len << " bytes\n";
if(this->input_type==2)
interact(s);
}
void interact(tcp::socket& s)
{
if(this->input_type == -1){
std::cout<<"what type of input you want ? option 1 : test.json / option 2 : manually through command line :";
int temp;
std::cin>>temp;
this->input_type = temp;
}
if(this->input_type==1)
{
//std::cout<<"reading from file\n";
std::ifstream input_file("test.json");
Json::Reader reader;
Json::Value input;
reader.parse(input_file, input);
for(auto i: input["commands"])
{
std::string str = i["type"].asString();
if(str=="login")
this->login_request(s,i);
}
std::cout<<"File read completely!! \n Do you want to continue or exit?: ";
}
}
The sending works fine, the message is sent and the server responds in a correct manner, but what I need to understand is why is the control not going to on_send_completed (which prints sent x bytes). Neither it prints the message [SERVER]: LOGIN ACKNOWLEDGEMENT RECEIVED, I know I am missing something basic or am doing something wrong, please correct me.
login_request function:
void login_request(tcp::socket& socket,Json::Value o) {
/*Some buffer being filled*/
async_write(socket, boost::asio::buffer(&info, sizeof(info)), on_send_completed);
}
Thanks in advance!!
From a cursory scan it looks like you redefined buffer_ that was already a class member (of IO, presumably).
It's hidden by the local in start_read, which is both UB (because the lifetime ends before the async read operation completes) and also makes it so the member _buffer isn't used.
I see a LOT of confusing code though. Why are you doing synchronous reads from within completion handlers?
I think you might be looking for the composed-ooperation reads (boost::asio::async_read and boost::asio::async_until)

Example: Debugging in OMNeT++

I know, this may be a lot to ask, but can anyone help me debug this code:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
class Node : public cSimpleModule
{
private:
cMessage *out_msg;
long no_sent = 0;
long no_rcvd = 0;
cOutVector rcvdRecord;
cLongHistogram Statistics;
public:
Node();
virtual ~Node();
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
virtual void finish() override;
};
Define_Module(Node);
Node::Node()
{
out_msg = nullptr;
}
Node::~Node()
{
delete out_msg;
}
void Node::initialize()
{
out_msg = nullptr;
if (strcmp("sender", getName()) == 0) {
EV << "Scheduling first send to t=5.0s\n";
scheduleAt(5.0, out_msg);
out_msg = new cMessage("Sending Message");
}
}
void Node::handleMessage(cMessage *msg)
{
if (msg == out_msg) {
EV << "Sending message to receiver\n";
send(out_msg, "out");
out_msg = nullptr;
no_sent++;
simtime_t delay = par("delayTime");
scheduleAt(simTime() + delay, out_msg);
}
else {
out_msg = msg;
no_rcvd++;
rcvdRecord.record(out_msg);
Statistics.collect(out_msg); //what's going on here ?
}
}
void Node::finish()
{
EV << "Sent: " << no_sent << endl;
EV << "Received: " << no_rcvd << endl;
EV << "Messages sent, mean: " << Statistics.getMean() << endl;
EV << "Messages sent, standard deviation: " << Statistics.getStddev() << endl;
EV << "Messages sent, variance: " << Statistics.getVariance() << endl;
recordScalar("#sent", no_sent);
recordScalar("#received", no_rcvd);
Statistics.recordAs("Message Statistics");
}
I get the following error message:
Exercise2.cc:66:38: error: no matching function for call to
'omnetpp::cOutVector::record(omnetpp::cMessage*&)'
Exercise2.cc:67:39: error: no matching function for call to
'omnetpp::cLongHistogram::collect(omnetpp::cMessage*&)'
So I really don't know what this is supposed to tell me. Aren't these built-in functions, part of the cOutVector or cLongHistogram classes respectively?
Aren't these built-in functions, part of the cOutVector or
cLongHistogram classes respectively?
They aren't. Well, cOutVector does have a member function named record, it just can't take a cMessage * as an argument, so that specific function overload you wanted to use doesn't exist. Same with cLongHistogram and collect.
Just take a look at the documentation:
A cOutVector object can write doubles to the output vector file ...
And, by the way, what exactly do you expect to see as a "histogram of messages"? :D This comic comes to my mind...
To record the messages (not into a cOutVector), you can enable event logging. The resulting file can be visualized in the Sequence Chart tool of the IDE, see: https://docs.omnetpp.org/tutorials/tictoc/part2/#25-visualizing-on-a-sequence-chart

Code working inline, but when in class

I'm writing program using Boost::Asio, I want to implement simple chat. Currently I'm struggling with problem that when I put some code inline of class function it's working, but when same code is provided by another class object is not. I think it could be connected to Boost::Asio, but I'm not sure:
void Connection::session(socket_ptr sock)
{
try{
for(;;) {
char mesg[1024];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(mesg), error);
if (error == boost::asio::error::eof){
disconnected(sock);
break;
}
else if (error)
throw boost::system::system_error(error);
message msg(mesg,length);
char *data;
data = msg.getData();
std::cout << "In session " << strlen(data) << " " << data;
/*This is working
string s_msg,s_data;
s_msg = mesg;
s_data = s_msg.substr(2,length);
std::vector<char> writable(s_data.size() + 1);
std::copy(s_data.begin(), s_data.end(), writable.begin());
std::cout << "In session " << strlen(&writable[0]) << " " << &writable[0];
send_all(sock,&writable[0],strlen(&writable[0]));
*/
send_all(sock,data,strlen(data));
}
}
catch (std::exception& e){
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
Class message that is only parsing data
message::message(char *c_msg, size_t length)
{
msg = c_msg;
id = msg.at(0);
data = msg.substr(2,length);
}
char* message::getData()
{
std::vector<char> writable(data.size() + 1);
std::copy(data.begin(), data.end(), writable.begin());
std::cout << data;
std::cout << &writable[0];
return &writable[0];
}
So when using class message this line:
std::cout << "In session " << strlen(data) << " " << data;
I get:
st String //this is cout from message getData
st String //this is cout from message getData
In session 0
With inline version:
In session 11 st String
So, in session function string is empty although message cout shows something opposite.
I don't know if it's important, but this function is invoked as new thread from main.
Regards,
Piotr
You're returning the address of a temporary:
char* message::getData()
{
std::vector<char> writable(data.size() + 1);
//...
return &writable[0];
}
This is undefined behaviour.
I'm assuming that data is just a std::string. You could do this instead:
const char* message::getData() const
{
return data.c_str();
}

Resetting the cout after redirection

I have a program in c++, during the program i use :
static ofstream s_outF(file.c_str());
if (!s_outF)
{
cerr << "ERROR : could not open file " << file << endl;
exit(EXIT_FAILURE);
}
cout.rdbuf(s_outF.rdbuf());
Meaning i redirect my cout to a file.
What would be the easiest way to return the cout back to the standard output?
thanks.
Save the old streambuf before you change cout's streambuf :
auto oldbuf = cout.rdbuf(); //save old streambuf
cout.rdbuf(s_outF.rdbuf()); //modify streambuf
cout << "Hello File"; //goes to the file!
cout.rdbuf(oldbuf); //restore old streambuf
cout << "Hello Stdout"; //goes to the stdout!
You can write a restorer to do that automatically as:
class restorer
{
std::ostream & dst;
std::ostream & src;
std::streambuf * oldbuf;
//disable copy
restorer(restorer const&);
restorer& operator=(restorer const&);
public:
restorer(std::ostream &dst,std::ostream &src): dst(dst),src(src)
{
oldbuf = dst.rdbuf(); //save
dst.rdbuf(src.rdbuf()); //modify
}
~restorer()
{
dst.rdbuf(oldbuf); //restore
}
};
Now use it based on scope as:
cout << "Hello Stdout"; //goes to the stdout!
if ( condition )
{
restorer modify(cout, s_out);
cout << "Hello File"; //goes to the file!
}
cout << "Hello Stdout"; //goes to the stdout!
The last cout would output to stdout even if condition is true and the if block is executed.

Checking to see if ofstream is empty?

I've created an ofstream and there is a point in which I need to check if it's empty or has had things streamed into it.
Any ideas how I would go about doing this?
The std::ofstream files don't support this directly. What you can do if this is an important requirement is to create a filtering stream buffer which internally used std::filebuf but also records if there was any output being done. This could look look as simple as this:
struct statusbuf:
std::streambuf {
statusbuf(std::streambuf* buf): buf_(buf), had_output_(false) {}
bool had_output() const { return this->had_output_; }
private:
int overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
this->had_output_ = true;
}
return this->buf_->overflow(c);
}
std::streambuf* buf_;
bool had_output_;
};
You can initialize an std::ostream with this and query the stream buffer as needed:
std::ofstream out("some file");
statusbuf buf(out.rdbuf());
std::ostream sout(&buf);
std::cout << "had_output: " << buf.had_output() << "\n";
sout << "Hello, world!\n";
std::cout << "had_ouptut: " << buf.had_output() << "\n";
you could use ofstream.rdbuff to get the file buffer and than use streambuf::sgetn to read it. I believe that should work.