Forum > Games

[SOLVED] Game logging template — StdOut, StdErr

(1/4) > >>

furious programming:
For the needs of my game, I need a very simple system for logging various data in the form of text, which is ultimately to be done using Write and WriteLn intrinsics (they are powerful, have built-in data type detection and various formatting abilities). Logging should be based on built-in mechanisms and system ones, i.e. System.StdOut and/or System.StdErr handles.

This should work so that if the system console is available, all data should be displayed there — if the application is compiled with {$APPTYPE CONSOLE} switch. However, if the console is not available, all the diagnostic data should be written to a text file (as a log file).

I have a problem understanding how such logging should work, how to properly redirect the output to the custom log file when the game is compiled with {$APPTYPE GUI} mode and where the log file should be created, according to operating system guidelines and security services (like UAC).

For now, I checked and confirmed that if the console is not available, the System.StdOut and System.StdErr handles are initialized and I can write data with WriteLn without any problems, but I don't know where they end up. Are they stored somewhere or are they lost?

Has anyone done something like this before? I would like to mention that I don't want to use any dependencies and logging frameworks — I want to create as simple a login system as possible, which must be based on Write and WriteLn. I will be grateful for any help.

Bogen85:
The thing is you need a logging framework, even if it is just a simple light one that you create custom for yourself.

The problem is when you create a simple custom one yourself, as time you goes on the more you use it, the more you will update, and it won't be so simple any more. (Even if it is simple to use.)

Been there, done that, many times...

furious programming:
As I mentioned, I don't want to use any framework for such a simple thing like creating log files. What I need is to understand how these handles works, for both to extend my knowledge and to implement what I want to implement in my project. So please, let's focus on my questions.

Bogen85:
Yes... understood on the not wanting a framework... But personally find logging that does not universally include file, line, function by default as "difficult". (and the ability to include stack traces...) Yes, better than nothing, but still "difficult"...

But I digress.

Problem on  write and writeln unless you explicitly indicate stderr or stdout, a redirect won't take place. (Unless I'm missing something).


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$mode objfpc}{$h+}program output_redirect; uses sysutils; procedure println(const text: string);  begin    writeln(stdout, text);  end; procedure eprintln(const text: string);  begin        writeln(stderr, text);  end; procedure println(const fmt: string; const args: array of const);  begin        println(format(fmt, args));  end; procedure eprintln(const fmt: string; const args: array of const);  begin        eprintln(format(fmt, args));  end; procedure hello1;  begin        writeln('hello 1!')  end; procedure hello2;  begin        writeln(stderr, 'hello 2!')  end; procedure hello3;  begin        writeln(stdout, 'hello 3!')  end; procedure hello4;  begin    println('hello 4!');  end; procedure hello5;  begin    eprintln('hello 5!');  end; procedure hello6;  begin    println('hello %d!', [6]);  end; procedure hello7;  begin    eprintln('hello %d!', [7]);  end; procedure hello_all;  begin        hello1;        hello2;        hello3;        hello4;        hello5;        hello6;        hello7;  end; begin  hello_all;  close(stdout);  close(stderr);  assign(stdout, 'stdout.txt');  assign(stderr, 'stderr.txt');  rewrite(stdout);  rewrite(stderr);  hello_all;end.
Compiles:

--- Code: Text  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---$ fpc output_redirect.pasFree Pascal Compiler version 3.3.1 [2022/12/31] for x86_64Copyright (c) 1993-2022 by Florian Klaempfl and othersTarget OS: Linux for x86-64Compiling output_redirect.pasLinking output_redirect82 lines compiled, 0.2 sec, 375600 bytes code, 166616 bytes data
Runs:

--- Code: Text  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---$ ./output_redirecthello 1!hello 2!hello 3!hello 4!hello 5!hello 6!hello 7!hello 1! $ cat stdout.txthello 3!hello 4!hello 6! $ cat stderr.txthello 2!hello 5!hello 7!
Problem is the second hello 1!, as writeln is not picking out the stdout redirect.

I included println and eprintln as println does work correctly before and after the redirect.
However, they are not intrinsics like write and writeln so they have no automatic type detection.... (and additional arguments to be printed are in an array, and needed to specified in the format string).

Something like println and eprintln (or what ever you would call them) could automatically file/line/function of the caller without specifying those in the call to them, but as you already pointed out, you don't seem to interested in any of that (even though you did say "game logging template"...) but once again, I digress.

If someone else knows how to make write and writeln both respect the stdout redirect implicity (with explicity including it in the call) I'd like to see the mechanism needed.


 

furious programming:
The first idea that came to my mind is the simplest solution, which is to check the IsConsole variable and if it is False, release the StdOut file and assign to it my own — with a relative path, so that the log file is created always next to the executable.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---if not IsConsole thenbegin  Close(StdOut);   Assign(StdOut, 'log.txt');  ReWrite(StdOut);end;
This is simple — if the game does not use the console (that is, build uses the {$APPTYPE GUI} switch), the current StdOut handle is freed, and a file is created instead and all data logged with WriteLn goes to it. Of course, for this to actually happen, all calls to Write and WriteLn must accept an output handle in the first parameter:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---WriteLn(StdOut, 'actual data in next parameters');
This is not a problem for me, so I can not only log data to the console or log file in this way, but also use all WriteLn capabilities (any number of arguments, formatting, support for any data types, etc.). And so that I don't have to explicitly use WriteLn, but my own identifiers, I can always declare a set of macros with names that match the convention used in the project (e.g. names Game_LogLn and similar).

I just don't know if creating a log file using a relative name — Assign(StdOut, 'log.txt') — won't be a bad choice. I don't know if operating systems will always allow application to create a log file next to the executable. However, I'd be in favor of actually creating a log file next to the executable so that the player doesn't have to look for it.

Navigation

[0] Message Index

[#] Next page

Go to full version