Sign in to follow this  

Quickie logging class for lambasting

This topic is 4667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone. As part of my experimenting with simple templates and familiarizing myself with the STL I threw together this tiny logging class. I'd be grateful for any feedback, particularly in the areas of design. Is there something particularly limiting with this sort of thing? Is it a terrible idea? Is it not generic enough, or perhaps did I forget a scenario when taking things into consideration? I imagine there's quite a few copying nuances I don't know about that would cause headaches in actual use... This would likely be expanded to provide things like timestamping or log rotation. It'd also likely be used by a larger class which handles an entire app's logging or more generic file use.
#include <iostream>
#include <fstream>
#include <string>

using namespace std;
class   testlog {
//
// test log
//
// Handles logging to a particular file.
//
private:
        fstream         fd;
        string          filename;

public:
        testlog(string,int=0);
        ~testlog();

        template <typename T> ostream &operator<<(T in);
        bool                    is_filename(string);
        bool                    is_good();
};

testlog::~testlog(){
//
//
//
fd.close();
}

testlog::testlog(string infn, int append){
//
// testlog constructor
//
// Takes a filename, and an append flag.
//  Defaults to overwrite.
//
if (append){
        fd.open(infn.c_str(),iostream::out | iostream::app );
}else{
        fd.open(infn.c_str(),iostream::out);
}
filename=infn;
}

bool    testlog::is_filename(string in){
//
// testlog is_filename()
//
// Returns true if in == file opened for logging and is good.
//

return(in == filename && is_good());
}



bool    testlog::is_good(){
//
//
//
return(fd.good());
}


template <typename T>
        ostream &testlog::operator<<(T in){
        //
        // input operator.
        //
        // Takes input, and passes it along to fd.
        //
        fd << in;
        return(fd);
}

Thanks once again to everyone's help here, and any help to come. With some of the feedback from this I'll venture into something perhaps a little more involved.

Share this post


Link to post
Share on other sites
I haven't looked at your code yet, but if you want to look into a 'case study' for a logging class that uses STL, look no further than Fluid Studios - Logger Class. It should be of good use for you to study and see something a little bit more involved. All I have to say is that it is of great merit! it should have most of the things you are looking for - the timestamp and stuff, just look at how you can customize it. Use it as 'inspiration' [wink]

- Drew

[Edited by - Drew_Benton on March 9, 2005 1:00:09 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Telastyn
Your second link has an extra " in it...

But that is interesting. It looks almost like a mini-implimentation of syslog.


Thanks for that. I think I accidenty typed out the double quotes [lol].

Anyways your code looks nice and simple. However there are a few things I would change. Just a few personal quirks.

For one thing, there should be a seperate function that does what the constructor does. Just in case you wanted an array of them [wink]. A little more error checking would be useful, just to make sure fd is valid at all times. I mean if something were to happen and the file could not be opened, i.e. infn == "", then you could have some serious bugs and crashes. That's just a few things I see right away.

The constructor thing is just my preference, but you should definitly do the fd validation. Other than that good job. It's definitly a good starting base to expand upon. Just remember to keep it simple [smile]! Cheers

- Drew

Share this post


Link to post
Share on other sites
So, toying around a little more, I've run across... unexpected behavior.

The current incarnations of the files:

teststream.h

#include <iostream>
#include <fstream>
#include <string>

using namespace std;
template <typename S>
class teststream {
//
// test log
//
// Handles logging to a particular file.
//
private:
S fd;
string filename;
bool retry();
public:
teststream(string,int=0);
~teststream();

istream& getline(char *,streamsize);
template <typename T> ostream &operator<<(T in);
template <typename T> istream &operator>>(T out);
bool is_filename(string);
bool is_good();
};

template <typename S>
teststream<S>::~teststream(){
//
//
//
fd.close();
}

template <typename S>teststream<S>::teststream(string infn, int append){
//
// testlog constructor
//
// Takes a filename, and an append flag.
// Defaults to overwrite.
//
if (append){
fd.open(infn.c_str(),iostream::in | iostream::out | iostream::app );
}else{
fd.open(infn.c_str(),iostream::in | iostream::out);
}
filename=infn;
}

template <typename S>
bool teststream<S>::is_filename(string in){
//
// testlog is_filename()
//
// Returns true if in == file opened for logging and is good.
//

return(in == filename && is_good());
}


template <typename S>
bool teststream<S>::is_good(){
//
//
//
return(!fd.bad());
}

template <typename S>
bool teststream<S>::retry(){
//
// Used to try and reopen fd...
//
long x;

x=fd.tellp();
fd.close();
fd.open(filename.c_str(),iostream::out | iostream::app);
if (is_good()){
fd.seekp(x);
fd << "testlog: Log reopened in retry().\n";
return(1);
}else{
return(0);
}
}


template <typename S>
istream& teststream<S>::getline(char *a,streamsize n){
//
//
//
fd.getline(a,n);
return(fd);
}

template <typename S>
template <typename T>
ostream &teststream<S>::operator<<(T in){
//
// input operator.
//
// Takes input, and passes it along to fd.
//
if (is_good() || retry()){
fd << in;
return(fd);
}else{
cerr << "Stream \"" << filename << "\" died, cerr: "<< in;
return(cerr);
}
}


template <typename S>
template <typename T>
istream &teststream<S>::operator>>(T out){
//
// input operator.
//
// Takes input, and passes it along to fd.
//
if (is_good() || retry()){
fd >> out;
return(fd);
}else{
cerr << "Stream \"" << filename << "\" died.";
return(fd);
}
}


typedef teststream<fstream> filelog;



loggertest.cc

#include <sstream>
#include "teststream.h"

int main(){

filelog test("test.log",0);
int x=42;
float y=5.5;
char moo[]="moo";
int x1;
float y1;
string moo1;
char *moo2;
moo2=(char *)malloc(512);

//test << x << y << moo << "\n";
test >> moo2;
cout << moo2;


}



so, test.log was created using the commented lines above. It is '425.5moo\n'. The above works fine, and prints the log [minus the newline...].
If I change moo2 to moo1 [use string rather than char*] nothing is displayed, and the program exits.

I'm guessing it's some sort of buffering/flush issue? Hrm. More investigation required I guess.

Share this post


Link to post
Share on other sites
If you are going for that syntax of useing the << and >>, take a look into the STL stringstream as well. As long as the object has the << operator overloaded, you can use it similarly to your log class. I'm not trying to discourage you from your own class, but just letting you know of some more useful tools at your disposal [wink]

- Drew

Share this post


Link to post
Share on other sites
Well, the functionality I'm trying to duplicate is kind of similar to what I currently have in non-templated form.

Currently, I can take arbitrary lists of objects, and create an arbitrary list of text. That list of text can then go to stdout(list of text) or file(filename, list of text) or network(socket, list of text) or something like game_renderer(list of text).

I'm just fiddling around to see if I can use this sort of thing to eliminate some of the disadvantages to that currect setup [many concatination calls or sprintf() sort of formattings; and where the text is being sent is hard-coded; and text back to object is less elegant]

I imagine the network and game_renderer implimentations will use a teststream<stringstream> sort of buffer.

Share this post


Link to post
Share on other sites
Well, the functionality I'm trying to duplicate is kind of similar to what I currently have in non-templated form.

Currently, I can take arbitrary lists of objects, and create an arbitrary list of text. That list of text can then go to stdout(list of text) or file(filename, list of text) or network(socket, list of text) or something like game_renderer(list of text).

I'm just fiddling around to see if I can use this sort of thing to eliminate some of the disadvantages to that currect setup [many concatination calls or sprintf() sort of formattings; and where the text is being sent is hard-coded; and text back to object is less elegant]

I imagine the network and game_renderer implimentations will use a teststream<stringstream> sort of buffer.

Share this post


Link to post
Share on other sites

This topic is 4667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this