Archived

This topic is now archived and is closed to further replies.

MindWipe

Logging, how do I do that?

Recommended Posts

MindWipe    940
I just need a funktion that saves some text like "DirectDraw init - OK" and/or "Shutdown complete" But the only save to file method I know saves it like many weird ACHII. Can anyone post his/her log funktion? I need a easy to use funktion like AddToLog("bla bla"); I thankful for any help /MindWipe "If it doesn''t fit, force it; if it breaks, it needed replacement anyway."

Share this post


Link to post
Share on other sites
der_meista    122
the easiest way would be file streams
you create the objekt
check if its ok
and store data by using just the << operator

example:
ofstream save(strFileName);

if (save.good())
{
save << somthing << something_else;
}
save.close();

you can save any basic type from int to char

der_meista

Share this post


Link to post
Share on other sites
nullguid    122
Have you tried following:

At init:
FILE* log=fopen("mylog.txt","wt");

when at any place
fprintf(log,"DirectDraw init OK\n");

and at end:
fclose(log);

This is more convenient than streams cause you may use expression like:
fprint(log,"%s %d %f",string,intval,floatval);
to print values to log (I found it very useful, and not only I)

Or you programming in Delphi of Visual Basic?
Hope you find it useful

Edited by - nullguid on January 29, 2001 2:48:36 PM

Share this post


Link to post
Share on other sites
phueppl1    122
something like this?

    
bool State_Protokollfileopened = false;
void Log(char* st, ...)
{
if(st == NULL)
return;

FILE* protokollfile = fopen("protokoll.log", "a+t");
if(State_Protokollfileopened)
{
fseek(protokollfile, 0, SEEK_SET);
State_Protokollfileopened = true;
}
else
fseek(protokollfile, 0, SEEK_END);

char output[800];
va_list ap;
va_start(ap, st); // Parses The String For Variables

vsprintf(output, st, ap); // And Converts Symbols To

va_end(ap);

fprintf(protokollfile, "%s\n", output);

fclose(protokollfile);
}



I just took this from my leveleditor. had to take some things out, so if somethings wrong, just e-mail me....
cya,
Phil

Uh, btw.. you can use this function just as any format function (just like sscanf, fprintf, printf, an so on)...

Visit Rarebyte!
and no!, there are NO kangaroos in Austria (I got this questions a few times over in the states

Edited by - phueppl1 on January 29, 2001 2:48:17 PM

Share this post


Link to post
Share on other sites
MindWipe    940
nullguid> Yup I''m using C++, I think I''ll use your method. Looks easiest. Thankx.

/MindWipe

"If it doesn''t fit, force it; if it breaks, it needed replacement anyway."

Share this post


Link to post
Share on other sites
Houdini    266
MindWipe, if you use C++ you might want to consider creating a LogFile class and make it a little more robust (support for multiple log files, debug levels for logging, displaying message to output window and/or printer, etc).

BTW, if you are going to log successful function calls (ie, DirectDraw init - OK) I''d recommend against opening/closing your file after every single log. It''ll kill your performance.


- Houdini

Share this post


Link to post
Share on other sites
Spanky    138
I would love to see multiple log files supported as well as auto indenting. So if you are like loading a level, you could indent it and show all the portions of the level that loaded... that would be nice

Timestamping would be a nice and easy feature as well.

Spanky

Share this post


Link to post
Share on other sites
You can also keep a log in RAM, which you''d want to do if you had a drop-down console for users to read as it is updated. You''d also need something like this for a message queue for RPGs or strategy games (conversations for RPGs, commands issued for strategy games). It would be this:


  
struct MessageLog
{
char* Message;
MessageLog* NextEntry;
};
//

MessageLog g_Log; // I''ll use a global for this example

//

void InitLog ( )
{
g_Log.Message = NULL;
g_Log.NextEntry = NULL;
}
//

void AddEntry ( char* NewMessage )
{
MessageLog* Temp;

if( !g_Log.Message ) g_Log.Message = NewMessage;
else
{
Temp = &g_Log;
//

while( Temp->NextEntry )
Temp = Temp->NextEntry;

Temp->NextEntry = new MessageLog;
Temp->NextEntry->Message = NewMessage;
Temp->NextEntry->NextEntry = NULL;
}
}
//

void DeleteLog ( )
{
MessageLog* Temp;
MessageLog* Next;
//

if( g_Log.Message ) delete [] g_Log.Message;
g_Log.Message = NULL;
Temp = g_Log.NextEntry;
g_Log.NextEntry = NULL;
//

while( Temp )
{
if( Temp->Message ) delete [] Temp->Message;
Next = Temp->NextEntry;
delete Temp;
Temp = Next;
}
}


~CGameProgrammer( );

Share this post


Link to post
Share on other sites
Xai    1838
I''ve created 3 variations of a general purpose logging module ... 2 variations for windows and 1 for BeOS ... and I just wanted to say ... Houdini ... in windows you must open/close your log file (at least in debug mode - or at least periodically) - because when your program spins/crashes/or locks ... you loose your entire log if it''s open ...you dont even get the stuff that was in it last time you closed ...so your log file MUST be closed at all times except the split second it''s logging.

One way to make this efficient is to have a fixed sized (to avoid dynamic memory overhead) internal buffer ... say 2-10KB in size (remember 4 lines at 255 is 1KB) and simply keep an index .. when the index gets to the end ... open the file ... copy the whole buffer in one call ... reset the index ... close the file.

In BeOS this is totally unnessesary ... the journalled file system retains everything .. if i send a byte to an open file ... then kill my program or pull power out of the socket ... when i reboot .. that byte is in the file ... neat huh

The 2 versions for windows are as follows ... the simple one .. which has a constructor which takes a file name and a logging threashold (so unimportant messages dont get logged) ... and a log method which takes the following: LogType (exception, debug data, execution trace, message), LogSeverity(the number that determines if the log should get loged at current log level), Source Module(the module of code in which the log call resides .. duh),LogDetails(a string which contains the specific information for this particular log). It is worth mentioning that these 4 values comprise a class I call LogEvent ... which represents a simple entity to log to the file .. and this class is derived from my Exception base class ...so you can do this

  
; assume EXCEPTION is an enum value for the EventType
; assume MAJOR_EXCEPTION is a #define for a numeric constant

if(!ProcessInput())
throw LogEvent(EXCEPTION,MAJOR_ERROR,"InputServer","ProcessInput() failed");


then ... if that exception gets handled ...good ...if not ... when you get out to the main catch block ...you can not only see what the error was ..but its fairly easy to go from the log file right to the subsection of you program that might have throw it and do a grep or FindInFiles for the message string "ProcessInput() failed"

When runtime efficiency becomes an issue ... you replace the 3rd and 4th parameters with 32 bit int .. which you define in a central location ... and then use #defines ...so it looks like this:

  
LogEvent(EXCEPTION,FATAL_ERROR,MODULE_IO,EXP_PROCESS_INPUT_FAILED);


so you can still see all the details right in the code ... but only 4 ints are being created and passed around the program ... helps avoid really large string data areas and/or unneccesary dynamic memory allocation.

The second windows logging module I have is identical, but adds named block nesting to the log ... this stuff is useless in multithreaded code ... but it works great for people not yet using threads.

I also have additional heavyweight stuff in a debug only version .. which can have different logging levels set based on source module ... or turn on and off logging of certain types of logs (such as ... turn DebugInfo logging off....) ... but this overhead is too great to leave in release code ... so i don''t use it much. I''ve found all you really need is that single discriminating threashold ... and in debug only senerios ... the ability to tell the logger to additionally log everything from just one specified module ... that''s it ...

Whew ..that was a long post ..I''ll clean the code up this week/weekend .. if someone can just tell me how to make it availible ...I will .. it is thouroughly tested ... But I''m only going to post the easy to use simple version .. don''t want any confusing support headaches - and it''s what I use in real code anyway.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Tip 1:

You will want to log a message using minimum (typing) effort because you will be logging a lot. So if you put the logfunctions in a (singleton/static) class its best to use a macro to access them.

  
class Log {
public:
static Log *instance();
void log(const char *formattedMessage, ...);
};

#define log Log::instance()->log


This code allows you to log messages like this:
  
log("Checking var: %d", i);


Tip 2:

Using polymorphism is a highly flexible way to route messages realtime. For example, you could have different classes that can route messages to a logfile on disk, the debug panel in VC, a console, stdout or whatever.

A simple implementation would be:

  
class Log {
public:
class Output {
virtual void write(const char *message) = 0;
};
class FileOutput : public Output {
protected:
FILE *file;
public:
void write(const char *message){
fprintf(message);
}

FileOutput(const char *filename){
file = fopen(filename, "wt");
if(!file) throw Exception("Can''t create logfile");
}
}
protected:
Output *output; // Current output class


public:
void logTo(Output *output);
void log(const char *message){
output->write(message);
}
};


Tip 3:

Don''t take message logging too lightly and make something crappy quick.
Its one of the best debugging tools you will ever get so spend some time on it to make it good.

Share this post


Link to post
Share on other sites
Countach    122
Apologies for the post above.
It has some errors and I forgot to login.
Administrators: please remove it.

Tip 1:

You will want to log a message using minimum (typing) effort because you will be logging a lot. So if you put the logfunctions in a (singleton/static) class its best to use a macro to access them.

  
class Log {
public:
static Log *instance();
void log(const char *formattedMessage, ...);
};

#define log Log::instance()->log


This code allows you to log messages like this:

log("Checking var: %d", i);


Tip 2:

Using polymorphism is a highly flexible way to route messages realtime. For example, you could have different classes that can route messages to a logfile on disk, the debug panel in VC, a console, stdout or whatever.

A simple implementation would be:

        
class Log {
public:
class Output {
virtual void write(const char *message) = 0;
};
class FileOutput : public Output {
protected:
FILE *file;
public:
void write(const char *message){
fprintf(message);
}

FileOutput(const char *filename){
file = fopen(filename, "wt");
if(!file) throw Exception("Can't create logfile");
}
~FileOutput(){
fclose(file);
}
};
protected:
Output *output; // Current output class


public:
void logTo(Output *output){
if(this->output != null) delete this->output;
this->output = output;
}
void log(const char *message){
if(output != null) output->write(message);
}

Log() : output(null) {}
~Log(){ logTo(null); }
};


The implementation of this system with the Singleton pattern is as follows:

  
Log::instance()->logTo(new Log::FileOutput("log.txt"));
log("Log opened");
Log::destroyInstance();


Obviously this produces a file with the contents 'Log opened'

Tip 3:

Don't take message logging too lightly and make something crappy quick.
Its one of the best debugging tools you will ever get so spend some time on it to make it good.

BTW: This sourcecode is something I thought up from the top of my head. Being the genius that I am its probably bugfree but I make no warranties. :-)

Edited by - Countach on January 30, 2001 4:44:18 AM

Share this post


Link to post
Share on other sites
MindWipe    940
Thanks everyone for all the help!

BUT! Many of the replies was a bit to complicated for me.
I just need:

- one funktion that makes a new txt-file (or re-make one)
- one that adds text to it, and closes it(If the program breaks)

That''s all. So that I can ie.

StartLogging("Log.txt");
Log("DDInit okey...");

Adding ints, and stuff to the log file would ofcourse help alot

/MindWipe

"If it doesn''t fit, force it; if it breaks, it needed replacement anyway."

Share this post


Link to post
Share on other sites