Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions agent/native/ext/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -801,8 +801,10 @@ ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( optionalBoolValue, asyncBackendComm )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( stringValue, bootstrapPhpPartFile )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, breakdownMetrics )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, captureErrors )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, captureExceptions )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( stringValue, devInternal )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, devInternalBackendCommLogVerbose )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, devInternalCaptureErrorsOnlyToLog )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( stringValue, disableInstrumentations )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, disableSend )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( boolValue, enabled )
Expand Down Expand Up @@ -1008,6 +1010,12 @@ static void initOptionsMetadata( OptionMetadata* optsMeta )
ELASTIC_APM_CFG_OPT_NAME_CAPTURE_ERRORS,
/* defaultValue: */ true );

ELASTIC_APM_INIT_METADATA(
buildBoolOptionMetadata,
captureExceptions,
ELASTIC_APM_CFG_OPT_NAME_CAPTURE_EXCEPTIONS,
/* defaultValue: */ true );

ELASTIC_APM_INIT_METADATA(
buildStringOptionMetadata,
devInternal,
Expand All @@ -1020,6 +1028,12 @@ static void initOptionsMetadata( OptionMetadata* optsMeta )
ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_BACKEND_COMM_LOG_VERBOSE,
/* defaultValue: */ false );

ELASTIC_APM_INIT_METADATA(
buildBoolOptionMetadata,
devInternalCaptureErrorsOnlyToLog,
ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_CAPTURE_ERRORS_ONLY_TO_LOG,
/* defaultValue: */ false );

ELASTIC_APM_INIT_METADATA(
buildStringOptionMetadata,
disableInstrumentations,
Expand Down
7 changes: 4 additions & 3 deletions agent/native/ext/ConfigManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ enum OptionId
optionId_bootstrapPhpPartFile,
optionId_breakdownMetrics,
optionId_captureErrors,
optionId_captureExceptions,
optionId_devInternal,
optionId_devInternalBackendCommLogVerbose,
optionId_devInternalCaptureErrorsOnlyToLog,
optionId_disableInstrumentations,
optionId_disableSend,
optionId_enabled,
Expand Down Expand Up @@ -257,16 +259,15 @@ const ConfigSnapshot* getGlobalCurrentConfigSnapshot();
#define ELASTIC_APM_CFG_OPT_NAME_BOOTSTRAP_PHP_PART_FILE "bootstrap_php_part_file"
#define ELASTIC_APM_CFG_OPT_NAME_BREAKDOWN_METRICS "breakdown_metrics"

/**
* Internal configuration option (not included in public documentation)
*/
#define ELASTIC_APM_CFG_OPT_NAME_CAPTURE_ERRORS "capture_errors"
#define ELASTIC_APM_CFG_OPT_NAME_CAPTURE_EXCEPTIONS "capture_exceptions"

/**
* Internal configuration option (not included in public documentation)
*/
#define ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL "dev_internal"
#define ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_BACKEND_COMM_LOG_VERBOSE "dev_internal_backend_comm_log_verbose"
#define ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_CAPTURE_ERRORS_ONLY_TO_LOG "dev_internal_capture_errors_only_to_log"

#define ELASTIC_APM_CFG_OPT_NAME_DISABLE_INSTRUMENTATIONS "disable_instrumentations"
#define ELASTIC_APM_CFG_OPT_NAME_DISABLE_SEND "disable_send"
Expand Down
2 changes: 2 additions & 0 deletions agent/native/ext/ConfigSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ struct ConfigSnapshot
String bootstrapPhpPartFile = nullptr;
bool breakdownMetrics = false;
bool captureErrors = false;
bool captureExceptions = false;
String devInternal = nullptr;
bool devInternalBackendCommLogVerbose = false;
bool devInternalCaptureErrorsOnlyToLog = false;
String disableInstrumentations = nullptr;
bool disableSend = false;
bool enabled = false;
Expand Down
54 changes: 1 addition & 53 deletions agent/native/ext/Hooking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,6 @@

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<elasticapm::php::PhpErrorData>(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<elasticapm::php::PhpErrorData>(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<elasticapm::php::PhpErrorData>(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 {
Expand Down Expand Up @@ -92,21 +47,14 @@ static void elastic_interrupt_function(zend_execute_data *execute_data) {
} zend_end_try();
}

void Hooking::replaceHooks(bool cfgCaptureErrors, bool cfgInferredSpansEnabled) {
void Hooking::replaceHooks(bool cfgInferredSpansEnabled) {
if (cfgInferredSpansEnabled) {
zend_execute_internal = elastic_execute_internal;
zend_interrupt_function = elastic_interrupt_function;
ELASTIC_APM_LOG_DEBUG( "Replaced zend_execute_internal and zend_interrupt_function hooks" );
} else {
ELASTIC_APM_LOG_DEBUG( "NOT replacing zend_execute_internal and zend_interrupt_function hooks because profiling_inferred_spans_enabled configuration option is set to false" );
}

if (cfgCaptureErrors) {
zend_error_cb = elastic_apm_error_cb;
ELASTIC_APM_LOG_DEBUG( "Replaced zend_error_cb hook" );
} else {
ELASTIC_APM_LOG_DEBUG( "NOT replacing zend_error_cb hook because capture_errors configuration option is set to false" );
}
}

}
24 changes: 1 addition & 23 deletions agent/native/ext/Hooking.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@ 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);

Expand All @@ -37,16 +23,14 @@ 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(bool cfgCaptureErrors, bool cfgInferredSpansEnabled);
void replaceHooks(bool cfgInferredSpansEnabled);

zend_execute_internal_t getOriginalExecuteInternal() {
return original_execute_internal_;
Expand All @@ -56,19 +40,13 @@ 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;
};


Expand Down
60 changes: 2 additions & 58 deletions agent/native/ext/elastic_apm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,10 @@ PHP_INI_BEGIN()
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_BOOTSTRAP_PHP_PART_FILE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_BREAKDOWN_METRICS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_CAPTURE_ERRORS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_CAPTURE_EXCEPTIONS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_BACKEND_COMM_LOG_VERBOSE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DEV_INTERNAL_CAPTURE_ERRORS_ONLY_TO_LOG )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DISABLE_INSTRUMENTATIONS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DISABLE_SEND )
ELASTIC_APM_NOT_RELOADABLE_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ENABLED )
Expand Down Expand Up @@ -287,23 +289,13 @@ static PHP_GINIT_FUNCTION(elastic_apm)
} catch (std::exception const &e) {
ELASTIC_APM_LOG_DIRECT_CRITICAL( "Unable to allocate AgentGlobals. '%s'", e.what());
}

ZVAL_UNDEF(&elastic_apm_globals->lastException);
new (&elastic_apm_globals->lastErrorData) std::unique_ptr<elasticapm::php::PhpErrorData>;
elastic_apm_globals->captureErrors = false;
}

static PHP_GSHUTDOWN_FUNCTION(elastic_apm) {
ELASTIC_APM_LOG_DIRECT_DEBUG( "%s: GSHUTDOWN called; parent PID: %d", __FUNCTION__, (int)getParentProcessId() );
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)
Expand Down Expand Up @@ -603,52 +595,6 @@ PHP_FUNCTION( elastic_apm_log )
}
/* }}} */

ZEND_BEGIN_ARG_INFO_EX( elastic_apm_get_last_thrown_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_get_last_thrown(): mixed
*/
PHP_FUNCTION( elastic_apm_get_last_thrown )
{
ResultCode resultCode;
ZVAL_NULL( /* out */ return_value );

// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
ELASTIC_APM_CALL_IF_FAILED_GOTO( elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) );

elasticApmGetLastThrown( /* out */ return_value );

finally:
return;

failure:
goto finally;
}
/* }}} */

ZEND_BEGIN_ARG_INFO_EX( elastic_apm_get_last_php_error_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_get_last_error(): array
*/
PHP_FUNCTION( elastic_apm_get_last_php_error )
{
ResultCode resultCode;
ZVAL_NULL( /* out */ return_value );

// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
ELASTIC_APM_CALL_IF_FAILED_GOTO( elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) );

elasticApmGetLastPhpError( /* out */ return_value );

finally:
return;

failure:
goto finally;
}
/* }}} */

ZEND_BEGIN_ARG_INFO_EX( elastic_apm_before_loading_agent_php_code_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_before_loading_agent_php_code(): void
Expand Down Expand Up @@ -717,8 +663,6 @@ static const zend_function_entry elastic_apm_functions[] =
PHP_FE( elastic_apm_intercept_calls_to_internal_function, elastic_apm_intercept_calls_to_internal_function_arginfo )
PHP_FE( elastic_apm_send_to_server, elastic_apm_send_to_server_arginfo )
PHP_FE( elastic_apm_log, elastic_apm_log_arginfo )
PHP_FE( elastic_apm_get_last_thrown, elastic_apm_get_last_thrown_arginfo )
PHP_FE( elastic_apm_get_last_php_error, elastic_apm_get_last_php_error_arginfo )
PHP_FE( elastic_apm_before_loading_agent_php_code, elastic_apm_before_loading_agent_php_code_arginfo )
PHP_FE( elastic_apm_after_loading_agent_php_code, elastic_apm_after_loading_agent_php_code_arginfo )
PHP_FE( elastic_apm_ast_instrumentation_pre_hook, elastic_apm_ast_instrumentation_pre_hook_arginfo )
Expand Down
Loading