-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(agent): Registered function begin/end and error handlers with Ob…
…server API (#501) * feat(agent): Registered function begin/end and error handlers with Observer API 1) Registered function begin/end handlers with Observer API 2) Created the function begin/end handler stubs. Full functionality is schedule for another ticket. 3) Registered currently existing error handler with Observer API 4) created php_observer.c/h module to contain the observer api logic. Testing: 1) Verified new function begin/end handlers were registered correctly and received zend_execute_data from PHP engine. 2) Current test cases verified that registering our current error handler directly caused no change in functionality. Additional * feat(agent): Don't call handlers for internal functions. Currently internal functions are not handled by OAPI, but they will be in 8.2. These functions are tailored to USER functions (similar to nr_php_execute) and we don't want internal functions filtered to these handlers. This will default to INTERNAL functions being handled by the current implementation. To change in the future, it's possible we'd need to implement handlers specific for internal functions (similar to nr_php_execute_internal).
- Loading branch information
Showing
9 changed files
with
236 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright 2022 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* This file handles the initialization that happens once per module load. | ||
*/ | ||
#include "php_agent.h" | ||
|
||
#include <dlfcn.h> | ||
#include <signal.h> | ||
|
||
#include "php_api_distributed_trace.h" | ||
#include "php_environment.h" | ||
#include "php_error.h" | ||
#include "php_extension.h" | ||
#include "php_globals.h" | ||
#include "php_header.h" | ||
#include "php_hooks.h" | ||
#include "php_internal_instrument.h" | ||
#include "php_samplers.h" | ||
#include "php_user_instrument.h" | ||
#include "php_vm.h" | ||
#include "php_wrapper.h" | ||
#include "fw_laravel.h" | ||
#include "lib_guzzle4.h" | ||
#include "lib_guzzle6.h" | ||
#include "nr_agent.h" | ||
#include "nr_app.h" | ||
#include "nr_banner.h" | ||
#include "nr_daemon_spawn.h" | ||
#include "util_logging.h" | ||
#include "util_memory.h" | ||
#include "util_signals.h" | ||
#include "util_strings.h" | ||
#include "util_syscalls.h" | ||
#include "util_threads.h" | ||
|
||
#include "php_observer.h" | ||
#include "php_execute.h" | ||
|
||
/* | ||
* Observer API functionality was added with PHP 8.0. | ||
* | ||
* The Observer API provide function handlers that trigger on every userland | ||
* function begin and end. The handlers provide all zend_execute_data and the | ||
* end handler provides the return value pointer. The previous way to hook into | ||
* PHP was via zend_execute_ex which will hook all userland function calls with | ||
* significant overhead for doing the call. However, depending on user stack | ||
* size settings, it could potentially generate an extremely deep call stack in | ||
* PHP because zend_execute_ex limits stack size to whatever user settings | ||
* are. Observer API bypasses the stack overflow issue that an agent could run | ||
* into when intercepting userland calls. Additionally, with PHP 8.0, JIT | ||
* optimizations could optimize out a call to zend_execute_ex and the agent | ||
* would not be able to overwite that call properly as the agent wouldn't have | ||
* access to the JITed information. This could lead to segfaults and caused PHP | ||
* to decide to disable JIT when detecting extensions that overwrote | ||
* zend_execute_ex. | ||
* | ||
* It only provides ZEND_USER_FUNCTIONS yet as it was assumed mechanisms already | ||
* exist to monitor internal functions by overwriting internal function | ||
* handlers. This will be included in PHP 8.2: Registered | ||
* zend_observer_fcall_init handlers are now also called for internal functions. | ||
* | ||
* Without overwriting the execute function and therefore being responsible for | ||
* continuing the execution of ALL functions that we intercepted, the agent is | ||
* provided zend_execute_data on each function start/end and is then able to use | ||
* it with our currently existing logic and instrumentation. | ||
*/ | ||
|
||
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP8+ */ | ||
/* | ||
* Register the begin and end function handlers with the Observer API. | ||
*/ | ||
static zend_observer_fcall_handlers nr_php_fcall_register_handlers( | ||
zend_execute_data* execute_data) { | ||
zend_observer_fcall_handlers handlers = {NULL, NULL}; | ||
if (NULL == execute_data) { | ||
return handlers; | ||
} | ||
if ((NULL == execute_data->func) | ||
|| (ZEND_INTERNAL_FUNCTION == execute_data->func->type)) { | ||
return handlers; | ||
} | ||
handlers.begin = nr_php_observer_fcall_begin; | ||
handlers.end = nr_php_observer_fcall_end; | ||
return handlers; | ||
} | ||
|
||
void nr_php_observer_minit() { | ||
/* | ||
* Register the Observer API handlers. | ||
*/ | ||
zend_observer_fcall_register(nr_php_fcall_register_handlers); | ||
zend_observer_error_register(nr_php_error_cb); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright 2022 New Relic Corporation. All rights reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/* | ||
* This file is the wrapper for PHP 8+ Observer API (OAPI) functionality. | ||
* | ||
* The registered function handlers are the entry points of instrumentation and | ||
* are implemented in php_execute.c which contains the brains/helper functions | ||
* required to monitor PHP. | ||
*/ | ||
|
||
#ifndef NEWRELIC_PHP_AGENT_PHP_OBSERVER_H | ||
#define NEWRELIC_PHP_AGENT_PHP_OBSERVER_H | ||
|
||
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO /* PHP8+ */ | ||
|
||
#include "Zend/zend_observer.h" | ||
|
||
/* | ||
* Purpose : Register the OAPI function handlers and any other minit actions. | ||
* | ||
* Params : None | ||
* | ||
* Returns : Void. | ||
*/ | ||
void nr_php_observer_minit(); | ||
|
||
/* | ||
* Purpose : Call the necessary functions needed to instrument a function by | ||
* updating a transaction or segment for a function that has just | ||
* started. This function is registered via the Observer API and will be called | ||
* by the zend engine every time a function begins. The zend engine directly | ||
* provides the zend_execute_data which has all details we need to know about | ||
* the function. This and nr_php_execute_observer_fcall_end sum to provide all | ||
* the functionality of nr_php_execute and nr_php _execute_enabled and as such | ||
* will use all the helper functions they also used. | ||
* | ||
* | ||
* Params : 1. zend_execute_data: everything we need to know about the | ||
* function. | ||
* | ||
* Returns : Void. | ||
*/ | ||
void nr_php_observer_fcall_begin(zend_execute_data* execute_data); | ||
/* | ||
* Purpose : Call the necessary functions needed to instrument a function when | ||
* updating a transaction or segment for a function that has just | ||
* ended. This function is registered via the Observer API and will be called by | ||
* the zend engine every time a function ends. The zend engine directly | ||
* provides the zend_execute_data and the return_value pointer, both of which | ||
* have all details that the agent needs to know about the function. This and | ||
* nr_php_execute_observer_fcall_start sum to provide all the functionality of | ||
* nr_php_execute and nr_php_execute_enabled and as such will use all the helper | ||
* functions they also used. | ||
* | ||
* | ||
* Params : 1. zend_execute_data: everything to know about the function. | ||
* 2. return_value: function return value information | ||
* | ||
* Returns : Void. | ||
*/ | ||
void nr_php_observer_fcall_end(zend_execute_data* execute_data, | ||
zval* return_value); | ||
#endif /* PHP8+ */ | ||
|
||
#endif // NEWRELIC_PHP_AGENT_PHP_OBSERVER_H |