Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » log file for game

This thread is locked; no one can reply to it. rss feed Print
log file for game
William Labbett
Member #4,486
March 2004
avatar

Need some advice on how to deal with the log file in my game.

The way I do things at the moment is :

#ifdef USE_LOG_FILE
   logfile << "some message about something.\n";
#endif

So the code only runs if there's a define for USE_LOG_FILE in a header somewhere.

What I'm thinking of doing instead is :-

if(use_log)
{
   logfile << "........\n";
}

Where the use_log is a variable set in the config file for the game.

This way means that the code is always run, even if it's just checking the if condition.

Is this way an acceptable way to do things ?

I prefer it because it means the log file doesn't have to get created.

LennyLen
Member #5,313
December 2004
avatar

Is this way an acceptable way to do things ?

Certainly. The checks aren't going to affect the game performance, and it means the logs can easily be enabled after the application has already been deployed, which is not possible when using the preprocessor method.

The only downside is that if the logs are never needed, the executable will be bigger than necessary. But the additional size is most likely insignificant, so this is a mostly moot point.

Quote:

I prefer it because it means the log file doesn't have to get created.

That applies to both methods.

William Labbett
Member #4,486
March 2004
avatar

Thanks.

Slartibartfast
Member #8,789
June 2007
avatar

#ifdef USE_LOG_FILE
logfile << "some message about something.\n";
#endif

This is usually done like:

#ifdef USE_LOG_FILE
#define LOG(blah) logfile<<(blah)
#else
#define LOG(blah)
#endif
...
LOG(".....\n");

Quote:

if(use_log)
{
logfile << "........\n";
}

Also nice. You could similarly stick that into an inlined function and have an easier time typing it; You can even use varargs to make it behave more like you'd expect a logging function to behave.

Though maybe I'm saying obvious things.

beoran
Member #12,636
March 2011

And an example in plain C:

#SelectExpand
1/* 2Log file example with allegro config file use. 3Compile with gcc on Linux: 4 5gcc forum_2.c -I /usr/local/include -L /usr/local/lib -lallegro_color -lallegro_font -lallegro_ttf -lallegro -o forum2 6 7Make an app.ini file in the executable file's directory that contains 8log=app.log and the log will be written to app.log. If the config value is 9empty, no logging takes place. 10*/ 11 12#include <allegro5/allegro.h> 13#include <stdio.h> 14#include <stdarg.h> 15 16 17#define APP_CONFIG_NAME "app.ini" 18 19FILE * log_open() { 20 FILE * result; 21 ALLEGRO_CONFIG * config; 22 const char * logname; 23 config = al_load_config_file(APP_CONFIG_NAME); 24 if (!config) return NULL; 25 logname = al_get_config_value(config, NULL, "log"); 26 if (logname) { 27 result = fopen(logname, "at"); 28 } 29 al_destroy_config(config); 30 return result; 31} 32 33void log_close(FILE * logfile) { 34 if(logfile) fclose(logfile); 35} 36 37void log_log(FILE * logfile, char * format, ...) { 38 va_list ap; 39 if (!logfile) return; 40 va_start(ap, format); 41 vfprintf(logfile, format, ap); 42 va_end(ap); 43 fflush(logfile); 44} 45 46 47int main (void) { 48 FILE * logfile = log_open(); 49 log_log(logfile, "This will be logged, but only if app.ini specifies it.\n"); log_log(logfile, "And with arguments: %d, %f\n", 11, 20.13); 50 log_close(logfile); 51 return 0; 52}

LennyLen
Member #5,313
December 2004
avatar

beoran said:

And an example in plain C:

That looks almost identical to mine, except that I add a timestamp to each line as it is written to the log.

beoran
Member #12,636
March 2011

Yeah, LennyLen, and with some changes and a macro or two you can get _LINE_ and _FILE_ in there as well. Just flex it to your own needs. :)

Luiji99
Member #12,254
September 2010

Also very useful, but not vital since you can gleam it from __FILE__ and __LINE__, is __func__. However, __func__ is C99 and MSVC calls it __FUNCTION__. Luckily, Allegro 5 is awesome and will automatically define __func__ as __FUNCTION__ for MSVC and will simply define it to "???" where not supported. I'd recommend log lines like:

__FILE__:__LINE__:__func__: Super important message

I.e.

kernel.c:1924:farbiktubennagen: Holy shit look a dog!!!!!

Programming should be fun. That's why I hate Java.

GullRaDriel
Member #3,861
September 2003
avatar

I like these threads. Pinned !

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Thomas Fjellstrom
Member #476
June 2000
avatar

Luiji99 said:

Also very useful, but not vital since you can gleam it from _FILE_ and _LINE_, is _func_. However, _func_ is C99 and MSVC calls it __FUNCTION__.

GCC also has __FUNCTION__ it also has __PRETTY_FUNCTION__ which helps out with C++ somewhat.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

William Labbett
Member #4,486
March 2004
avatar

Thanks for the help guys.

I like

if(use_log)
{
   logfile << "Initialising tertiary subsystem 3.\n";
}

It's super simple.

If I have to use conditional includes then there's two versions of the program, one which can do logs and another that can't. I'd rather have one program that can do both depending on config file.

I think I'll do

LOG(x) (if(use_log) logfile << x << "\n";)

Luiji99
Member #12,254
September 2010

That type of #define is good, too. In fact, I'd definitely recommend that over two executables considering you want it to be enabled/disabled by the user. You could still use #define LOG(x) (use_log ? logfile << __FILE__ << ":" __LINE__ ":" << __PRETTY_FUNCTION__ << ": " << (x) : (void) 0)

I'm pretty sure that putting an if statement in parenthesis is invalid. You will have to use the tertiary operator like boolean_value ? true_execution : (void) 0, as most implementations of assert do.

Programming should be fun. That's why I hate Java.

Audric
Member #907
January 2001

The general issue of "; in macro?" is solved by a construct, seemingly ugly but fully working:
#define MYMACRO do { your stuff } while (0)

Luiji99
Member #12,254
September 2010

I'd imagine that the assert method would be more efficient, only because I haven't yet found an implementation of assert that uses the do {} while(0) kludge.

Programming should be fun. That's why I hate Java.

bamccaig
Member #7,536
July 2006
avatar

#SelectExpand
1class Logger 2{ 3 bool enabled_; 4 std::ofstream log_; 5public: 6 Logger(): 7 enabled_(false) 8 { 9 } 10 11 Logger(const std::string & file, bool enabled = true): 12 enabled_(enabled) 13 log_(file, ios::base::app) 14 { 15 } 16 17 // ... etc ... 18 19 const Logger & operator<<(const std::string & arg) const 20 { 21 if(this->enabled_) 22 { 23 this->log_ /* etc ... */ << arg << std::endl; 24 } 25 26 return *this; 27 } 28};

(Untested, but you get the idea...)

Logger null;
Logger disabled("my.log", false);
Logger log("my.log");

null << "This isn't logged anywhere.";
disabled << "This either.";
log << "This is.";

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I second bamccaig, although I abstract my log even further to point to any ostream and then OutputLog() retrieves a reference.

   OutputLog() << "Write this to the log ...." << endl;

It doesn't allow for disabling the log but I usually only use the log for diagnostic purposes.

Go to: