agent/native/ext/elastic_apm.cpp (501 lines of code) (raw):
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "php_elastic_apm.h"
// external libraries
#include <php_ini.h>
#include <php.h>
#include <zend_types.h>
#include "constants.h"
#include "lifecycle.h"
#include "supportability_zend.h"
#include "elastic_apm_API.h"
#include "ConfigManager.h"
#include "elastic_apm_assert.h"
#include "elastic_apm_alloc.h"
#include "tracer_PHP_part.h"
#include "PhpBridge.h"
#include "CommonUtils.h"
#define ELASTIC_APM_CURRENT_LOG_CATEGORY ELASTIC_APM_LOG_CATEGORY_EXT_INFRA
ZEND_DECLARE_MODULE_GLOBALS( elastic_apm )
Tracer* getGlobalTracer()
{
return &( ZEND_MODULE_GLOBALS_ACCESSOR( elastic_apm, globalTracer ) );
}
#ifndef ZEND_PARSE_PARAMETERS_NONE
# define ZEND_PARSE_PARAMETERS_NONE() \
ZEND_PARSE_PARAMETERS_START(0, 0) \
ZEND_PARSE_PARAMETERS_END()
#endif
static inline ResultCode zendToResultCode( ZEND_RESULT_CODE zendResultCode )
{
if ( zendResultCode == SUCCESS ) return resultSuccess;
return resultFailure;
}
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(elastic_apm)
{
ResultCode resultCode;
// 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__ ) );
elasticApmRequestInit();
// We ignore errors because we want the monitored application to continue working
// even if APM encountered an issue that prevent it from working
finally:
return SUCCESS;
failure:
goto finally;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(elastic_apm)
{
ResultCode resultCode;
// 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__ ) );
elasticApmRequestShutdown();
// We ignore errors because we want the monitored application to continue working
// even if APM encountered an issue that prevent it from working
finally:
return SUCCESS;
failure:
goto finally;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(elastic_apm)
{
ResultCode resultCode;
// 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__ ) );
elasticApmModuleInfo( zend_module );
// We ignore errors because we want the monitored application to continue working
// even if APM encountered an issue that prevent it from working
finally:
return;
failure:
goto finally;
}
/* }}} */
#define ELASTIC_APM_INI_ENTRY_IMPL( optName, isReloadableFlag ) \
PHP_INI_ENTRY( \
"elastic_apm." optName \
, /* default value: */ NULL \
, isReloadableFlag \
, /* on_modify (validator): */ NULL )
#define ELASTIC_APM_INI_ENTRY( optName ) ELASTIC_APM_INI_ENTRY_IMPL( optName, PHP_INI_ALL )
#define ELASTIC_APM_NOT_RELOADABLE_INI_ENTRY( optName ) ELASTIC_APM_INI_ENTRY_IMPL( optName, PHP_INI_PERDIR )
PHP_INI_BEGIN()
ELASTIC_APM_NOT_RELOADABLE_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ABORT_ON_MEMORY_LEAK )
#ifdef PHP_WIN32
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ALLOW_ABORT_DIALOG )
#endif
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_API_KEY )
#if ( ELASTIC_APM_ASSERT_ENABLED_01 != 0 )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ASSERT_LEVEL )
#endif
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_AST_PROCESS_ENABLED )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_AST_PROCESS_DEBUG_DUMP_CONVERTED_BACK_TO_SOURCE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_AST_PROCESS_DEBUG_DUMP_FOR_PATH_PREFIX )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_AST_PROCESS_DEBUG_DUMP_OUT_DIR )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ASYNC_BACKEND_COMM )
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_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_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 )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_GLOBAL_LABELS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_ENVIRONMENT )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_HOSTNAME )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_INTERNAL_CHECKS_LEVEL )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_FILE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_LEVEL )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_LEVEL_FILE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_LEVEL_STDERR )
#ifndef PHP_WIN32
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_LEVEL_SYSLOG )
#endif
#ifdef PHP_WIN32
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_LOG_LEVEL_WIN_SYS_DEBUG )
#endif
#if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_MEMORY_TRACKING_LEVEL )
#endif
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_NON_KEYWORD_STRING_MAX_LENGTH )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_PROFILING_INFERRED_SPANS_ENABLED )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_PROFILING_INFERRED_SPANS_MIN_DURATION )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_PROFILING_INFERRED_SPANS_SAMPLING_INTERVAL )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SANITIZE_FIELD_NAMES )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SECRET_TOKEN )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SERVER_TIMEOUT )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SERVER_URL )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SERVICE_NAME )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SERVICE_NODE_NAME )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SERVICE_VERSION )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SPAN_COMPRESSION_ENABLED )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SPAN_COMPRESSION_EXACT_MATCH_MAX_DURATION )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SPAN_COMPRESSION_SAME_KIND_MAX_DURATION )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_SPAN_STACK_TRACE_MIN_DURATION )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_STACK_TRACE_LIMIT )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_TRANSACTION_IGNORE_URLS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_TRANSACTION_MAX_SPANS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_TRANSACTION_SAMPLE_RATE )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_URL_GROUPS )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_VERIFY_SERVER_CERT )
ELASTIC_APM_INI_ENTRY( ELASTIC_APM_CFG_OPT_NAME_DEBUG_DIAGNOSTICS_FILE )
PHP_INI_END()
#undef ELASTIC_APM_INI_ENTRY_IMPL
#undef ELASTIC_APM_INI_ENTRY
#undef ELASTIC_APM_NOT_RELOADABLE_INI_ENTRY
#undef ELASTIC_APM_SECRET_INI_ENTRY
ResultCode registerElasticApmIniEntries( int type, int module_number, IniEntriesRegistrationState* iniEntriesRegistrationState )
{
ELASTIC_APM_LOG_TRACE_FUNCTION_ENTRY_MSG( "module: { type: %d, number: %d }", type, module_number );
ELASTIC_APM_ASSERT_VALID_PTR( iniEntriesRegistrationState );
ResultCode resultCode;
const ConfigManager* const cfgManager = getGlobalTracer()->configManager;
ELASTIC_APM_CALL_IF_FAILED_GOTO( zendToResultCode( (ZEND_RESULT_CODE)REGISTER_INI_ENTRIES() ) );
iniEntriesRegistrationState->entriesRegistered = true;
ELASTIC_APM_FOR_EACH_OPTION_ID( optId )
{
GetConfigManagerOptionMetadataResult getMetaRes;
getConfigManagerOptionMetadata( cfgManager, optId, &getMetaRes );
if ( ! getMetaRes.isSecret ) continue;
int zendResultCode = zend_ini_register_displayer( (char*) ( getMetaRes.iniName.begin )
, (uint32_t) ( getMetaRes.iniName.length )
, displaySecretIniValue );
if ( zendResultCode != SUCCESS )
{
ELASTIC_APM_LOG_ERROR( "zend_ini_register_displayer() failed with result code: %d; iniName: %.*s."
, zendResultCode
, (int) getMetaRes.iniName.length, getMetaRes.iniName.begin );
ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
}
}
resultCode = resultSuccess;
finally:
ELASTIC_APM_LOG_TRACE_RESULT_CODE_FUNCTION_EXIT();
return resultCode;
failure:
unregisterElasticApmIniEntries( type, module_number, iniEntriesRegistrationState );
goto finally;
}
void unregisterElasticApmIniEntries( int type, int module_number, IniEntriesRegistrationState* iniEntriesRegistrationState )
{
ELASTIC_APM_LOG_TRACE_FUNCTION_ENTRY_MSG( "module: { type: %d, number: %d }", type, module_number );
if ( iniEntriesRegistrationState->entriesRegistered )
{
UNREGISTER_INI_ENTRIES();
iniEntriesRegistrationState->entriesRegistered = false;
}
ELASTIC_APM_LOG_TRACE_FUNCTION_EXIT();
}
static PHP_GINIT_FUNCTION(elastic_apm)
{
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
ELASTIC_APM_LOG_DIRECT_DEBUG( "%s: GINIT called; parent PID: %d", __FUNCTION__, (int)getParentProcessId() );
// memset(&elastic_apm_globals->globalTracer, 0, sizeof(Tracer));
elastic_apm_globals->globals = nullptr;
auto phpBridge = std::make_shared<elasticapm::php::PhpBridge>();
auto inferredSpans = std::make_shared<elasticapm::php::InferredSpans>([interruptFlag = reinterpret_cast<void *>(&EG(vm_interrupt))]() {
#if PHP_VERSION_ID >= 80200
zend_atomic_bool_store_ex(reinterpret_cast<zend_atomic_bool *>(interruptFlag), true);
#else
*static_cast<zend_bool *>(interruptFlag) = 1;
#endif
}, [phpBridge](elasticapm::php::InferredSpans::time_point_t requestTime, elasticapm::php::InferredSpans::time_point_t now) {
phpBridge->callInferredSpans(now - requestTime);
});
elasticapm::php::PhpSapi sapi(phpBridge->getPhpSapiName());
try {
elastic_apm_globals->globals = new elasticapm::php::AgentGlobals(std::move(phpBridge), std::move(sapi), {}, std::move(inferredSpans), std::make_shared<elasticapm::php::SharedMemoryState>());
} 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)
{
ResultCode resultCode;
// 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__ ) );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_NOT_SET", logLevel_not_set, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_OFF", logLevel_off, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_CRITICAL", logLevel_critical, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_ERROR", logLevel_error, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_WARNING", logLevel_warning, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_INFO", logLevel_info, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_DEBUG", logLevel_debug, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_LOG_LEVEL_TRACE", logLevel_trace, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_ASSERT_LEVEL_NOT_SET", assertLevel_not_set, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_ASSERT_LEVEL_OFF", assertLevel_off, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_ASSERT_LEVEL_O_1", assertLevel_O_1, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_ASSERT_LEVEL_O_N", assertLevel_O_n, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_ASSERT_LEVEL_ALL", assertLevel_all, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_NOT_SET", memoryTrackingLevel_not_set, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_OFF", memoryTrackingLevel_off, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_TOTAL_COUNT_ONLY", memoryTrackingLevel_totalCountOnly, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_EACH_ALLOCATION", memoryTrackingLevel_eachAllocation, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_EACH_ALLOCATION_WITH_STACK_TRACE", memoryTrackingLevel_eachAllocationWithStackTrace, CONST_CS|CONST_PERSISTENT );
REGISTER_LONG_CONSTANT( "ELASTIC_APM_MEMORY_TRACKING_LEVEL_ALL", memoryTrackingLevel_all, CONST_CS|CONST_PERSISTENT );
REGISTER_STRING_CONSTANT( ELASTIC_APM_WORDPRESS_DIRECT_CALL_METHOD_SET_READY_TO_WRAP_FILTER_CALLBACKS_CONST_NAME
, ELASTIC_APM_WORDPRESS_DIRECT_CALL_METHOD_SET_READY_TO_WRAP_FILTER_CALLBACKS
, CONST_CS | CONST_PERSISTENT );
elasticApmModuleInit( type, module_number );
// We ignore errors because we want the monitored application to continue working
// even if APM encountered an issue that prevent it from working
finally:
return SUCCESS;
failure:
goto finally;
}
PHP_MSHUTDOWN_FUNCTION(elastic_apm)
{
ResultCode resultCode;
// 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__ ) );
elasticApmModuleShutdown( type, module_number );
// We ignore errors because we want the monitored application to continue working
// even if APM encountered an issue that prevent it from working
finally:
return SUCCESS;
failure:
goto finally;
}
/* {{{ bool elastic_apm_is_enabled()
*/
PHP_FUNCTION( elastic_apm_is_enabled )
{
RETVAL_BOOL(false);
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
ZEND_PARSE_PARAMETERS_NONE();
RETVAL_BOOL(elasticApmIsEnabled());
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_get_config_option_by_name_arginfo, 0, 0, 1 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, optionName, IS_STRING, /* allow_null: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_get_config_option_by_name( string $optionName ): mixed
*/
PHP_FUNCTION( elastic_apm_get_config_option_by_name )
{
ZVAL_NULL( return_value );
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != ResultCode::resultSuccess) {
return;
}
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
char* optionName = NULL;
size_t optionNameLength = 0;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING( optionName, optionNameLength )
ZEND_PARSE_PARAMETERS_END();
elasticApmGetConfigOption( optionName, /* out */ return_value );
}
/* }}} */
/* {{{ elastic_apm_get_number_of_dynamic_config_options(): int
*/
PHP_FUNCTION( elastic_apm_get_number_of_dynamic_config_options )
{
ResultCode resultCode;
long retVal = 0;
// 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__ ) );
ZEND_PARSE_PARAMETERS_NONE();
retVal = elasticApmGetNumberOfDynamicConfigOptions(); // NOLINT(cppcoreguidelines-narrowing-conversions)
finally:
RETURN_LONG( retVal );
failure:
goto finally;
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_intercept_calls_to_internal_method_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 2 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, /* name */ className, IS_STRING, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, /* name */ methodName, IS_STRING, /* allow_null: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_intercept_calls_to_internal_method( string $className, string $methodName ): int // <- interceptRegistrationId
*/
PHP_FUNCTION( elastic_apm_intercept_calls_to_internal_method )
{
RETVAL_LONG(-1);
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
char* className = NULL;
size_t classNameLength = 0;
char* methodName = NULL;
size_t methodNameLength = 0;
uint32_t interceptRegistrationId;
ZEND_PARSE_PARAMETERS_START( /* min_num_args: */ 2, /* max_num_args: */ 2 )
Z_PARAM_STRING( className, classNameLength )
Z_PARAM_STRING( methodName, methodNameLength )
ZEND_PARSE_PARAMETERS_END();
if (elasticApmInterceptCallsToInternalMethod( className, methodName, &interceptRegistrationId ) != resultSuccess) {
return;
}
RETURN_LONG(interceptRegistrationId);
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_intercept_calls_to_internal_function_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 1 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, /* name */ functionName, IS_STRING, /* allow_null: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_intercept_calls_to_internal_function( string $className, string $functionName ): int // <- interceptRegistrationId
*/
PHP_FUNCTION( elastic_apm_intercept_calls_to_internal_function )
{
RETVAL_LONG(-1);
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
char* functionName = NULL;
size_t functionNameLength = 0;
uint32_t interceptRegistrationId;
ZEND_PARSE_PARAMETERS_START( /* min_num_args: */ 1, /* max_num_args: */ 1 )
Z_PARAM_STRING( functionName, functionNameLength )
ZEND_PARSE_PARAMETERS_END();
if (elasticApmInterceptCallsToInternalFunction( functionName, &interceptRegistrationId ) != resultSuccess) {
return;
}
RETURN_LONG(interceptRegistrationId);
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_send_to_server_arginfo, /* _unused: */ 0, /* return_reference: */ 0, /* required_num_args: */ 2 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, userAgentHttpHeader, IS_STRING, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, serializedEvents, IS_STRING, /* allow_null: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_send_to_server(
* string userAgentHttpHeader,
* string $serializedEvents ): bool
*/
PHP_FUNCTION( elastic_apm_send_to_server ) {
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
RETURN_BOOL(false);
return;
}
char* userAgentHttpHeader = NULL;
size_t userAgentHttpHeaderLength = 0;
char* serializedEvents = NULL;
size_t serializedEventsLength = 0;
ZEND_PARSE_PARAMETERS_START( /* min_num_args: */ 2, /* max_num_args: */ 2 )
Z_PARAM_STRING( userAgentHttpHeader, userAgentHttpHeaderLength )
Z_PARAM_STRING( serializedEvents, serializedEventsLength )
ZEND_PARSE_PARAMETERS_END();
if (elasticApmSendToServer(makeStringView( userAgentHttpHeader, userAgentHttpHeaderLength ) , makeStringView( serializedEvents, serializedEventsLength )) != resultSuccess) {
RETURN_BOOL(false);
}
RETURN_BOOL(true);
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_log_arginfo, /* _unused: */ 0, /* return_reference: */ 0, /* required_num_args: */ 7 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, isForced, IS_LONG, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, level, IS_LONG, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, category, IS_STRING, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, file, IS_STRING, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, line, IS_LONG, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, func, IS_STRING, /* allow_null: */ 0 )
ZEND_ARG_TYPE_INFO( /* pass_by_ref: */ 0, message, IS_STRING, /* allow_null: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_log(
* int $isForced,
* int $level,
* string $category,
* string $file,
* int $line,
* string $func,
* string $message
* ): void
*/
PHP_FUNCTION( elastic_apm_log )
{
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
zend_long isForced = 0;
zend_long level = 0;
char* file = NULL;
size_t fileLength = 0;
char* category = NULL;
size_t categoryLength = 0;
zend_long line = 0;
char* func = NULL;
size_t funcLength = 0;
char* message = NULL;
size_t messageLength = 0;
ZEND_PARSE_PARAMETERS_START( /* min_num_args: */ 7, /* max_num_args: */ 7 )
Z_PARAM_LONG( isForced )
Z_PARAM_LONG( level )
Z_PARAM_STRING( category, categoryLength )
Z_PARAM_STRING( file, fileLength )
Z_PARAM_LONG( line )
Z_PARAM_STRING( func, funcLength )
Z_PARAM_STRING( message, messageLength )
ZEND_PARSE_PARAMETERS_END();
logWithLogger(
getGlobalLogger()
, /* isForced: */ ( isForced != 0 )
, /* statementLevel: */ (LogLevel) level
, /* category: */ makeStringView( category, categoryLength )
, /* filePath: */ makeStringView( file, fileLength )
, /* lineNumber: */ (UInt) line
, /* funcName: */ makeStringView( func, funcLength )
, /* msgPrintfFmt: */ "%s"
, /* msgPrintfFmtArgs: */ message );
}
/* }}} */
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
*/
PHP_FUNCTION( elastic_apm_before_loading_agent_php_code )
{
elasticApmBeforeLoadingAgentPhpCode();
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_after_loading_agent_php_code_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_after_loading_agent_php_code(): void
*/
PHP_FUNCTION( elastic_apm_after_loading_agent_php_code )
{
elasticApmAfterLoadingAgentPhpCode();
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_ast_instrumentation_pre_hook_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_after_loading_agent_php_code(): void
*/
PHP_FUNCTION( elastic_apm_ast_instrumentation_pre_hook )
{
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
tracerPhpPartAstInstrumentationCallPreHook( execute_data, return_value );
}
/* }}} */
ZEND_BEGIN_ARG_INFO_EX( elastic_apm_ast_instrumentation_direct_call_arginfo, /* _unused */ 0, /* return_reference: */ 0, /* required_num_args: */ 0 )
ZEND_END_ARG_INFO()
/* {{{ elastic_apm_after_loading_agent_php_code(): void
*/
PHP_FUNCTION( elastic_apm_ast_instrumentation_direct_call )
{
// We SHOULD NOT log before resetting state if forked because logging might be using thread synchronization
// which might deadlock in forked child
if (elasticApmApiEntered( __FILE__, __LINE__, __FUNCTION__ ) != resultSuccess) {
return;
}
tracerPhpPartAstInstrumentationDirectCall( execute_data );
}
/* }}} */
/* {{{ arginfo
*/
ZEND_BEGIN_ARG_INFO(elastic_apm_no_paramters_arginfo, 0)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ elastic_apm_functions[]
*/
static const zend_function_entry elastic_apm_functions[] =
{
PHP_FE( elastic_apm_is_enabled, elastic_apm_no_paramters_arginfo )
PHP_FE( elastic_apm_get_config_option_by_name, elastic_apm_get_config_option_by_name_arginfo )
PHP_FE( elastic_apm_get_number_of_dynamic_config_options, elastic_apm_no_paramters_arginfo )
PHP_FE( elastic_apm_intercept_calls_to_internal_method, elastic_apm_intercept_calls_to_internal_method_arginfo )
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 )
PHP_FE( elastic_apm_ast_instrumentation_direct_call, elastic_apm_ast_instrumentation_direct_call_arginfo )
PHP_FE_END
};
/* }}} */
/* {{{ elastic_apm_module_entry
*/
zend_module_entry elastic_apm_module_entry = {
STANDARD_MODULE_HEADER,
"elastic_apm", /* Extension name */
elastic_apm_functions, /* zend_function_entry */
PHP_MINIT(elastic_apm), /* PHP_MINIT - Module initialization */
PHP_MSHUTDOWN(elastic_apm), /* PHP_MSHUTDOWN - Module shutdown */
PHP_RINIT(elastic_apm), /* PHP_RINIT - Request initialization */
PHP_RSHUTDOWN(elastic_apm), /* PHP_RSHUTDOWN - Request shutdown */
PHP_MINFO(elastic_apm), /* PHP_MINFO - Module info */
PHP_ELASTIC_APM_VERSION, /* Version */
PHP_MODULE_GLOBALS(elastic_apm), /* PHP_MODULE_GLOBALS */
PHP_GINIT(elastic_apm), /* PHP_GINIT */
PHP_GSHUTDOWN(elastic_apm), /* PHP_GSHUTDOWN */
elasticApmRequestPostDeactivate, /* post deactivate */
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
extern "C" ZEND_GET_MODULE(elastic_apm)