|
9 | 9 | #include "php_user_instrument.h"
|
10 | 10 | #include "php_execute.h"
|
11 | 11 | #include "php_wrapper.h"
|
| 12 | +#include "php_error.h" |
12 | 13 | #include "fw_drupal_common.h"
|
13 | 14 | #include "fw_hooks.h"
|
14 | 15 | #include "fw_support.h"
|
|
20 | 21 |
|
21 | 22 | #define PHP_PACKAGE_NAME "drupal/core"
|
22 | 23 |
|
| 24 | +NR_PHP_WRAPPER(nr_drupal_exception) { |
| 25 | + int priority = nr_php_error_get_priority(E_ERROR); |
| 26 | + zval* event = NULL; |
| 27 | + zval* exception = NULL; |
| 28 | + |
| 29 | + /* Warning avoidance */ |
| 30 | + (void)wraprec; |
| 31 | + |
| 32 | + NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_DRUPAL8); |
| 33 | + |
| 34 | + if (NR_SUCCESS != nr_txn_record_error_worthy(NRPRG(txn), priority)) { |
| 35 | + NR_PHP_WRAPPER_CALL; |
| 36 | + goto end; |
| 37 | + } |
| 38 | + |
| 39 | + /* Get the event that was given. */ |
| 40 | + event = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS); |
| 41 | + |
| 42 | + /* Call the original function. */ |
| 43 | + NR_PHP_WRAPPER_CALL; |
| 44 | + |
| 45 | + if (0 == nr_php_is_zval_valid_object(event)) { |
| 46 | + nrl_verbosedebug(NRL_TXN, |
| 47 | + "Drupal: ExceptionSubscriber::onException() does not " |
| 48 | + "have an `event` parameter"); |
| 49 | + goto end; |
| 50 | + } |
| 51 | + |
| 52 | + /* |
| 53 | + * Get the exception from the event. |
| 54 | + */ |
| 55 | + exception = nr_php_call(event, "getThrowable"); |
| 56 | + if (!nr_php_is_zval_valid_object(exception)) { |
| 57 | + // be abundantly cautious: free exception before attempting to re-assign |
| 58 | + nr_php_zval_free(&exception); |
| 59 | + exception = nr_php_call(event, "getException"); |
| 60 | + } |
| 61 | + |
| 62 | + if (!nr_php_is_zval_valid_object(exception)) { |
| 63 | + nrl_verbosedebug(NRL_TXN, "Drupal: getException() returned a non-object"); |
| 64 | + goto end; |
| 65 | + } |
| 66 | + |
| 67 | + if (NR_SUCCESS |
| 68 | + != nr_php_error_record_exception(NRPRG(txn), exception, priority, true, |
| 69 | + NULL, |
| 70 | + &NRPRG(exception_filters))) { |
| 71 | + nrl_verbosedebug(NRL_TXN, "Drupal: unable to record exception"); |
| 72 | + } |
| 73 | + |
| 74 | +end: |
| 75 | + nr_php_arg_release(&event); |
| 76 | + nr_php_zval_free(&exception); |
| 77 | +} |
| 78 | +NR_PHP_WRAPPER_END |
| 79 | + |
23 | 80 | /*
|
24 | 81 | * Purpose : Convenience function to handle adding a callback to a method,
|
25 | 82 | * given a class entry and a method name. This will check the
|
@@ -730,6 +787,26 @@ void nr_drupal8_enable(TSRMLS_D) {
|
730 | 787 | "er::getControllerFromDefinition"),
|
731 | 788 | nr_drupal8_name_the_wt TSRMLS_CC);
|
732 | 789 |
|
| 790 | + /* |
| 791 | + * ExceptionSubscribers handle Drupal errors and exceptions before |
| 792 | + * the agent has the opportunity to capture them. Instrument several |
| 793 | + * of these ExceptionSubscriber function `onException` methods in order |
| 794 | + * to capture Exceptions and Errors in Drupal 9.x+ |
| 795 | + */ |
| 796 | + // clang-format off |
| 797 | + /* |
| 798 | + * Log exceptions without further handling. |
| 799 | + */ |
| 800 | + nr_php_wrap_user_function(NR_PSTR("Drupal\\Core\\EventSubscriber\\ExceptionLoggingSubscriber::onException"), |
| 801 | + nr_drupal_exception); |
| 802 | + |
| 803 | + /* |
| 804 | + * Last-chance handler for exceptions: the final exception subscriber. |
| 805 | + */ |
| 806 | + nr_php_wrap_user_function(NR_PSTR("Drupal\\Core\\EventSubscriber\\FinalExceptionSubscriber::onException"), |
| 807 | + nr_drupal_exception); |
| 808 | + // clang-format on |
| 809 | + |
733 | 810 | /*
|
734 | 811 | * The drupal_modules config setting controls instrumentation of modules,
|
735 | 812 | * hooks, and views.
|
|
0 commit comments