Skip to content

Commit 2a7da47

Browse files
committed
feat(agent): add drupal hook attribute instrumentation
1 parent 8ddc8af commit 2a7da47

File tree

1 file changed

+127
-10
lines changed

1 file changed

+127
-10
lines changed

agent/fw_drupal8.c

Lines changed: 127 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -605,12 +605,123 @@ NR_PHP_WRAPPER(nr_drupal94_invoke_all_with_clean) {
605605
NR_PHP_WRAPPER_END
606606
#endif // OAPI
607607

608+
/*
609+
* Purpose: Instrument Drupal Attribute Hooks for Drupal 11.1+
610+
*
611+
* Params: 1. A zval pointer to the moduleHandler instance in use by Drupal.
612+
*
613+
* Return: bool
614+
*
615+
*/
616+
static bool nr_drupal_hook_attribute_instrument(zval* module_handler) {
617+
zval* hook_implementation_map = NULL;
618+
619+
nr_php_string_hash_key_t* hook_key = NULL;
620+
zval* hook_val = NULL;
621+
nr_php_string_hash_key_t* class_key = NULL;
622+
zval* class_val = NULL;
623+
nr_php_string_hash_key_t* method_key = NULL;
624+
zval* module_val = NULL;
625+
zend_ulong key_num = 0;
626+
627+
char* hook_str = NULL;
628+
char* class_str = NULL;
629+
char* method_str = NULL;
630+
char* module_str = NULL;
631+
char* hookpath = NULL;
632+
633+
hook_implementation_map = nr_php_get_zval_object_property(
634+
module_handler, "hookImplementationsMap");
635+
if (hook_implementation_map) {
636+
if (nr_php_is_zval_valid_array(hook_implementation_map)) {
637+
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(hook_implementation_map), key_num,
638+
hook_key, hook_val) {
639+
(void)key_num;
640+
if ((NULL == hook_key) || (0 == nr_php_is_zval_valid_array(hook_val))) {
641+
nrl_warning(NRL_FRAMEWORK,
642+
"hookImplementationsMap[hook = %s]: invalid value",
643+
NRSAFESTR(ZEND_STRING_VALUE(hook_key)));
644+
return false;
645+
}
646+
647+
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(hook_val), key_num, class_key,
648+
class_val) {
649+
(void)key_num;
650+
if ((NULL == class_key)
651+
|| (0 == nr_php_is_zval_valid_array(class_val))) {
652+
nrl_warning(NRL_FRAMEWORK,
653+
"hookImplementationsMap[class = %s]: invalid value",
654+
NRSAFESTR(ZEND_STRING_VALUE(class_key)));
655+
return false;
656+
}
657+
658+
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(class_val), key_num, method_key,
659+
module_val) {
660+
(void)key_num;
661+
662+
nr_free(hook_str);
663+
nr_free(class_str);
664+
nr_free(method_str);
665+
nr_free(module_str);
666+
nr_free(hookpath);
667+
668+
if ((NULL == method_key)
669+
|| (0 == nr_php_is_zval_valid_string(module_val))) {
670+
nrl_warning(NRL_FRAMEWORK,
671+
"hookImplementationsMap[method = %s]: invalid value",
672+
NRSAFESTR(ZEND_STRING_VALUE(method_key)));
673+
return false;
674+
}
675+
676+
hook_str = nr_strdup(ZEND_STRING_VALUE(hook_key));
677+
class_str = nr_strdup(ZEND_STRING_VALUE(class_key));
678+
method_str = nr_strdup(ZEND_STRING_VALUE(method_key));
679+
module_str = nr_strdup(Z_STRVAL_P(module_val));
680+
681+
if (0
682+
== nr_stricmp(ZEND_STRING_VALUE(class_key),
683+
"Drupal\\Core\\Extension\\ProceduralCall")) {
684+
hookpath = nr_formatf("%s", method_str);
685+
} else {
686+
hookpath = nr_formatf("%s::%s", class_str, method_str);
687+
}
688+
689+
nr_php_wrap_user_function_drupal(hookpath, nr_strlen(hookpath),
690+
module_str, nr_strlen(module_str),
691+
hook_str, nr_strlen(hook_str));
692+
}
693+
ZEND_HASH_FOREACH_END();
694+
}
695+
ZEND_HASH_FOREACH_END();
696+
}
697+
ZEND_HASH_FOREACH_END();
698+
699+
} else {
700+
nrl_warning(NRL_FRAMEWORK,
701+
"hookImplementationsMap property not a valid array");
702+
return false;
703+
}
704+
} else {
705+
nrl_warning(NRL_FRAMEWORK, "NULL hookImplementationsMap object property");
706+
return false;
707+
}
708+
709+
nr_free(hook_str);
710+
nr_free(class_str);
711+
nr_free(method_str);
712+
nr_free(module_str);
713+
nr_free(hookpath);
714+
715+
return true;
716+
}
717+
608718
/*
609719
* Purpose : Wrap the invoke() method of the module handler instance in use.
610720
*/
611721
NR_PHP_WRAPPER(nr_drupal8_module_handler) {
612722
zend_class_entry* ce = NULL;
613723
zval** retval_ptr = NR_GET_RETURN_VALUE_PTR;
724+
bool hook_attribute_instrumentation = false;
614725

615726
NR_UNUSED_SPECIALFN;
616727
(void)wraprec;
@@ -632,20 +743,26 @@ NR_PHP_WRAPPER(nr_drupal8_module_handler) {
632743

633744
ce = Z_OBJCE_P(*retval_ptr);
634745

635-
nr_drupal8_add_method_callback(ce, NR_PSTR("getimplementations"),
636-
nr_drupal8_post_get_implementations TSRMLS_CC);
637-
nr_drupal8_add_method_callback(ce, NR_PSTR("implementshook"),
638-
nr_drupal8_post_implements_hook TSRMLS_CC);
639-
/* Drupal 9.4 introduced a replacement method for getImplentations */
746+
hook_attribute_instrumentation
747+
= nr_drupal_hook_attribute_instrument(*retval_ptr);
748+
749+
if (!hook_attribute_instrumentation) {
750+
nr_drupal8_add_method_callback(
751+
ce, NR_PSTR("getimplementations"),
752+
nr_drupal8_post_get_implementations TSRMLS_CC);
753+
nr_drupal8_add_method_callback(ce, NR_PSTR("implementshook"),
754+
nr_drupal8_post_implements_hook TSRMLS_CC);
755+
/* Drupal 9.4 introduced a replacement method for getImplentations */
640756
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
641757
&& !defined OVERWRITE_ZEND_EXECUTE_DATA
642-
nr_drupal8_add_method_callback_before_after_clean(
643-
ce, NR_PSTR("invokeallwith"), nr_drupal94_invoke_all_with,
644-
nr_drupal94_invoke_all_with_after, nr_drupal94_invoke_all_with_clean);
758+
nr_drupal8_add_method_callback_before_after_clean(
759+
ce, NR_PSTR("invokeallwith"), nr_drupal94_invoke_all_with,
760+
nr_drupal94_invoke_all_with_after, nr_drupal94_invoke_all_with_clean);
645761
#else
646-
nr_drupal8_add_method_callback(ce, NR_PSTR("invokeallwith"),
647-
nr_drupal94_invoke_all_with TSRMLS_CC);
762+
nr_drupal8_add_method_callback(ce, NR_PSTR("invokeallwith"),
763+
nr_drupal94_invoke_all_with TSRMLS_CC);
648764
#endif
765+
}
649766
}
650767
NR_PHP_WRAPPER_END
651768

0 commit comments

Comments
 (0)