diff --git a/agent/native/ext/Hooking.cpp b/agent/native/ext/Hooking.cpp index 07a5b6924..f3610bf66 100644 --- a/agent/native/ext/Hooking.cpp +++ b/agent/native/ext/Hooking.cpp @@ -1,14 +1,63 @@ #include "Hooking.h" -#include #include + #include "php_elastic_apm.h" #include "PhpBridge.h" +#include "PhpErrorData.h" + +#include +#include namespace elasticapm::php { +#if PHP_VERSION_ID < 80000 +void elastic_apm_error_cb(int type, const char *error_filename, const Hooking::zend_error_cb_lineno_t error_lineno, const char *format, va_list args) { //<8.0 +#elif PHP_VERSION_ID < 80100 +void elastic_apm_error_cb(int type, const char *error_filename, const uint32_t error_lineno, zend_string *message) { // 8.0 +#else +void elastic_apm_error_cb(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message) { // 8.1+ +#endif + using namespace std::string_view_literals; + + if (ELASTICAPM_G(captureErrors)) { +#if PHP_VERSION_ID < 80000 + char * message = nullptr; + va_list messageArgsCopy; + va_copy(messageArgsCopy, args); + vspprintf(/* out */ &message, 0, format, messageArgsCopy); // vspprintf allocates memory for the resulted string buffer and it needs to be freed with efree() + va_end(messageArgsCopy); + + ELASTICAPM_G(lastErrorData) = std::make_unique(type, error_filename ? error_filename : ""sv, error_lineno, message ? message : ""sv); + + if (message) { + efree(message); + } +#elif PHP_VERSION_ID < 80100 + ELASTICAPM_G(lastErrorData) = std::make_unique(type, error_filename ? error_filename : ""sv, error_lineno, message ? std::string_view{ZSTR_VAL(message), ZSTR_LEN(message)} : ""sv); +#else + ELASTICAPM_G(lastErrorData) = nullptr; + ELASTICAPM_G(lastErrorData) = std::make_unique(type, error_filename ? std::string_view{ZSTR_VAL(error_filename), ZSTR_LEN(error_filename)} : ""sv, error_lineno, message ? std::string_view{ZSTR_VAL(message), ZSTR_LEN(message)} : ""sv); +#endif + } + + auto original = Hooking::getInstance().getOriginalZendErrorCb(); + if (original == elastic_apm_error_cb) { + ELASTIC_APM_LOG_DIRECT_CRITICAL("originalZendErrorCallback == elasticApmZendErrorCallback dead loop detected"); + return; + } + + if (original) { +#if PHP_VERSION_ID < 80000 + original(type, error_filename, error_lineno, format, args); +#else + original(type, error_filename, error_lineno, message); +#endif + } +} + static void elastic_execute_internal(INTERNAL_FUNCTION_PARAMETERS) { zend_try { @@ -42,6 +91,7 @@ static void elastic_interrupt_function(zend_execute_data *execute_data) { void Hooking::replaceHooks() { zend_execute_internal = elastic_execute_internal; zend_interrupt_function = elastic_interrupt_function; + zend_error_cb = elastic_apm_error_cb; } } diff --git a/agent/native/ext/Hooking.h b/agent/native/ext/Hooking.h index 0f106bd5e..9afd94ce2 100644 --- a/agent/native/ext/Hooking.h +++ b/agent/native/ext/Hooking.h @@ -1,12 +1,30 @@ #pragma once +#include
#include +#include + +#include namespace elasticapm::php { class Hooking { public: +#if PHP_VERSION_ID < 70400 + using zend_error_cb_lineno_t = uint; +#else + using zend_error_cb_lineno_t = uint32_t; +#endif + +#if PHP_VERSION_ID < 80000 + using zend_error_cb_t = void (*)(int type, const char *error_filename, const zend_error_cb_lineno_t error_lineno, const char *format, va_list args); //<8.0 +#elif PHP_VERSION_ID < 80100 + using zend_error_cb_t = void (*)(int type, const char *error_filename, const uint32_t error_lineno, zend_string *message); // 8.0 +#else + using zend_error_cb_t = void (*)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message); // 8.1+ +#endif + using zend_execute_internal_t = void (*)(zend_execute_data *execute_data, zval *return_value); using zend_interrupt_function_t = void (*)(zend_execute_data *execute_data); @@ -19,16 +37,17 @@ class Hooking { void fetchOriginalHooks() { original_execute_internal_ = zend_execute_internal; original_zend_interrupt_function_ = zend_interrupt_function; + original_zend_error_cb_ = zend_error_cb; } void restoreOriginalHooks() { zend_execute_internal = original_execute_internal_; zend_interrupt_function = original_zend_interrupt_function_; + zend_error_cb = original_zend_error_cb_; } void replaceHooks(); - zend_execute_internal_t getOriginalExecuteInternal() { return original_execute_internal_; } @@ -37,15 +56,19 @@ class Hooking { return original_zend_interrupt_function_; } + zend_error_cb_t getOriginalZendErrorCb() { + return original_zend_error_cb_; + } + + private: Hooking(Hooking const &) = delete; void operator=(Hooking const &) = delete; Hooking() = default; - - zend_execute_internal_t original_execute_internal_ = nullptr; zend_interrupt_function_t original_zend_interrupt_function_ = nullptr; + zend_error_cb_t original_zend_error_cb_ = nullptr; }; diff --git a/agent/native/ext/PhpErrorData.cpp b/agent/native/ext/PhpErrorData.cpp new file mode 100644 index 000000000..5cc7d4bfc --- /dev/null +++ b/agent/native/ext/PhpErrorData.cpp @@ -0,0 +1,43 @@ + +#include "PhpErrorData.h" + +#include
+#include +#include +#include +#include + +#include +#include + +namespace elasticapm::php { +PhpErrorData::PhpErrorData(int type, std::string_view fileName, uint32_t lineNumber, std::string_view message) : type_(type), fileName_(fileName), lineNumber_(lineNumber), message_(message) { + ZVAL_UNDEF(&stackTrace_); + zend_fetch_debug_backtrace(&stackTrace_, /* skip_last */ 0, /* options */ 0, /* limit */ 0); +} + +PhpErrorData::~PhpErrorData() { + zval_ptr_dtor(&stackTrace_); +} + +int PhpErrorData::getType() const { + return type_; +} + +std::string_view PhpErrorData::getFileName() const { + return fileName_; +} + +int PhpErrorData::getLineNumber() const { + return lineNumber_; +} + +std::string_view PhpErrorData::getMessage() const { + return message_; +} + +zval *PhpErrorData::getStackTrace() { + return &stackTrace_; +} + +} diff --git a/agent/native/ext/PhpErrorData.h b/agent/native/ext/PhpErrorData.h new file mode 100644 index 000000000..1dddb841a --- /dev/null +++ b/agent/native/ext/PhpErrorData.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +namespace elasticapm::php { + +class PhpErrorData { +public: + PhpErrorData(int type, std::string_view fileName, uint32_t lineNumber, std::string_view message); + ~PhpErrorData(); + + int getType() const; + std::string_view getFileName() const; + int getLineNumber() const; + std::string_view getMessage() const; + zval *getStackTrace(); + +private: + int type_ = -1; + std::string fileName_; + uint32_t lineNumber_ = 0; + std::string message_; + zval stackTrace_; +}; + +} \ No newline at end of file diff --git a/agent/native/ext/elastic_apm.cpp b/agent/native/ext/elastic_apm.cpp index 0006c7fb7..1754db4ab 100644 --- a/agent/native/ext/elastic_apm.cpp +++ b/agent/native/ext/elastic_apm.cpp @@ -283,6 +283,8 @@ static PHP_GINIT_FUNCTION(elastic_apm) } ZVAL_UNDEF(&elastic_apm_globals->lastException); + new (&elastic_apm_globals->lastErrorData) std::unique_ptr; + elastic_apm_globals->captureErrors = false; } static PHP_GSHUTDOWN_FUNCTION(elastic_apm) { @@ -290,6 +292,12 @@ static PHP_GSHUTDOWN_FUNCTION(elastic_apm) { if (elastic_apm_globals->globals) { delete elastic_apm_globals->globals; } + + if (elastic_apm_globals->lastErrorData) { + ELASTIC_APM_LOG_DIRECT_WARNING( "%s: still holding error", __FUNCTION__); + // we need to relese any dangling php error data beacause it is already freed (it was allocated in request pool) + elastic_apm_globals->lastErrorData.release(); + } } PHP_MINIT_FUNCTION(elastic_apm) diff --git a/agent/native/ext/lifecycle.cpp b/agent/native/ext/lifecycle.cpp index 763dff7a0..94193a118 100644 --- a/agent/native/ext/lifecycle.cpp +++ b/agent/native/ext/lifecycle.cpp @@ -45,6 +45,7 @@ #include "Hooking.h" #include "CommonUtils.h" #include "Diagnostics.h" +#include "Hooking.h" #define ELASTIC_APM_CURRENT_LOG_CATEGORY ELASTIC_APM_LOG_CATEGORY_LIFECYCLE @@ -138,7 +139,7 @@ typedef void (* ZendThrowExceptionHook )( #endif ); -static bool elasticApmZendErrorCallbackSet = false; +// static bool elasticApmZendErrorCallbackSet = false; static bool elasticApmZendThrowExceptionHookSet = false; static ZendThrowExceptionHook originalZendThrowExceptionHook = NULL; @@ -203,254 +204,9 @@ void elasticApmZendThrowExceptionHook( originalZendThrowExceptionHook( thrownObj ); } } -// In PHP 8.1 filename parameter of zend_error_cb() was changed from "const char*" to "zend_string*" -#if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version before 8.1.0 */ -# define ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_FILE_NAME_C_STRING 1 -#else -# define ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_FILE_NAME_C_STRING 0 -#endif - -typedef -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_FILE_NAME_C_STRING == 1 - const char* -# else - zend_string* -# endif -ZendErrorCallbackFileName; - -const char* zendErrorCallbackFileNameToCString( ZendErrorCallbackFileName fileName ) -{ -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_FILE_NAME_C_STRING == 1 - return fileName; -# else - return fileName ? ZSTR_VAL( fileName ) : nullptr; -# endif -} - -// In PHP 8.0 -// zend_error_cb( , const char *format, va_list args ) -// was changed to -// zend_error_cb( , zend_string* message ) -// -#if PHP_MAJOR_VERSION < 8 -# define ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST 1 -#else -# define ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST 0 -#endif - -#if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 -# define ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE_MSG_PART() const char* messageFormat, va_list messageArgs -#else -# define ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE_MSG_PART() zend_string* alreadyFormattedMessage -#endif - -#define ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE() \ - int type \ - , ZendErrorCallbackFileName fileName \ - , const uint32_t lineNumber \ - , ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE_MSG_PART() - -#if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 -# define ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS_MSG_PART() messageFormat, messageArgs -#else -# define ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS_MSG_PART() alreadyFormattedMessage -#endif - -#define ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS() \ - type \ - , fileName \ - , lineNumber \ - , ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS_MSG_PART() - -typedef void (* ZendErrorCallback )( ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE() ); - -static ZendErrorCallback originalZendErrorCallback = NULL; - -struct PhpErrorData -{ - int type; - const char* fileName; - uint32_t lineNumber; - const char* message; - zval stackTrace; -}; -typedef struct PhpErrorData PhpErrorData; - -static bool g_lastPhpErrorDataSet = false; -static PhpErrorData g_lastPhpErrorData; - -void zeroLastPhpErrorData( PhpErrorData* phpErrorData ) -{ - phpErrorData->type = -1; - phpErrorData->fileName = NULL; - phpErrorData->lineNumber = 0; - phpErrorData->message = NULL; - ZVAL_NULL( &( phpErrorData->stackTrace ) ); -} - -void shallowCopyLastPhpErrorData( PhpErrorData* src, PhpErrorData* dst ) -{ - dst->type = src->type; - dst->fileName = src->fileName; - dst->lineNumber = src->lineNumber; - dst->message = src->message; - dst->stackTrace = src->stackTrace; -} - -void freeAndZeroLastPhpErrorData( PhpErrorData* phpErrorData ) -{ - if ( phpErrorData->fileName != NULL ) - { - ELASTIC_APM_EFREE_STRING_AND_SET_TO_NULL( /* in,out */ phpErrorData->fileName ); - } - - if ( phpErrorData->message != NULL ) - { - ELASTIC_APM_EFREE_STRING_AND_SET_TO_NULL( /* in,out */ phpErrorData->message ); - } - - if ( ! Z_ISNULL( phpErrorData->stackTrace ) ) - { - zval_ptr_dtor( &( phpErrorData->stackTrace ) ); - ZVAL_NULL( &( phpErrorData->stackTrace ) ); - } - - zeroLastPhpErrorData( phpErrorData ); -} - -void resetLastPhpErrorData() -{ - if ( ! g_lastPhpErrorDataSet ) - { - return; - } - - freeAndZeroLastPhpErrorData( &g_lastPhpErrorData ); - - g_lastPhpErrorDataSet = false; -} - -void setLastPhpErrorData( int type, const char* fileName, uint32_t lineNumber, const char* message ) -{ - ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG( "type: %d, fileName: %s, lineNumber: %" PRIu64 ", message: %s", type, fileName, (UInt64)lineNumber, message ); - - [[maybe_unused]] ResultCode resultCode; - PhpErrorData tempPhpErrorData; - zeroLastPhpErrorData( &tempPhpErrorData ); - - if ( fileName != NULL ) - { - ELASTIC_APM_EMALLOC_DUP_STRING_IF_FAILED_GOTO( fileName, /* out */ tempPhpErrorData.fileName ); - } - if ( message != NULL ) - { - ELASTIC_APM_EMALLOC_DUP_STRING_IF_FAILED_GOTO( message, /* out */ tempPhpErrorData.message ); - } - - zend_fetch_debug_backtrace( &( tempPhpErrorData.stackTrace ), /* skip_last */ 0, /* options */ 0, /* limit */ 0 ); - - tempPhpErrorData.type = type; - tempPhpErrorData.lineNumber = lineNumber; - - freeAndZeroLastPhpErrorData( &g_lastPhpErrorData ); - shallowCopyLastPhpErrorData( &tempPhpErrorData, &g_lastPhpErrorData ); - zeroLastPhpErrorData( &tempPhpErrorData ); - g_lastPhpErrorDataSet = true; - - finally: - return; - - failure: - freeAndZeroLastPhpErrorData( &tempPhpErrorData ); - goto finally; -} - -void elasticApmZendErrorCallbackImpl( ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE() ) -{ - ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG( - "type: %d (%s), fileName: %s, lineNumber: %u" -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 - ", messageFormat: %s" -# else - ", alreadyFormattedMessage: %s" -# endif - , type, get_php_error_name( type ), zendErrorCallbackFileNameToCString( fileName ), (UInt)lineNumber -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 - , messageFormat -# else - , ZSTR_VAL( alreadyFormattedMessage ) -# endif - ); - - ResultCode resultCode; - char* locallyFormattedMessage = NULL; - -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 - va_list messageArgsCopy; - va_copy( messageArgsCopy, messageArgs ); - // vspprintf allocates memory for the resulted string buffer and it needs to be freed with efree() - vspprintf( /* out */ &locallyFormattedMessage, 0, messageFormat, messageArgsCopy ); - va_end( messageArgsCopy ); -# endif - - setLastPhpErrorData( type, zendErrorCallbackFileNameToCString( fileName ), lineNumber, -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 1 - locallyFormattedMessage -# else - ZSTR_VAL( alreadyFormattedMessage ) -# endif - ); - - resultCode = resultSuccess; - -# if ELASTIC_APM_IS_ZEND_ERROR_CALLBACK_MSG_VA_LIST == 0 - if ( locallyFormattedMessage != NULL ) - { - efree( locallyFormattedMessage ); - locallyFormattedMessage = NULL; - } -# endif - - ELASTIC_APM_LOG_DEBUG_RESULT_CODE_FUNCTION_EXIT(); - // We ignore errors because we want the monitored application to continue working - // even if APM encountered an issue that prevent it from working - return; -} - -void elasticApmZendErrorCallback( ELASTIC_APM_ZEND_ERROR_CALLBACK_SIGNATURE() ) -{ - Tracer* const tracer = getGlobalTracer(); - const ConfigSnapshot* config = getTracerCurrentConfigSnapshot( tracer ); - if (config->captureErrors) { - elasticApmZendErrorCallbackImpl( ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS() ); - } - - - if (originalZendErrorCallback == elasticApmZendErrorCallback) { - ELASTIC_APM_LOG_CRITICAL( "originalZendErrorCallback == elasticApmZendErrorCallback" ); - return; - } - - if ( originalZendErrorCallback != NULL ) - { - originalZendErrorCallback( ELASTIC_APM_ZEND_ERROR_CALLBACK_ARGS() ); - } -} - - -static void registerErrorAndExceptionHooks() { - if (!elasticApmZendErrorCallbackSet) { - originalZendErrorCallback = zend_error_cb; - zend_error_cb = elasticApmZendErrorCallback; - elasticApmZendErrorCallbackSet = true; - ELASTIC_APM_LOG_DEBUG( "Set zend_error_cb: %p (%s elasticApmZendErrorCallback) -> %p" - , originalZendErrorCallback, originalZendErrorCallback == elasticApmZendErrorCallback ? "==" : "!=" - , elasticApmZendErrorCallback ); - } else { - ELASTIC_APM_LOG_WARNING( "zend_error_cb already set: %p. Original: %p, Elastic: %p", zend_error_cb, originalZendErrorCallback, elasticApmZendErrorCallback ); - } +static void registerExceptionHooks() { if (!elasticApmZendThrowExceptionHookSet) { originalZendThrowExceptionHook = zend_throw_exception_hook; zend_throw_exception_hook = elasticApmZendThrowExceptionHook; @@ -464,7 +220,7 @@ static void registerErrorAndExceptionHooks() { } -static void unregisterErrorAndExceptionHooks() { +static void unregisterExceptionHooks() { if (elasticApmZendThrowExceptionHookSet) { ZendThrowExceptionHook zendThrowExceptionHookBeforeRestore = zend_throw_exception_hook; zend_throw_exception_hook = originalZendThrowExceptionHook; @@ -475,18 +231,6 @@ static void unregisterErrorAndExceptionHooks() { } else { ELASTIC_APM_LOG_DEBUG("zend_throw_exception_hook not restored: %p, elastic: %p", zend_throw_exception_hook, elasticApmZendThrowExceptionHook); } - - if (!elasticApmZendErrorCallbackSet) { - ZendErrorCallback zendErrorCallbackBeforeRestore = zend_error_cb; - zend_error_cb = originalZendErrorCallback; - ELASTIC_APM_LOG_DEBUG( "Restored zend_error_cb: %p (%s elasticApmZendErrorCallback: %p) -> %p" - , zendErrorCallbackBeforeRestore, zendErrorCallbackBeforeRestore == elasticApmZendErrorCallback ? "==" : "!=" - , elasticApmZendErrorCallback, originalZendErrorCallback ); - originalZendErrorCallback = NULL; - } else { - ELASTIC_APM_LOG_DEBUG("zend_error_cb not restored: %p, elastic: %p", zend_error_cb, elasticApmZendErrorCallback); - } - } void elasticApmModuleInit( int moduleType, int moduleNumber ) @@ -534,7 +278,7 @@ void elasticApmModuleInit( int moduleType, int moduleNumber ) registerCallbacksToLogFork(); registerAtExitLogging(); - registerErrorAndExceptionHooks(); + registerExceptionHooks(); curlCode = curl_global_init( CURL_GLOBAL_ALL ); if ( curlCode != CURLE_OK ) @@ -589,7 +333,7 @@ void elasticApmModuleShutdown( int moduleType, int moduleNumber ) elasticapm::php::Hooking::getInstance().restoreOriginalHooks(); astInstrumentationOnModuleShutdown(); - unregisterErrorAndExceptionHooks(); + unregisterExceptionHooks(); backgroundBackendCommOnModuleShutdown( config ); @@ -617,20 +361,18 @@ void elasticApmModuleShutdown( int moduleType, int moduleNumber ) ELASTIC_APM_LOG_DIRECT_DEBUG( "%s exiting...", __FUNCTION__ ); } -void elasticApmGetLastPhpError( zval* return_value ) -{ - if ( ! g_lastPhpErrorDataSet ) - { +void elasticApmGetLastPhpError(zval* return_value) { + if (!ELASTICAPM_G(lastErrorData)) { RETURN_NULL(); } array_init( return_value ); - ELASTIC_APM_ZEND_ADD_ASSOC( return_value, "type", long, (zend_long)( g_lastPhpErrorData.type ) ); - ELASTIC_APM_ZEND_ADD_ASSOC_NULLABLE_STRING( return_value, "fileName", g_lastPhpErrorData.fileName ); - ELASTIC_APM_ZEND_ADD_ASSOC( return_value, "lineNumber", long, (zend_long)( g_lastPhpErrorData.lineNumber ) ); - ELASTIC_APM_ZEND_ADD_ASSOC_NULLABLE_STRING( return_value, "message", g_lastPhpErrorData.message ); - Z_TRY_ADDREF( g_lastPhpErrorData.stackTrace ); - ELASTIC_APM_ZEND_ADD_ASSOC( return_value, "stackTrace", zval, &( g_lastPhpErrorData.stackTrace ) ); + ELASTIC_APM_ZEND_ADD_ASSOC(return_value, "type", long, static_cast(ELASTICAPM_G(lastErrorData)->getType())); + ELASTIC_APM_ZEND_ADD_ASSOC_NULLABLE_STRING( return_value, "fileName", ELASTICAPM_G(lastErrorData)->getFileName().data() ); + ELASTIC_APM_ZEND_ADD_ASSOC(return_value, "lineNumber", long, static_cast(ELASTICAPM_G(lastErrorData)->getLineNumber())); + ELASTIC_APM_ZEND_ADD_ASSOC_NULLABLE_STRING( return_value, "message", ELASTICAPM_G(lastErrorData)->getMessage().data()); + Z_TRY_ADDREF_P((ELASTICAPM_G(lastErrorData)->getStackTrace())); + ELASTIC_APM_ZEND_ADD_ASSOC(return_value, "stackTrace", zval, (ELASTICAPM_G(lastErrorData)->getStackTrace())); } auto buildPeriodicTaskExecutor() { @@ -734,6 +476,7 @@ void elasticApmRequestInit() if (!config->captureErrors) { ELASTIC_APM_LOG_DEBUG( "capture_errors (captureErrors) configuration option is set to false which means errors will NOT be captured" ); } + ELASTICAPM_G(captureErrors) = config->captureErrors; if ( config->astProcessEnabled ) { @@ -836,6 +579,8 @@ void elasticApmRequestShutdown() ELASTICAPM_G(globals)->periodicTaskExecutor_->suspendPeriodicTasks(); } + ELASTICAPM_G(captureErrors) = false; // disabling error capturing on shutdown + tracerPhpPartOnRequestShutdown(); // there is no guarantee that following code will be executed - in case of error on php side @@ -871,7 +616,7 @@ int elasticApmRequestPostDeactivate(void) { resetCallInterceptionOnRequestShutdown(); - resetLastPhpErrorData(); + ELASTICAPM_G(lastErrorData).reset(nullptr); resetLastThrown(); if ( tracer->isInited && isMemoryTrackingEnabled( &tracer->memTracker ) ) @@ -882,7 +627,6 @@ int elasticApmRequestPostDeactivate(void) { return SUCCESS; } - static pid_t g_lastDetectedCurrentProcessId = -1; ResultCode resetStateIfForkedChild( String dbgCalledFromFile, int dbgCalledFromLine, String dbgCalledFromFunction ) diff --git a/agent/native/ext/log.h b/agent/native/ext/log.h index a9a1d61d9..05072d5d0 100644 --- a/agent/native/ext/log.h +++ b/agent/native/ext/log.h @@ -314,6 +314,7 @@ ResultCode resetLoggingStateInForkedChild(); #define ELASTIC_APM_LOG_CATEGORY_UTIL "Util" #define ELASTIC_APM_LOG_DIRECT_CRITICAL( fmt, ... ) ELASTIC_APM_LOG_DIRECT( logLevel_critical, fmt, ##__VA_ARGS__ ) +#define ELASTIC_APM_LOG_DIRECT_WARNING( fmt, ... ) ELASTIC_APM_LOG_DIRECT( logLevel_warning, fmt, ##__VA_ARGS__ ) #define ELASTIC_APM_LOG_DIRECT_INFO( fmt, ... ) ELASTIC_APM_LOG_DIRECT( logLevel_info, fmt, ##__VA_ARGS__ ) #define ELASTIC_APM_LOG_DIRECT_DEBUG( fmt, ... ) ELASTIC_APM_LOG_DIRECT( logLevel_debug, fmt, ##__VA_ARGS__ ) diff --git a/agent/native/ext/php_elastic_apm.h b/agent/native/ext/php_elastic_apm.h index e7f89d124..ada2a9a00 100644 --- a/agent/native/ext/php_elastic_apm.h +++ b/agent/native/ext/php_elastic_apm.h @@ -24,11 +24,14 @@ #include "AgentGlobals.h" +#include "PhpErrorData.h" + #include #include #include #include +#include extern zend_module_entry elastic_apm_module_entry; @@ -37,10 +40,14 @@ extern zend_module_entry elastic_apm_module_entry; ZEND_TSRMLS_CACHE_EXTERN() #endif + + ZEND_BEGIN_MODULE_GLOBALS(elastic_apm) Tracer globalTracer; elasticapm::php::AgentGlobals *globals; zval lastException; + std::unique_ptr lastErrorData; + bool captureErrors; ZEND_END_MODULE_GLOBALS(elastic_apm) ZEND_EXTERN_MODULE_GLOBALS(elastic_apm)