MQLplus/lib_debug/example/LibDebug_Integrated.mq5
super.admin 466f9ca5c5 convert
2025-05-30 16:09:52 +02:00

495 lines
15 KiB
MQL5

/**********************************************************************************
* Copyright (C) 2020 Dominik Egert <info@freie-netze.de>
*
* This file is the lib_debug demonstration file.
*
* Lisence applied: Free, no license applied to this file.
*
* Author Dominik Egert / Freie Netze UG.
**********************************************************************************
*
* Version: 1.01
* State: public
*
* File information
* ================
*
*/
#property version "1.01"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Additional options for LIB_DEBUG
//
// LIB_DEBUG_MQLAPI_TRACE
//
// MQL API function call tracing support. This will log calls to MQL built-in functions.
// "LIB_DEBUG_MQLAPI_TRACE" will enable this feature. You will get trace output, if you have
// LIB_DEBUG built-in tracing for the particular function enabled. - See example below on how to
// integrate tracing of a function.
//
// Functions for which tracing is activated, see description below, will now
// also log calls to MQL-API functions. The error code and return type will be logged.
//
//
// !!! IMPORTANT NOTE !!!
//
// MQL-API-Function tracing is incompatible with the standard library from MQL.
// You will receive compiler errors, if activated and using standard-library.
//
// If you wish to do so anyways, move forward to "Custom Integration" below
// to learn how you could do it anyways.
//
//
// LIMITATION when using LIB_DEBUG_MQLAPI_TRACE
//
// If you are callling an MQL function on global scope, you must do so before
// including lib_debug.mqh.
//
// Example:
//
// // Global MQL function calls must happen before "#include lib_debug"
// const string files = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\files\\";
// const uint ticks = GetTickCount();
//
// // Include lib_debug
// #define LIB_MQLAPI_TRACE
// #include <MQLplus\lib_debug.mqh>
//
// These global calls will not be tracked.
//
/////////////////////////////////////////
//
// Include the library
//
#define LIB_DEBUG
#define LIB_DEBUG_MQLAPI_TRACE
#include <MQLplus/lib_debug.mqh>
///////////////////////////////////////////////////////////////////////
//
// In OnInit you can see a simple usage of the debugging macros.
//
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//////////////////////////////////////////////////////////////
//
// Simple output macros
//
// Some initial debug message
DBG_MSG("Example how to use lib_debug.mqh as project integrated version.");
// Output details about current program
// Available in debugging and runtime
printf("%s", DBG_STR_EX45_FILEINFO);
// Keep this message also in runtime builds
DBG_MSG_PERSIST("Persistent message in debug and runtime (Runtime is without debug details)");
// Return
return(INIT_SUCCEEDED);
}
///////////////////////////////////////////////////////////////////////
//
// In OnDeinit we will use full tracing of the function call.
//
// First we define some helpers for compile time code
// inclusion selection. This will make it easy to enable/disable
// function tracing as needed.
//
// To do this, first a macro is defined which will be used as a
// switch (defined = trace function) (not defined = disable tracing)
//
// We can collect these "switches" at top of file for a better overview
// Also we could wrap them into a condition, so that they will only be
// defined when debugging is enabled.
//
// Example:
// #ifdef LIB_DEBUG
// #define DBG_TRACE_EXPERT_MAIN_ONDEINIT
//
// #endif
// En/Disable function tracing by commenting following macro:
#define DBG_TRACE_EXPERT_MAIN_ONDEINIT
// Now we define the helper macros which will be used inside
// the functions body.
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_ONDEINIT
#undef DBG_TRACE_EXPERT_MAIN_ONDEINIT
#define DBG_TRACE_EXPERT_MAIN_ONDEINIT(x) x
#define DBG_TRACE_EXPERT_MAIN_ONDEINIT_RETURN DBG_MSG_TRACE_RETURN
#else
#define DBG_TRACE_EXPERT_MAIN_ONDEINIT(x)
#define DBG_TRACE_EXPERT_MAIN_ONDEINIT_RETURN DBG_MSG_NOTRACE_RETURN
#endif
/////////////////////////////////////
void OnDeinit(const int reason)
{
/////////////////////////////////////
//
// TOP of function body
//
// Here the tracing code gets included, this is mandatory for tracing to work.
// The switching macro can also be used to include additional
// debugging code, if any is required, see example below.
DBG_TRACE_EXPERT_MAIN_ONDEINIT(
DBG_MSG_TRACE_BEGIN;
// Additional details can be added here, as required.
// For example to trace the inputs to this function, we can add
DBG_MSG_VAR(reason);
// Or whatever we would like to add.
);
// Additionally the macro "PERF_COUNTER_BEGIN" must be added.
// It is mandatory to complete the "return" macro, irrespective of it
// being used or not. (Any insertions will be removed for runtime builds,
// if "LIB_PERF_PROFILING" is not defined)
PERF_COUNTER_BEGIN;
//
// This concludes the functions head
// control code required for tracing.
// If tracing is disabled for this function,
// all additional code will be stripped at
// compile time.
//
// Now follows the actual functions body:
/////////////////////////////////////
// Local init
int some_int_val = 3;
string some_string = "I dont know";
/////////////////////////////////////
//
// As an example, here the local variables
// are printed, but only if tracing is enbaled.
// In contrast to the usage of macros in OnInit, where
// the macros were not wrapped in the
// Trace-Enable-Disable macro.
//
DBG_TRACE_EXPERT_MAIN_ONDEINIT(
DBG_MSG_VAR(some_int_val);
DBG_MSG_VAR(some_string);
);
// Destroy timer
EventKillTimer();
/////////////////////////////////////
//
// EXITING/RETURNING from the fucntions body.
//
// A return statement is mandatory, no matter the functions signature.
// This will inform the debug library about the functions ending/exiting.
//
// The special function "OnDeinit" will auto-resolve the deinit reason
// and show the state of the _StopFlag/IsStopped() variable.
// This is automatically inserted and needs no extra care taking.
//
DBG_TRACE_EXPERT_MAIN_ONDEINIT_RETURN;
}
///////////////////////////////////////////////////////////////////////
//
// In OnTick we will use full tracing of the function call as
// shown with OnDeinit, and we will integrate global performance
// counters as well. This will give output of the runtime used by
// this function.
//
// Since the tracing has already been exlained, here is a
// stripped version, showing the raw requirements for a full trace.
//
// Short outline.
// - First define the enable/disable macros.
// - Then include the head required inside the body.
// - Use the return macro at all exit points of the function.
//
// To enable tracing for this function, same procedure as
// with OnDeinit applies.
// Again, this could be collected at top of file for better oversight.
// Turn on tracing
#define DBG_TRACE_EXPERT_MAIN_ONTICK
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_ONTICK
#undef DBG_TRACE_EXPERT_MAIN_ONTICK
#define DBG_TRACE_EXPERT_MAIN_ONTICK(x) x
#define DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN DBG_MSG_TRACE_RETURN
#else
#define DBG_TRACE_EXPERT_MAIN_ONTICK(x)
#define DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN DBG_MSG_NOTRACE_RETURN
#endif
/////////////////////////////////////
void OnTick()
{
DBG_TRACE_EXPERT_MAIN_ONTICK(
DBG_MSG_TRACE_BEGIN;
);
PERF_COUNTER_BEGIN;
// Local init
int some_var = MathRand();
DBG_MSG_VAR(some_var);
// Some random check operation
if((some_var % 2) == 0)
{
call_sub_function();
call_sub2_function();
call_obj_function();
}
// Some eventual exit at annother point inside the functions body
if((some_var % 2048) == 0)
{ DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN; }
// Return
DBG_TRACE_EXPERT_MAIN_ONTICK_RETURN;
}
///////////////////////////////////////////////////////////////////////
//
// In call_sub_function we will use full tracing of the function call.
//
// This example shows the difference for a function with
// a return value.
//
// Take notice of the used macros. - It is required to use a
// different return macro for this type of function call.
//
// Instead of using the macro "DBG_MSG_TRACE_RETURN" and "DBG_MSG_NOTRACE_RETURN"
// here the macros "DBG_MSG_TRACE_RETURN_VAR(x)" and "DBG_MSG_NOTRACE_RETURN_VAR(x)"
// are used.
//
// For use of objects of type "struct", "class" or "interface", a separate
// return value macro must be used. - (This implementation is new in MQL5)
//
// Returning objects from functions, use following macros:
// "DBG_MSG_TRACE_RETURN_OBJ(x)" and "DBG_MSG_NOTRACE_RETURN_OBJ(x)"
//
// For use with pointers as return value, either macro can be used, preferably use
// "DBG_MSG_TRACE_RETURN_VAR(x)".
//
// IMPORTANT NOTICE:
// Calling the macro with the parameter "NULL" requires!!! a cast operation.
// (This functions return value is "int", "const int" or "int" doesnt make a difference)
//
// Example:
// DBG_MSG_TRACE_RETURN_VAR((int)NULL);
//
// This cast operation can be included in the macro definition itself, like this:
// #define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN(x) DBG_MSG_TRACE_RETURN_VAR((int)x)
// #define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN(x) DBG_MSG_NOTRACE_RETURN_VAR(x)
//
// or inside the function using the custom defined macro:
// DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN((int)NULL);
//
// See second function example below.
// Here the cast operation is inside the functions body.
//
// NOTE on CAST-OPeration:
// The runtime macro does not require the cast operation.
// You should include the cast-operation as shown in second example. If it is included
// in the functions body, it will be also part of the runtime-code and not being stripped
// from your code by the library.
//
// Again the enbale trace macro needs to be defined, so tracing
// is enabled.
// Enable tracing of this function
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION
//+------------------------------------------------------------------+
//| Example function with return value |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION
#undef DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION(x) x
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN(x) DBG_MSG_TRACE_RETURN_VAR(x)
#else
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION(x)
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN(x) DBG_MSG_NOTRACE_RETURN_VAR(x)
#endif
/////////////////////////////////////
const int call_sub_function()
{
DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION(
DBG_MSG_TRACE_BEGIN;
);
PERF_COUNTER_BEGIN;
// Do some stuff
if(MathRand() == 5)
{ DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN(5); }
// Return
DBG_TRACE_EXPERT_MAIN_CALL_SUB_FUNCTION_RETURN((int)NULL);
}
// Enable tracing of this function
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION
//+------------------------------------------------------------------+
//| Example function with return value |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION
#undef DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION(x) x
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION_RETURN(x) DBG_MSG_TRACE_RETURN_VAR((int)x)
#else
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION(x)
#define DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION_RETURN(x) DBG_MSG_NOTRACE_RETURN_VAR(x)
#endif
/////////////////////////////////////
const int call_sub2_function()
{
DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION(
DBG_MSG_TRACE_BEGIN;
);
PERF_COUNTER_BEGIN;
// Do some stuff
if(MathRand() == 12)
{ DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION_RETURN(12); }
// Return
DBG_TRACE_EXPERT_MAIN_CALL_SUB2_FUNCTION_RETURN(NULL);
}
// A local class
class CObj
{
public:
int test;
CObj() :
test(NULL)
{ };
CObj(const CObj& p_in)
{
test = p_in.test;
printf("%s", "COPY");
};
};
// Enable tracing of this function
#define DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION
//+------------------------------------------------------------------+
//| Example function with return object |
//+------------------------------------------------------------------+
/////////////////////////////////////
// Function debug trace code
#ifdef DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION
#undef DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION
#define DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION(x) x
#define DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION_RETURN(x) DBG_MSG_TRACE_RETURN_VAR(x)
#else
#define DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION(x)
#define DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION_RETURN(x) DBG_MSG_NOTRACE_RETURN_VAR(x)
#endif
/////////////////////////////////////
CObj call_obj_function()
{
DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION(
DBG_MSG_TRACE_BEGIN;
);
PERF_COUNTER_BEGIN;
// Local init
CObj test_obj;
CObj* test_ptr = new CObj();
Print("1");
DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION(
DBG_MSG_VAR(1);
DBG_MSG_VAR(test_obj);
DBG_MSG_VAR(test_ptr);
);
// Do some stuff
if(MathRand() == 12)
{ DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION_RETURN(test_obj); }
// Return
DBG_TRACE_EXPERT_MAIN_CALL_OBJ_FUNCTION_RETURN(test_obj);
}