Skip to content
Merged
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
27 changes: 26 additions & 1 deletion agent/native/ext/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,11 @@ static void parsedOptionalBoolValueToZval( const OptionMetadata* optMeta, Parsed
ELASTIC_APM_ASSERT_EQ_UINT64( parsedValue.type, optMeta->defaultValue.type );
ELASTIC_APM_ASSERT_VALID_PTR( return_value );

RETURN_STRING( optionalBoolToString( parsedValue.u.optionalBoolValue ) );
if (parsedValue.u.optionalBoolValue.isSet) {
RETURN_BOOL(parsedValue.u.optionalBoolValue.value);
} else {
RETURN_NULL();
}
}

static ResultCode parseDurationValue( const OptionMetadata* optMeta, String rawValue, /* out */ ParsedOptionValue* parsedValue )
Expand Down Expand Up @@ -801,8 +805,11 @@ 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, captureErrorsWithPhpPart )
ELASTIC_APM_DEFINE_FIELD_ACCESS_FUNCS( optionalBoolValue, 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 +1015,18 @@ static void initOptionsMetadata( OptionMetadata* optsMeta )
ELASTIC_APM_CFG_OPT_NAME_CAPTURE_ERRORS,
/* defaultValue: */ true );

ELASTIC_APM_INIT_METADATA(
buildBoolOptionMetadata,
captureErrorsWithPhpPart,
ELASTIC_APM_CFG_OPT_NAME_CAPTURE_ERRORS_WITH_PHP_PART,
/* defaultValue: */ false );

ELASTIC_APM_INIT_METADATA(
buildOptionalBoolOptionMetadata,
captureExceptions,
ELASTIC_APM_CFG_OPT_NAME_CAPTURE_EXCEPTIONS,
/* defaultValue: */ makeNotSetOptionalBool() );

ELASTIC_APM_INIT_METADATA(
buildStringOptionMetadata,
devInternal,
Expand All @@ -1020,6 +1039,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
9 changes: 6 additions & 3 deletions agent/native/ext/ConfigManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ enum OptionId
optionId_bootstrapPhpPartFile,
optionId_breakdownMetrics,
optionId_captureErrors,
optionId_captureErrorsWithPhpPart,
optionId_captureExceptions,
optionId_devInternal,
optionId_devInternalBackendCommLogVerbose,
optionId_devInternalCaptureErrorsOnlyToLog,
optionId_disableInstrumentations,
optionId_disableSend,
optionId_enabled,
Expand Down Expand Up @@ -257,16 +260,16 @@ 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_ERRORS_WITH_PHP_PART "capture_errors_with_php_part"
#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
7 changes: 5 additions & 2 deletions agent/native/ext/ConfigSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,16 @@ struct ConfigSnapshot
bool astProcessDebugDumpConvertedBackToSource = false;
String astProcessDebugDumpForPathPrefix = nullptr;
String astProcessDebugDumpOutDir = nullptr;
OptionalBool asyncBackendComm = {false, false};
OptionalBool asyncBackendComm = ELASTIC_APM_MAKE_NOT_SET_OPTIONAL_BOOL();
String bootstrapPhpPartFile = nullptr;
bool breakdownMetrics = false;
bool captureErrors = false;
bool captureErrorsWithPhpPart = false;
OptionalBool captureExceptions = ELASTIC_APM_MAKE_NOT_SET_OPTIONAL_BOOL();
String debugDiagnosticsFile = nullptr;
String devInternal = nullptr;
bool devInternalBackendCommLogVerbose = false;
bool devInternalCaptureErrorsOnlyToLog = false;
String disableInstrumentations = nullptr;
bool disableSend = false;
bool enabled = false;
Expand Down Expand Up @@ -88,5 +92,4 @@ struct ConfigSnapshot
String transactionSampleRate = nullptr;
String urlGroups = nullptr;
bool verifyServerCert = false;
String debugDiagnosticsFile = nullptr;
};
43 changes: 28 additions & 15 deletions agent/native/ext/Hooking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,35 @@ void elastic_apm_error_cb(int type, zend_string *error_filename, const uint32_t
#endif
using namespace std::string_view_literals;

if (ELASTICAPM_G(captureErrors)) {
if (ELASTICAPM_G(captureErrorsUsingNative)) {
ELASTICAPM_G(lastErrorData) = nullptr;
std::unique_ptr<elasticapm::php::PhpErrorData> errorData;
#if PHP_VERSION_ID < 80000
char * message = nullptr;
va_list messageArgsCopy;
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);
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);
errorData = std::make_unique<elasticapm::php::PhpErrorData>(type, error_filename ? error_filename : ""sv, error_lineno, message ? message : ""sv);

if (message) {
efree(message);
}
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);
errorData = 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);
errorData = 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

if (ELASTICAPM_G(captureErrorsToLogOnly)) {
ELASTIC_APM_LOG_DEBUG(
"Captured error but only to log it; error_filename: " ELASTIC_APM_PRINTF_STRING_VIEW_FMT_SPEC() "; error_lineno: %d; message: " ELASTIC_APM_PRINTF_STRING_VIEW_FMT_SPEC(),
ELASTIC_APM_PRINTF_STD_STRING_VIEW_ARG(errorData->getFileName()), errorData->getLineNumber(), ELASTIC_APM_PRINTF_STD_STRING_VIEW_ARG(errorData->getMessage())
);
} else {
ELASTICAPM_G(lastErrorData) = std::move(errorData);
}
}

auto original = Hooking::getInstance().getOriginalZendErrorCb();
Expand Down Expand Up @@ -92,7 +102,7 @@ static void elastic_interrupt_function(zend_execute_data *execute_data) {
} zend_end_try();
}

void Hooking::replaceHooks(bool cfgCaptureErrors, bool cfgInferredSpansEnabled) {
void Hooking::replaceHooks(bool cfgCaptureErrors, bool cfgCaptureErrorsWithPhpPart, bool cfgInferredSpansEnabled) {
if (cfgInferredSpansEnabled) {
zend_execute_internal = elastic_execute_internal;
zend_interrupt_function = elastic_interrupt_function;
Expand All @@ -101,11 +111,14 @@ void Hooking::replaceHooks(bool cfgCaptureErrors, bool cfgInferredSpansEnabled)
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) {
if (cfgCaptureErrors && (!cfgCaptureErrorsWithPhpPart)) {
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" );
ELASTIC_APM_LOG_DEBUG(
"NOT replacing zend_error_cb hook because configuration options capture_errors is %s and capture_errors_with_php_part is %s",
boolToString(cfgCaptureErrors), boolToString(cfgCaptureErrorsWithPhpPart)
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion agent/native/ext/Hooking.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Hooking {
zend_error_cb = original_zend_error_cb_;
}

void replaceHooks(bool cfgCaptureErrors, bool cfgInferredSpansEnabled);
void replaceHooks(bool cfgCaptureErrors, bool cfgCaptureErrorsWithPhpPart, bool cfgInferredSpansEnabled);

zend_execute_internal_t getOriginalExecuteInternal() {
return original_execute_internal_;
Expand Down
4 changes: 3 additions & 1 deletion agent/native/ext/OptionalBool.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ static inline String optionalBoolToString( OptionalBool optionalBoolValue )
return optionalBoolValue.isSet ? "not set" : boolToString( optionalBoolValue.value );
}

#define ELASTIC_APM_MAKE_NOT_SET_OPTIONAL_BOOL() ((OptionalBool){ .isSet = false, .value = false })

static inline OptionalBool makeNotSetOptionalBool()
{
return (OptionalBool){ .isSet = false, .value = false };
return ELASTIC_APM_MAKE_NOT_SET_OPTIONAL_BOOL();
}

static inline OptionalBool makeSetOptionalBool( bool value )
Expand Down
6 changes: 5 additions & 1 deletion agent/native/ext/elastic_apm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,11 @@ 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_ERRORS_WITH_PHP_PART )
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 @@ -290,7 +293,8 @@ static PHP_GINIT_FUNCTION(elastic_apm)

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

static PHP_GSHUTDOWN_FUNCTION(elastic_apm) {
Expand Down
44 changes: 30 additions & 14 deletions agent/native/ext/lifecycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,20 @@ void elasticApmZendThrowExceptionHookImpl(
#endif
)
{
ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG("lastException set: %s", boolToString(Z_TYPE(ELASTICAPM_G(lastException)) != IS_UNDEF));

ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG( "lastException set: %s", boolToString( Z_TYPE(ELASTICAPM_G(lastException)) != IS_UNDEF ) );

resetLastThrown();

if (ELASTICAPM_G(captureErrorsToLogOnly)) {
ELASTIC_APM_LOG_DEBUG("Captured exception but only to log it");
} else {
resetLastThrown();
#if PHP_MAJOR_VERSION >= 8 /* if PHP version is 8.* and later */
ZVAL_OBJ_COPY(&ELASTICAPM_G( lastException ), thrownAsPzobj );
ZVAL_OBJ_COPY(&ELASTICAPM_G( lastException ), thrownAsPzobj );
#else
ZVAL_COPY(&ELASTICAPM_G(lastException), thrownAsPzval );
ZVAL_COPY(&ELASTICAPM_G(lastException), thrownAsPzval );
#endif
}

ELASTIC_APM_LOG_DEBUG_FUNCTION_EXIT();
ELASTIC_APM_LOG_DEBUG_FUNCTION_EXIT_MSG("lastException set: %s", boolToString(Z_TYPE(ELASTICAPM_G(lastException)) != IS_UNDEF));
}

void elasticApmGetLastThrown(zval *return_value) {
Expand Down Expand Up @@ -201,8 +203,12 @@ void elasticApmZendThrowExceptionHook(


static void registerExceptionHooks(const ConfigSnapshot& config) {
if (!config.captureErrors) {
ELASTIC_APM_LOG_DEBUG( "NOT replacing zend_throw_exception_hook hook because capture_errors configuration option is set to false" );
bool shouldCaptureExceptions = config.captureExceptions.isSet ? config.captureExceptions.value : config.captureErrors;
if ((!shouldCaptureExceptions) || config.captureErrorsWithPhpPart) {
ELASTIC_APM_LOG_DEBUG(
"NOT replacing zend_throw_exception_hook hook because configuration options capture_exceptions is %s, capture_errors is %s and capture_errors_with_php_part is %s",
optionalBoolToString(config.captureExceptions), boolToString(config.captureErrors), boolToString(config.captureErrorsWithPhpPart)
);
return;
}

Expand Down Expand Up @@ -291,7 +297,7 @@ void elasticApmModuleInit( int moduleType, int moduleNumber )

astInstrumentationOnModuleInit( config );

elasticapm::php::Hooking::getInstance().replaceHooks(config->captureErrors, config->profilingInferredSpansEnabled);
elasticapm::php::Hooking::getInstance().replaceHooks(config->captureErrors, config->captureErrorsWithPhpPart, config->profilingInferredSpansEnabled);

if (php_check_open_basedir_ex(config->bootstrapPhpPartFile, false) != 0) {
ELASTIC_APM_LOG_WARNING(
Expand Down Expand Up @@ -484,10 +490,20 @@ void elasticApmRequestInit()
goto finally;
}

if (!config->captureErrors) {
ELASTICAPM_G(captureErrorsUsingNative) = false;
if (config->captureErrors) {
if (config->captureErrorsWithPhpPart) {
ELASTIC_APM_LOG_DEBUG( "capture_errors_with_php_part (captureErrorsWithPhpPart) configuration option is set to true which means errors will be captured by PHP part of the agent" );
} else {
ELASTICAPM_G(captureErrorsUsingNative) = true;
}
if (config->devInternalCaptureErrorsOnlyToLog) {
ELASTIC_APM_LOG_DEBUG( "dev_internal_capture_errors_only_to_log (devInternalCaptureErrorsOnlyToLog) configuration option is set to true which means errors will be logged only" );
}
} else {
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;
}
ELASTICAPM_G(captureErrorsToLogOnly) = config->devInternalCaptureErrorsOnlyToLog;

if ( config->astProcessEnabled )
{
Expand Down Expand Up @@ -590,7 +606,7 @@ void elasticApmRequestShutdown()
ELASTICAPM_G(globals)->periodicTaskExecutor_->suspendPeriodicTasks();
}

ELASTICAPM_G(captureErrors) = false; // disabling error capturing on shutdown
ELASTICAPM_G(captureErrorsUsingNative) = false; // disabling error capturing on shutdown

tracerPhpPartOnRequestShutdown();

Expand Down
3 changes: 3 additions & 0 deletions agent/native/ext/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include "TextOutputStream.h"
#include "platform.h"

#define ELASTIC_APM_PRINTF_STRING_VIEW_FMT_SPEC() "%.*s"
#define ELASTIC_APM_PRINTF_STD_STRING_VIEW_ARG(stdStrVw) (static_cast<int>((stdStrVw).length())), ((stdStrVw).data())

extern String logLevelNames[ numberOfLogLevels ];

enum LogSinkType
Expand Down
3 changes: 2 additions & 1 deletion agent/native/ext/php_elastic_apm.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ ZEND_BEGIN_MODULE_GLOBALS(elastic_apm)
elasticapm::php::AgentGlobals *globals;
zval lastException;
std::unique_ptr<elasticapm::php::PhpErrorData> lastErrorData;
bool captureErrors;
bool captureErrorsUsingNative;
bool captureErrorsToLogOnly;
ZEND_END_MODULE_GLOBALS(elastic_apm)

ZEND_EXTERN_MODULE_GLOBALS(elastic_apm)
Expand Down
Loading
Loading