New debug output system

Started by Crimson Wizard, Sun 24/06/2012 17:44:56

Previous topic - Next topic

Crimson Wizard

Well, I made this as a small experiment. I wrote a separate output "system" as a possible substitute for existing functions.
It may be found in the "feature_dbgoutput" branch here:
https://github.com/adventuregamestudio/ags/tree/feature_dbgoutput
Check that out (in both meanings :)) if you are interested. Actually I would like to hear some comments.

Idea was to have a simple subsystem meant for outputting text messages for debug or user notification purposes.
Output is being controlled by verbosity settings (at the moment they are hard-coded, but I supposed they should be read from config or command line).
Verbosity is defined as flags:
Code: cpp

        VERBOSE_DO_LOG          = 0x0001, // do log (otherwise do not, C.O.)

        // Debug reason is for random information about current game state,
        // like outputting object values, or telling that execution has
        // passed certain point in the function
        REASON_DEBUG            = 0x0002,
        // Notifications are made when the program is passing important
        // checkpoints, like initializing or shutting engine down, or
        // when program decides to make a workaround to solve some problem
        REASON_NOTIFICATION     = 0x0004,
        // Warnings are made when unexpected or generally strange behavior
        // is detected in program, which does not necessarily mean error,
        // but still may be a symptom of a bigger problem
        REASON_WARNING          = 0x0008,
        // Handled errors are ones that were 'fixed' by the program on run;
        // There's high chance that program will continue running as normal,
        // but message should be maid to bring user or dev's attention
        REASON_HANDLED_ERROR    = 0x0010,
        // Unhandled errors are errors that program was not able to fix;
        // Program *may* try to continue, but there's no guarantee it will
        // work as expected
        REASON_UNHANDLED_ERROR  = 0x0020,
        // Fatal errors make program abort immediately
        REASON_FATAL_ERROR      = 0x0040,

        // Convenience aliases
        REASON_FUNCTION_ENTER   = REASON_DEBUG,
        REASON_FUNCTION_EXIT    = REASON_DEBUG,

        REASON_NOT_DEBUG        = 0x007D,
        REASON_WARN_ERRORS      = 0x0079,
        // Just print out the damned message!
        REASON_WHATEVER         = 0x00FF


System registers a variable number of "output targets" - objects of classes, which implement IOutputTarget interface. These may be newly created classes or any other preexisting class that was extended to become IOutputTarget implementation. For example, in this branch I made AGSPlatformDriver its implementor.

There's a general verbosity setting that is used to tell what types of messages should be completely ignored during game run, and each output target has its own verbosity setting that is being checked after general setting.
Print is made by ALL output targets that pass verbosity check. That means you may have, for example, a file output for printing out only serious errors, and console or editor debugger output for printing both errors and some minor debug notifications. You may even have two file outputs - one for general logging (some 'debug.log'), and separate one (original 'warnings.log') for printing only serious errors, and so forth - any combination of these.

Basically you register them like this:
Code: cpp

    out::add_output_target(TARGET_FILE, new Engine::out::CRawFileOutputTarget("warning.log"),
        out::REASON_NOT_DEBUG, false);
    out::add_output_target(TARGET_SYSTEMDEBUGGER, AGSPlatformDriver::GetDriver(),
        out::REASON_WARN_ERRORS, true);
    out::add_output_target(TARGET_GAMECONSOLE, new Engine::out::CConsoleOutputTarget(),
        out::REASON_WHATEVER, false);
    out::add_output_target(TARGET_FILE_EXTRA_TEST, new Engine::out::CRawFileOutputTarget("ags_game_debug.log"),
        out::REASON_WHATEVER, false);


There's a common function for printing simple message with given "reason", as well as bunch of convenience helper functions for more user-friendliness.
The output is made simply like:
Code: cpp

    out::fprint("Debug system: testing!");

    out::debug          ("This is a debug message, p1 = %d, p2 = %f", 1, 2.0);
    out::debug          ("Function name", "This is a debug message, p1 = %d, p2 = %f", 1, 2.0);
    out::notify         ("This is a notification, p1 = %d, p2 = %f", 1, 2.0);
    out::notify         ("Function name", "This is a notification, p1 = %d, p2 = %f", 1, 2.0);
    out::warn           ("This is a warning, p1 = %d, p2 = %f", 1, 2.0);
    out::warn           ("Function name", "This is a warning, p1 = %d, p2 = %f", 1, 2.0);
    out::handled_err    ("This is a handled error, p1 = %d, p2 = %f", 1, 2.0);
    out::handled_err    ("Function name", "This is a handled error, p1 = %d, p2 = %f", 1, 2.0);
    out::unhandled_err  ("This is an unhandled error, p1 = %d, p2 = %f", 1, 2.0);
    out::unhandled_err  ("Function name", "This is an unhandled error, p1 = %d, p2 = %f", 1, 2.0);
    out::fatal_err      ("This is a fatal error, p1 = %d, p2 = %f", 1, 2.0);
    out::fatal_err      ("Function name", "This is a fatal error, p1 = %d, p2 = %f", 1, 2.0);
    out::fnin           ("Function name");
    out::fnout          ("Function name");

    out::fprint("Debug system: end testing!");


The code is not final, ofc. Main issue is unsafe usage of string buffers, and also limits made by using static array, but this would be fixed as soon as utility classes are implemented.
I also may have gone too far with namespaces ;). On other hand the whole thing could be converted to the class in a matter of an hour.
Currently functionality mimics original AGS logging (file and writing to game console; btw it's funny I don't remember ever seeing that.... :/ or maybe I forgot how it looks like).

What do you think?

SMF spam blocked by CleanTalk