495 lines
15 KiB
MQL5
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);
|
|
}
|
|
|
|
|