diff --git a/agent/Makefile.frag b/agent/Makefile.frag index 1cfe1606c..648fc84b3 100644 --- a/agent/Makefile.frag +++ b/agent/Makefile.frag @@ -107,6 +107,7 @@ TEST_BINARIES = \ tests/test_php_minit \ tests/test_php_stack \ tests/test_php_stacked_segment \ + tests/test_php_txn \ tests/test_php_wrapper \ tests/test_predis \ tests/test_redis \ diff --git a/agent/config.m4 b/agent/config.m4 index a77122c37..ee0859e30 100644 --- a/agent/config.m4 +++ b/agent/config.m4 @@ -230,7 +230,8 @@ if test "$PHP_NEWRELIC" = "yes"; then fw_zend2.c fw_zend.c" LIBRARIES="lib_aws_sdk_php.c lib_monolog.c lib_doctrine2.c lib_guzzle3.c \ lib_guzzle4.c lib_guzzle6.c lib_guzzle_common.c \ - lib_mongodb.c lib_phpunit.c lib_predis.c lib_zend_http.c" + lib_mongodb.c lib_phpunit.c lib_predis.c lib_zend_http.c \ + lib_composer.c" PHP_NEW_EXTENSION(newrelic, $FRAMEWORKS $LIBRARIES $NEWRELIC_AGENT, $ext_shared,, \\$(NEWRELIC_CFLAGS)) PHP_SUBST(NEWRELIC_CFLAGS) diff --git a/agent/fw_drupal.c b/agent/fw_drupal.c index 12e43b5cf..3537f8b42 100644 --- a/agent/fw_drupal.c +++ b/agent/fw_drupal.c @@ -20,6 +20,8 @@ #include "util_memory.h" #include "util_strings.h" +#define PHP_PACKAGE_NAME "drupal/drupal" + /* * Set the Web Transaction (WT) name to "(cached page)" * @@ -879,4 +881,12 @@ void nr_drupal_enable(TSRMLS_D) { nr_php_user_function_add_declared_callback( NR_PSTR("drupal_http_request"), nr_drupal_replace_http_request TSRMLS_CC); #endif + + if (NRINI(vulnerability_management_package_detection_enabled)) { + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_drupal8.c b/agent/fw_drupal8.c index 6593e17a8..541cb8b87 100644 --- a/agent/fw_drupal8.c +++ b/agent/fw_drupal8.c @@ -689,8 +689,6 @@ void nr_drupal_version() { if (NRINI(vulnerability_management_package_detection_enabled)) { nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); } nr_php_zval_free(&zval_version); @@ -762,4 +760,7 @@ void nr_drupal8_enable(TSRMLS_D) { nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_hooks.h b/agent/fw_hooks.h index e78f65cbd..c4500aeb2 100644 --- a/agent/fw_hooks.h +++ b/agent/fw_hooks.h @@ -56,6 +56,7 @@ extern void nr_phpunit_enable(TSRMLS_D); extern void nr_predis_enable(TSRMLS_D); extern void nr_zend_http_enable(TSRMLS_D); extern void nr_monolog_enable(TSRMLS_D); +extern void nr_composer_handle_autoload(const char* filename); /* Vulnerability Management Packages */ extern void nr_drupal_version(void); diff --git a/agent/fw_laminas3.c b/agent/fw_laminas3.c index 604976bf0..a5d27de94 100644 --- a/agent/fw_laminas3.c +++ b/agent/fw_laminas3.c @@ -13,6 +13,8 @@ #include "util_logging.h" #include "util_memory.h" +#define PHP_PACKAGE_NAME "laminas/laminas-mvc" + /* * Laminas is a rebranding of Zend, but the logic remains the same, * it is simply a name change and corresponds directly to Zend 3.x. @@ -163,7 +165,10 @@ void nr_laminas3_enable(TSRMLS_D) { nr_laminas3_name_the_wt TSRMLS_CC); if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "laminas/laminas-mvc", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_laravel.c b/agent/fw_laravel.c index 11718a7e6..bbac65b20 100644 --- a/agent/fw_laravel.c +++ b/agent/fw_laravel.c @@ -963,8 +963,9 @@ NR_PHP_WRAPPER(nr_laravel_application_construct) { // Add php package to transaction nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); if (version) { nrl_debug(NRL_FRAMEWORK, "Laravel version is " NRP_FMT, NRP_PHP(version)); diff --git a/agent/fw_lumen.c b/agent/fw_lumen.c index 239578ae1..2d34551f0 100644 --- a/agent/fw_lumen.c +++ b/agent/fw_lumen.c @@ -11,10 +11,13 @@ #include "php_wrapper.h" #include "php_hash.h" #include "fw_hooks.h" +#include "fw_support.h" #include "util_logging.h" #include "util_memory.h" #include "util_strings.h" +#define PHP_PACKAGE_NAME "laravel/lumen-framework" + /* * Sets the web transaction name. If strip_base == true, * leading class path components will be stripped. @@ -232,7 +235,10 @@ void nr_lumen_enable(TSRMLS_D) { #endif if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "laravel/lumen-framework", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_slim.c b/agent/fw_slim.c index a70323459..facaeecc1 100644 --- a/agent/fw_slim.c +++ b/agent/fw_slim.c @@ -163,8 +163,8 @@ NR_PHP_WRAPPER(nr_slim_application_construct) { nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); nr_free(version); nr_php_scope_release(&this_var); diff --git a/agent/fw_support.c b/agent/fw_support.c index daff2692c..23c9c44c1 100644 --- a/agent/fw_support.c +++ b/agent/fw_support.c @@ -58,23 +58,39 @@ void nr_fw_support_add_logging_supportability_metric(nrtxn_t* txn, void nr_fw_support_add_package_supportability_metric( nrtxn_t* txn, const char* package_name, - const char* package_version) { - if (NULL == txn || NULL == package_name || NULL == package_version) { + const char* package_version, + nr_php_package_t* p) { + if (NULL == txn || NULL == package_name) { return; } char* metname = NULL; char major_version[MAJOR_VERSION_LENGTH] = {0}; + const char* version = package_version; + + // override provided package_version only if: + // - php_package is provided + // - its version is not NULL + // - its version is not PHP_PACKAGE_VERSION_UNKNOWN + if (NULL != p && NULL != p->package_version + && 0 != nr_strcmp(p->package_version, PHP_PACKAGE_VERSION_UNKNOWN)) { + version = p->package_version; + } + + // only generate metric if version is known + if (NULL == version || 0 == nr_strcmp(version, PHP_PACKAGE_VERSION_UNKNOWN)) { + return; + } /* The below for loop checks if the major version of the package is more than * one digit and keeps looping until a '.' is encountered or one of the * conditions is met. */ - for (int i = 0; package_version[i] && i < MAJOR_VERSION_LENGTH - 1; i++) { - if ('.' == package_version[i]) { + for (int i = 0; version[i] && i < MAJOR_VERSION_LENGTH - 1; i++) { + if ('.' == version[i]) { break; } - major_version[i] = package_version[i]; + major_version[i] = version[i]; } if (NR_FW_UNSET == NRINI(force_framework)) { diff --git a/agent/fw_support.h b/agent/fw_support.h index 5099a7d35..ad4b02722 100644 --- a/agent/fw_support.h +++ b/agent/fw_support.h @@ -8,6 +8,7 @@ #define FW_SUPPORT_HDR #include "php_user_instrument.h" +#include "nr_php_packages.h" extern void nr_php_framework_add_supportability_metric( const char* framework_name, @@ -44,11 +45,13 @@ extern void nr_fw_support_add_logging_supportability_metric( * Params : 1. Transaction object * 2. Package name * 3. Package version + * 4. PHP package reported for vulnerability management * */ extern void nr_fw_support_add_package_supportability_metric( nrtxn_t* txn, const char* package_name, - const char* package_version); + const char* package_version, + nr_php_package_t* p); #endif /* FW_SUPPORT_HDR */ diff --git a/agent/fw_symfony4.c b/agent/fw_symfony4.c index 6e1c9982d..8592186ac 100644 --- a/agent/fw_symfony4.c +++ b/agent/fw_symfony4.c @@ -10,6 +10,8 @@ #include "fw_support.h" #include "fw_symfony_common.h" +#define PHP_PACKAGE_NAME "symfony/http-kernel" + NR_PHP_WRAPPER(nr_symfony4_exception) { int priority = nr_php_error_get_priority(E_ERROR); zval* event = NULL; @@ -277,7 +279,10 @@ void nr_symfony4_enable(TSRMLS_D) { #endif if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "symfony/http-kernel", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_wordpress.c b/agent/fw_wordpress.c index 55a0be5f0..050750f6a 100644 --- a/agent/fw_wordpress.c +++ b/agent/fw_wordpress.c @@ -804,8 +804,7 @@ void nr_wordpress_version() { "})();"; zval retval; - int result - = zend_eval_string(func_string, &retval, "Get Wordpress Version"); + int result = zend_eval_string(func_string, &retval, "Get Wordpress Version"); // Add php package to transaction if (SUCCESS == result) { if (nr_php_is_zval_valid_string(&retval)) { @@ -813,8 +812,9 @@ void nr_wordpress_version() { if (NRINI(vulnerability_management_package_detection_enabled)) { nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); } zval_dtor(&retval); } diff --git a/agent/fw_yii.c b/agent/fw_yii.c index 74aa19335..0b1af7c96 100644 --- a/agent/fw_yii.c +++ b/agent/fw_yii.c @@ -14,6 +14,7 @@ #include "util_memory.h" #include "util_strings.h" +#define PHP_PACKAGE_NAME "yiisoft/yii2" /* * Yii1: Set the web transaction name from the controllerId + actionId combo. * @@ -221,4 +222,12 @@ void nr_yii2_enable(TSRMLS_D) { nr_php_wrap_user_function(NR_PSTR("yii\\base\\ErrorHandler::logException"), nr_yii2_error_handler_wrapper TSRMLS_CC); #endif + + if (NRINI(vulnerability_management_package_detection_enabled)) { + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/lib_aws_sdk_php.c b/agent/lib_aws_sdk_php.c index cff08dbfd..ad956ac1e 100644 --- a/agent/lib_aws_sdk_php.c +++ b/agent/lib_aws_sdk_php.c @@ -69,8 +69,10 @@ void nr_lib_aws_sdk_php_handle_version() { /* Add php package to transaction */ nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); + nr_php_zval_free(&zval_version); } diff --git a/agent/lib_composer.c b/agent/lib_composer.c new file mode 100644 index 000000000..f6596639a --- /dev/null +++ b/agent/lib_composer.c @@ -0,0 +1,272 @@ +/* + * Copyright 2022 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "php_agent.h" +#include "fw_hooks.h" +#include "fw_support.h" +#include "nr_txn.h" +#include "util_logging.h" +#include "util_memory.h" +#include "util_syscalls.h" + +static bool nr_execute_handle_autoload_composer_is_initialized() { + zend_class_entry* zce = NULL; + + if (NULL == (zce = nr_php_find_class("composer\\installedversions"))) { + nrl_verbosedebug(NRL_INSTRUMENT, + "Composer\\InstalledVersions class not found"); + return false; + }; + + // the class is found - there's hope! + if (NULL == nr_php_find_class_method(zce, "getallrawdata") + || NULL == nr_php_find_class_method(zce, "getrootpackage")) { + nrl_verbosedebug( + NRL_INSTRUMENT, + "Composer\\InstalledVersions class found, but methods not found"); + return false; + } + + return true; +} + +static int nr_execute_handle_autoload_composer_init(const char* vendor_path) { + char* code = NULL; + zval retval; + int result = FAILURE; + + if (nr_execute_handle_autoload_composer_is_initialized()) { + nrl_verbosedebug(NRL_INSTRUMENT, "%s: already initialized", __func__); + return NR_SUCCESS; + } + + code = nr_formatf("include_once '%s/composer/InstalledVersions.php';", + vendor_path); + + result = zend_eval_string(code, &retval, "newrelic\\init_composer_api"); + if (result != SUCCESS) { + nrl_verbosedebug(NRL_INSTRUMENT, + "%s: zend_eval_string(%s) failed, result=%d", __func__, + code, result); + nr_free(code); + return NR_FAILURE; + } + + zval_dtor(&retval); + nr_free(code); + + // Make sure runtime API is available after loading + // Composer\\InstalledVersions class: + if (!nr_execute_handle_autoload_composer_is_initialized()) { + nrl_verbosedebug(NRL_INSTRUMENT, + "%s: unable to initialize Composer runtime API", __func__); + return NR_FAILURE; + } + + return NR_SUCCESS; +} + +static void nr_execute_handle_autoload_composer_get_packages_information( + const char* vendor_path) { + zval retval; // This is used as a return value for zend_eval_string. + // It will only be set if the result of the eval is SUCCESS. + int result = FAILURE; + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(!NRINI(vulnerability_management_package_detection_enabled))) { + // do nothing when collecting package information for vulnerability + // management is disabled + return; + } + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(!NRINI(vulnerability_management_composer_api_enabled))) { + // do nothing when use of composer to collect package info is disabled + return; + } + + // clang-format off + char* getallrawdata + = "" + "(function() {" + " try {" + " $root_package = \\Composer\\InstalledVersions::getRootPackage();" + " $packages = array();" + " foreach (\\Composer\\InstalledVersions::getAllRawData() as $installed) { " + " foreach ($installed['versions'] as $packageName => $packageData) {" + " if (!is_string($packageName)) {" + " continue;" + " }" + " if (is_array($root_package) && array_key_exists('name', $root_package) && $packageName == $root_package['name']) {" + " continue;" + " }" + " if (!array_key_exists('pretty_version', $packageData)) {" + " continue;" + " }" + " $pretty_version = $packageData['pretty_version'];" + " if (is_string($pretty_version)) {" + " $packages[$packageName] = ltrim($pretty_version, 'v');" + " }" + " }" + " }" + " return $packages;" + " } catch (Throwable $e) {" + " return NULL;" + " }" + "})();"; + // clang-format on + + if (NR_SUCCESS != nr_execute_handle_autoload_composer_init(vendor_path)) { + nrl_debug(NRL_INSTRUMENT, + "%s - unable to initialize Composer runtime API - package info " + "unavailable", + __func__); + return; + } + + nrl_verbosedebug(NRL_INSTRUMENT, "%s - Composer runtime API available", + __func__); + + result + = zend_eval_string(getallrawdata, &retval, "composer_getallrawdata.php"); + if (SUCCESS != result) { + nrl_verbosedebug(NRL_INSTRUMENT, "%s - composer_getallrawdata.php failed", + __func__); + return; + } + if (IS_ARRAY == Z_TYPE(retval)) { + zend_string* package_name = NULL; + zval* package_version = NULL; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(retval), package_name, + package_version) { + if (NULL == package_name || NULL == package_version) { + continue; + } + if (nr_php_is_zval_non_empty_string(package_version)) { + nrl_verbosedebug(NRL_INSTRUMENT, "package %s, version %s", + NRSAFESTR(ZSTR_VAL(package_name)), + NRSAFESTR(Z_STRVAL_P(package_version))); + nr_txn_add_php_package_from_source(NRPRG(txn), ZSTR_VAL(package_name), + Z_STRVAL_P(package_version), + NR_PHP_PACKAGE_SOURCE_COMPOSER); + } + } + ZEND_HASH_FOREACH_END(); + } else { + char strbuf[80]; + nr_format_zval_for_debug(&retval, strbuf, 0, sizeof(strbuf) - 1, 0); + nrl_verbosedebug(NRL_INSTRUMENT, + "%s - installed packages is: " NRP_FMT ", not an array", + __func__, NRP_ARGSTR(strbuf)); + } + zval_dtor(&retval); +} + +static char* nr_execute_handle_autoload_composer_get_vendor_path( + const char* filename) { + char* vendor_path = NULL; // result of dirname(filename) + char* cp = NULL; + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(NULL == filename)) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s - filename is NULL", __func__); + return NULL; + } + + // vendor_path = dirname(filename): + // 1. copy filename to vendor_path + vendor_path = nr_strdup(filename); + // 2. // find last occurence of '/' in vendor_path + cp = nr_strrchr(vendor_path, '/'); + // 3. replace '/' with '\0' to get the directory path + if (NULL != cp) { + *cp = '\0'; + } else { + nrl_verbosedebug(NRL_FRAMEWORK, "%s - no '/' in filename '%s'", __func__, + filename); + } + + return vendor_path; +} + +static bool nr_execute_handle_autoload_composer_file_exists( + const char* vendor_path, + const char* filename) { + char* composer_magic_file = NULL; // vendor_path + filename + bool file_exists = false; + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(NULL == vendor_path)) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s - vendor_path is NULL", __func__); + return false; + } + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(NULL == filename)) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s - filename is NULL", __func__); + return false; + } + + composer_magic_file = nr_formatf("%s/%s", vendor_path, filename); + if (0 == nr_access(composer_magic_file, F_OK | R_OK)) { + file_exists = true; + } + nr_free(composer_magic_file); + return file_exists; +} + +void nr_composer_handle_autoload(const char* filename) { +// Composer signature file" +#define COMPOSER_MAGIC_FILE_1 "composer/autoload_real.php" +#define COMPOSER_MAGIC_FILE_1_LEN (sizeof(COMPOSER_MAGIC_FILE_1) - 1) +// Composer runtime API files: +#define COMPOSER_MAGIC_FILE_2 "composer/InstalledVersions.php" +#define COMPOSER_MAGIC_FILE_2_LEN (sizeof(COMPOSER_MAGIC_FILE_2) - 1) +#define COMPOSER_MAGIC_FILE_3 "composer/installed.php" +#define COMPOSER_MAGIC_FILE_3_LEN (sizeof(COMPOSER_MAGIC_FILE_3) - 1) + char* vendor_path = NULL; // result of dirname(filename) + + // nrunlikely because this should alredy be ensured by the caller + if (nrunlikely(NULL == filename)) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s - filename is NULL", __func__); + return; + } + + vendor_path = nr_execute_handle_autoload_composer_get_vendor_path(filename); + if (NULL == vendor_path) { + nrl_verbosedebug(NRL_FRAMEWORK, "unable to get vendor path from '%s'", + filename); + return; + } + + if (!nr_execute_handle_autoload_composer_file_exists(vendor_path, + COMPOSER_MAGIC_FILE_1)) { + nrl_verbosedebug(NRL_FRAMEWORK, "'%s' not found in '%s'", + COMPOSER_MAGIC_FILE_1, vendor_path); + goto leave; + } + + if (!nr_execute_handle_autoload_composer_file_exists(vendor_path, + COMPOSER_MAGIC_FILE_2)) { + nrl_verbosedebug(NRL_FRAMEWORK, "'%s' not found in '%s'", + COMPOSER_MAGIC_FILE_2, vendor_path); + goto leave; + } + + if (!nr_execute_handle_autoload_composer_file_exists(vendor_path, + COMPOSER_MAGIC_FILE_3)) { + nrl_verbosedebug(NRL_FRAMEWORK, "'%s' not found in '%s'", + COMPOSER_MAGIC_FILE_3, vendor_path); + goto leave; + } + + nrl_verbosedebug(NRL_FRAMEWORK, "detected composer"); + NRPRG(txn)->composer_info.composer_detected = true; + nr_fw_support_add_library_supportability_metric(NRPRG(txn), "Composer"); + + nr_execute_handle_autoload_composer_get_packages_information(vendor_path); +leave: + nr_free(vendor_path); +} diff --git a/agent/lib_doctrine2.c b/agent/lib_doctrine2.c index e767d253f..8f8b8dfe3 100644 --- a/agent/lib_doctrine2.c +++ b/agent/lib_doctrine2.c @@ -16,6 +16,8 @@ #include "php_call.h" #include "lib_doctrine2.h" +#define PHP_PACKAGE_NAME "doctrine/orm" + /* * This answers the somewhat complicated question of whether we should * instrument DQL, which is dependent on the input query setting as well as SQL @@ -106,7 +108,10 @@ void nr_doctrine2_enable(TSRMLS_D) { #endif /* OAPI */ if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "doctrine/orm", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/lib_guzzle4.c b/agent/lib_guzzle4.c index f3dfc94e9..c52ddffff 100644 --- a/agent/lib_guzzle4.c +++ b/agent/lib_guzzle4.c @@ -33,6 +33,8 @@ #include "util_logging.h" #include "util_memory.h" +#define PHP_PACKAGE_NAME "guzzlehttp/guzzle" + /* * We rely on the const correctness of certain Zend functions that weren't * const correct before 5.3 and/or 5.4: since Guzzle 4 requires 5.4.0 anyway, @@ -520,9 +522,12 @@ void nr_guzzle4_enable(TSRMLS_D) { nr_guzzle_client_construct TSRMLS_CC); if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "guzzlehttp/guzzle", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } void nr_guzzle4_minit(TSRMLS_D) { diff --git a/agent/lib_guzzle6.c b/agent/lib_guzzle6.c index d9003545c..e65a684b7 100644 --- a/agent/lib_guzzle6.c +++ b/agent/lib_guzzle6.c @@ -359,15 +359,25 @@ NR_PHP_WRAPPER_START(nr_guzzle6_client_construct) { } /* - * If we were unable to get the full version before, at least we can extract - * the major version to send to the supportability metric. - * This is relevant to guzzle7+ which no longer supplies full version. - */ + * If we were unable to get the full version before, at least we can extract + * the major version to send to the supportability metric now, as + * this incomplete version will not be stored in a php package record + * and so the supportability metric cannot be created later like for + * most packages. + * + * This is relevant to guzzle7+ which no longer supplies full version. + */ if (NULL == version) { version = nr_php_get_object_constant(this_var, "MAJOR_VERSION"); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + + /* if version is still NULL that is OK this next call will accept + * that value and when supportability metrics are made for + * packages if another method has determined the package version + * (composer api for example) then it will be filled in at that time + */ + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); nr_free(version); (void)wraprec; diff --git a/agent/lib_mongodb.c b/agent/lib_mongodb.c index c21e1e01b..8d129ae9d 100644 --- a/agent/lib_mongodb.c +++ b/agent/lib_mongodb.c @@ -18,6 +18,8 @@ #include "lib_mongodb_private.h" +#define PHP_PACKAGE_NAME "mongodb/mongodb" + static int nr_mongodb_is_server(const zval* obj TSRMLS_DC) { return nr_php_object_instanceof_class(obj, "MongoDB\\Driver\\Server" TSRMLS_CC); @@ -445,7 +447,10 @@ void nr_mongodb_enable() { #endif /* OAPI */ if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "mongodb/mongodb", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/lib_monolog.c b/agent/lib_monolog.c index 667e33583..fcdb1ac06 100644 --- a/agent/lib_monolog.c +++ b/agent/lib_monolog.c @@ -378,8 +378,8 @@ NR_PHP_WRAPPER(nr_monolog_logger_addrecord) { = nr_monolog_get_timestamp(api, argc, NR_EXECUTE_ORIG_ARGS TSRMLS_CC); char version[MAJOR_VERSION_LENGTH]; snprintf(version, sizeof(version), "%d", api); - nr_fw_support_add_package_supportability_metric(NRPRG(txn), - PHP_PACKAGE_NAME, version); + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); } /* Record the log event */ @@ -523,4 +523,7 @@ void nr_monolog_enable(TSRMLS_D) { nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/lib_phpunit.c b/agent/lib_phpunit.c index e41c55b29..4050bf969 100644 --- a/agent/lib_phpunit.c +++ b/agent/lib_phpunit.c @@ -14,6 +14,8 @@ #include "util_logging.h" #include "util_strings.h" +#define PHP_PACKAGE_NAME "phpunit/phpunit" + /* * PHPUnit instrumentation * ======================= @@ -697,7 +699,10 @@ void nr_phpunit_enable(TSRMLS_D) { nr_phpunit_instrument_testresult_adderror TSRMLS_CC); if (NRINI(vulnerability_management_package_detection_enabled)) { - nr_txn_add_php_package(NRPRG(txn), "phpunit/phpunit", + nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, PHP_PACKAGE_VERSION_UNKNOWN); } + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/lib_predis.c b/agent/lib_predis.c index b299c5595..607e11ed2 100644 --- a/agent/lib_predis.c +++ b/agent/lib_predis.c @@ -654,8 +654,10 @@ NR_PHP_WRAPPER(nr_predis_client_construct) { // Add php package to transaction nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version); } - nr_fw_support_add_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, - version); + + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + version); + nr_free(version); /* diff --git a/agent/php_execute.c b/agent/php_execute.c index 3ecb33100..83ff4d5a9 100644 --- a/agent/php_execute.c +++ b/agent/php_execute.c @@ -411,7 +411,7 @@ static const nr_framework_table_t all_frameworks[] = { NR_PSTR("symfony/bundle/frameworkbundle/frameworkbundle.php"), 0, nr_symfony2_enable, NR_FW_SYMFONY2}, /* also Symfony 3 */ {"Symfony4", "symfony4", NR_PSTR("http-kernel/httpkernel.php"), 0, - nr_symfony4_enable, NR_FW_SYMFONY4}, /* also Symfony 5 */ + nr_symfony4_enable, NR_FW_SYMFONY4}, /* also Symfony 5/6/7 */ {"WordPress", "wordpress", NR_PSTR("wp-config.php"), 0, nr_wordpress_enable, NR_FW_WORDPRESS}, @@ -931,6 +931,40 @@ static void nr_execute_handle_library(const char* filename, } } +static void nr_execute_handle_autoload(const char* filename, + const size_t filename_len) { +#define AUTOLOAD_MAGIC_FILE "vendor/autoload.php" +#define AUTOLOAD_MAGIC_FILE_LEN (sizeof(AUTOLOAD_MAGIC_FILE) - 1) + + if (!NRINI(vulnerability_management_package_detection_enabled)) { + // do nothing when vulnerability management package detection is disabled + return; + } + + if (!NRINI(vulnerability_management_composer_api_enabled)) { + // do nothing when use of composer to collect package info is disabled + return; + } + + if (NRPRG(txn)->composer_info.autoload_detected) { + // autoload already handled + return; + } + + if (!nr_striendswith(STR_AND_LEN(filename), AUTOLOAD_MAGIC_FILE, + AUTOLOAD_MAGIC_FILE_LEN)) { + // not an autoload file + return; + } + + nrl_debug(NRL_FRAMEWORK, "detected autoload with %s, which ends with %s", + filename, AUTOLOAD_MAGIC_FILE); + NRPRG(txn)->composer_info.autoload_detected = true; + nr_fw_support_add_library_supportability_metric(NRPRG(txn), "Autoloader"); + + nr_composer_handle_autoload(filename); +} + static void nr_execute_handle_logging_framework(const char* filename, const size_t filename_len TSRMLS_DC) { @@ -999,6 +1033,7 @@ static void nr_php_user_instrumentation_from_file(const char* filename, nr_execute_handle_framework(all_frameworks, num_all_frameworks, filename, filename_len TSRMLS_CC); nr_execute_handle_library(filename, filename_len TSRMLS_CC); + nr_execute_handle_autoload(filename, filename_len); nr_execute_handle_logging_framework(filename, filename_len TSRMLS_CC); if (NRINI(vulnerability_management_package_detection_enabled)) { nr_execute_handle_package(filename); diff --git a/agent/php_newrelic.h b/agent/php_newrelic.h index 04ebd1ad2..1860b5167 100644 --- a/agent/php_newrelic.h +++ b/agent/php_newrelic.h @@ -593,6 +593,8 @@ nrinibool_t nrinibool_t vulnerability_management_package_detection_enabled; /* newrelic.vulnerability_management.package_detection.enabled */ +nrinibool_t + vulnerability_management_composer_api_enabled; /* newrelic.vulnerability_management.composer_api.enabled */ #if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO /* diff --git a/agent/php_nrini.c b/agent/php_nrini.c index 6fdd898d3..6c21d1bdf 100644 --- a/agent/php_nrini.c +++ b/agent/php_nrini.c @@ -3091,6 +3091,15 @@ STD_PHP_INI_ENTRY_EX("newrelic.vulnerability_management.package_detection.enable newrelic_globals, nr_enabled_disabled_dh) +STD_PHP_INI_ENTRY_EX("newrelic.vulnerability_management.composer_api.enabled", + "0", + NR_PHP_REQUEST, + nr_boolean_mh, + vulnerability_management_composer_api_enabled, + zend_newrelic_globals, + newrelic_globals, + nr_enabled_disabled_dh) + PHP_INI_END() /* } */ void nr_php_register_ini_entries(int module_number TSRMLS_DC) { diff --git a/agent/php_txn.c b/agent/php_txn.c index 785007b41..b5b57975c 100644 --- a/agent/php_txn.c +++ b/agent/php_txn.c @@ -19,10 +19,12 @@ #include "nr_agent.h" #include "nr_commands.h" #include "nr_header.h" +#include "nr_php_packages.h" #include "nr_rum.h" #include "nr_segment_children.h" #include "nr_txn.h" #include "nr_version.h" +#include "fw_support.h" #include "util_labels.h" #include "util_logging.h" #include "util_memory.h" @@ -711,6 +713,50 @@ void nr_php_txn_create_agent_php_version_metrics(nrtxn_t* txn) { nr_php_txn_create_php_version_metric(txn, version); } +void nr_php_txn_php_package_create_major_metric(void* value, + const char* key, + size_t key_len, + void* user_data) { + nrtxn_t* txn = (nrtxn_t*)user_data; + nr_php_package_t* suggested = value; + nr_php_package_t* actual = NULL; + + (void)key; + (void)key_len; + + if (NULL == txn) { + return; + } + + if (NULL == suggested) { + return; + } + + /* see if the actual packages has a version we can use over the + * one provided with the suggested package + */ + actual + = nr_php_packages_get_package(txn->php_packages, suggested->package_name); + + nrl_verbosedebug( + NRL_INSTRUMENT, + "Creating PHP Package Supportability Metric for package " + "'%s', suggested version '%s', actual version '%s'", + NRSAFESTR(suggested->package_name), NRSAFESTR(suggested->package_version), + NRSAFESTR(NULL != actual ? actual->package_version : "NULL")); + nr_fw_support_add_package_supportability_metric( + txn, suggested->package_name, suggested->package_version, actual); +} + +void nr_php_txn_create_packages_major_metrics(nrtxn_t* txn) { + if (NULL == txn) { + return; + } + + nr_php_packages_iterate(txn->php_package_major_version_metrics_suggestions, + nr_php_txn_php_package_create_major_metric, txn); +} + nr_status_t nr_php_txn_begin(const char* appnames, const char* license TSRMLS_DC) { nrtxnopt_t opts; @@ -1165,6 +1211,9 @@ nr_status_t nr_php_txn_end(int ignoretxn, int in_post_deactivate TSRMLS_DC) { /* Agent and PHP version metrics*/ nr_php_txn_create_agent_php_version_metrics(txn); + /* PHP packages major version metrics */ + nr_php_txn_create_packages_major_metrics(txn); + /* Add CPU and memory metrics */ nr_php_resource_usage_sampler_end(TSRMLS_C); diff --git a/agent/php_txn_private.h b/agent/php_txn_private.h index bf49eb107..6788877ad 100644 --- a/agent/php_txn_private.h +++ b/agent/php_txn_private.h @@ -65,3 +65,24 @@ extern void nr_php_txn_create_agent_version_metric(nrtxn_t* txn); */ extern void nr_php_txn_create_php_version_metric(nrtxn_t* txn, const char* version); + +/* + * Purpose : Callback for nr_php_packages_iterate to create major + * version metrics. + * + * Params : 1. PHP suggestion package version + * 2. PHP suggestion package name + * 3. PHP suggestion package name length + * 4. The current transaction (via userdata) + */ +extern void nr_php_txn_php_package_create_major_metric(void* value, + const char* key, + size_t key_len, + void* user_data); + +/* + * Purpose : Create and record metric for a package major versions. + * + * Params : 1. The current transaction. + */ +extern void nr_php_txn_create_packages_major_metrics(nrtxn_t* txn); diff --git a/agent/scripts/newrelic.ini.template b/agent/scripts/newrelic.ini.template index 0e5da6ab3..4ed06a091 100644 --- a/agent/scripts/newrelic.ini.template +++ b/agent/scripts/newrelic.ini.template @@ -1332,3 +1332,12 @@ newrelic.daemon.logfile = "/var/log/newrelic/newrelic-daemon.log" ; for vulnerability management. ; ;newrelic.vulnerability_management.package_detection.enabled = true + +; Setting: newrelic.vulnerability_management.composer_api.enabled +; Type : boolean +; Scope : per-directory +; Default: false +; Info : Toggles whether the agent should try using Composer's runtime API +; to gather package information for vulnerability management. +; +;newrelic.vulnerability_management.composer_api.enabled = false diff --git a/agent/tests/test_fw_support.c b/agent/tests/test_fw_support.c index c8b8e021d..980dc02aa 100644 --- a/agent/tests/test_fw_support.c +++ b/agent/tests/test_fw_support.c @@ -11,7 +11,12 @@ tlib_parallel_info_t parallel_info = {.suggested_nthreads = -1, .state_size = 0}; -static void test_fw_supportability_metrics(void) { +// When package detection for vulnerability management is disabled, +// txn->php_packages is not populated and package version cannot +// be obtained from php_package. This test is to ensure that +// the package supportability metric is created in case php_package +// is not available and that fallback version is used. +static void test_fw_supportability_metrics_with_vm_disabled(void) { #define LIBRARY_NAME "php-package" #define LIBRARY_MAJOR_VERSION "7" #define LIBRARY_MAJOR_VERSION_2 "10" @@ -22,9 +27,11 @@ static void test_fw_supportability_metrics(void) { #define LIBRARY_MAJOR_VERSION_7 "0.4.5" #define LIBRARY_METRIC "Supportability/library/" LIBRARY_NAME "/detected" #define LOGGING_LIBRARY_METRIC "Supportability/Logging/PHP/" LIBRARY_NAME -#define PACKAGE_METRIC "Supportability/PHP/package/" LIBRARY_NAME +#define PACKAGE_METRIC_PREFIX "Supportability/PHP/package/" +#define PACKAGE_METRIC PACKAGE_METRIC_PREFIX LIBRARY_NAME nrtxn_t t; nrtxn_t* txn = &t; + nr_php_package_t* php_package = NULL; txn->unscoped_metrics = nrm_table_create(10); /* NULL tests - don't blow up */ @@ -44,15 +51,18 @@ static void test_fw_supportability_metrics(void) { tlib_pass_if_int_equal("NULL logging library metric not created", 0, nrm_table_size(txn->unscoped_metrics)); - nr_fw_support_add_package_supportability_metric(NULL, LIBRARY_NAME, LIBRARY_MAJOR_VERSION); + nr_fw_support_add_package_supportability_metric( + NULL, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, php_package); tlib_pass_if_int_equal("package metric not created in NULL metrics", 0, nrm_table_size(txn->unscoped_metrics)); - nr_fw_support_add_package_supportability_metric(txn, NULL, LIBRARY_MAJOR_VERSION); + nr_fw_support_add_package_supportability_metric( + txn, NULL, LIBRARY_MAJOR_VERSION, php_package); tlib_pass_if_int_equal("NULL package name, metric not created", 0, nrm_table_size(txn->unscoped_metrics)); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, NULL); + nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, NULL, + php_package); tlib_pass_if_int_equal("NULL major version, metric not created", 0, nrm_table_size(txn->unscoped_metrics)); @@ -71,51 +81,51 @@ static void test_fw_supportability_metrics(void) { "happy path: logging library metric created", nrm_find(txn->unscoped_metrics, LOGGING_LIBRARY_METRIC "/disabled")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, php_package); tlib_pass_if_not_null("happy path test 1: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_2); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_2, php_package); tlib_pass_if_not_null("happy path test 2: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION_2 "/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_3); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_3, php_package); tlib_pass_if_not_null("happy path test 3: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION_3 "/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_4); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_4, php_package); tlib_pass_if_not_null( "happy path test 4: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/1/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_5); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_5, php_package); tlib_pass_if_not_null( "happy path test 5: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/12/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_6); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_6, php_package); tlib_pass_if_not_null( "happy path test 6: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/123/detected")); - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION_7); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION_7, php_package); tlib_pass_if_not_null( "happy path test 7: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/0/detected")); NRINI(force_framework) = true; - nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, - LIBRARY_MAJOR_VERSION); + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, php_package); tlib_pass_if_not_null( "happy path test 8: package metric created", nrm_find(txn->unscoped_metrics, PACKAGE_METRIC "/7/forced")); @@ -123,6 +133,88 @@ static void test_fw_supportability_metrics(void) { nrm_table_destroy(&txn->unscoped_metrics); } +// When package detection for vulnerability management is enabled, +// txn->php_packages is populated and package version can be obtained +// from php_package stored in txn->php_packages. This test is to ensure +// that the package supportability metric is created in case php_package +// is available and that package version from php_package is used. +static void test_fw_supportability_metrics_with_vm_enabled(void) { +#define PHP_PACKAGE_MAJOR_VERSION "8" +#define PHP_PACKAGE_VERSION PHP_PACKAGE_MAJOR_VERSION ".4.0" + nrtxn_t t; + nrtxn_t* txn = &t; + nr_php_package_t php_package + = {.package_name = LIBRARY_NAME, + .package_version = PHP_PACKAGE_VERSION, + .source_priority = NR_PHP_PACKAGE_SOURCE_COMPOSER}; + nr_php_package_t php_package_null_version + = {.package_name = LIBRARY_NAME, + .package_version = NULL, + .source_priority = NR_PHP_PACKAGE_SOURCE_COMPOSER}; + nr_php_package_t php_package_unknown_version + = {.package_name = LIBRARY_NAME, + .package_version = PHP_PACKAGE_VERSION_UNKNOWN, + .source_priority = NR_PHP_PACKAGE_SOURCE_COMPOSER}; + txn->unscoped_metrics = nrm_table_create(10); + + NRINI(force_framework) = false; + nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, NULL, + &php_package_null_version); + tlib_pass_if_null( + "library major version metric not created when version is unknown - " + "version is NULL and package version is NULL", + nrm_get_metric(txn->unscoped_metrics, 0)); + + nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN, + &php_package_null_version); + tlib_pass_if_null( + "library major version metric not created when version is unknown - " + "version is PHP_PACKAGE_VERSION_UNKNOWN and package version is NULL", + nrm_get_metric(txn->unscoped_metrics, 0)); + + nr_fw_support_add_package_supportability_metric(txn, LIBRARY_NAME, NULL, + &php_package_unknown_version); + tlib_pass_if_null( + "library major version metric not created when version is unknown - " + "version is NULL and package version is PHP_PACKAGE_VERSION_UNKNOWN", + nrm_get_metric(txn->unscoped_metrics, 0)); + + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, &php_package); + tlib_pass_if_not_null( + "php package major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" PHP_PACKAGE_MAJOR_VERSION "/detected")); + + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, &php_package_null_version); + tlib_pass_if_not_null( + "library major version is used for 'detected' metric when php package " + "version is NULL", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); + + NRINI(force_framework) = true; + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, &php_package); + tlib_pass_if_not_null( + "php package major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" PHP_PACKAGE_MAJOR_VERSION "/forced")); + + nr_fw_support_add_package_supportability_metric( + txn, LIBRARY_NAME, LIBRARY_MAJOR_VERSION, &php_package_null_version); + tlib_pass_if_not_null( + "library major version is used for 'forced' metric when php package " + "version is NULL", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); + + nrm_table_destroy(&txn->unscoped_metrics); +} + void test_main(void* p NRUNUSED) { - test_fw_supportability_metrics(); + test_fw_supportability_metrics_with_vm_disabled(); + test_fw_supportability_metrics_with_vm_enabled(); } diff --git a/agent/tests/test_lib_aws_sdk_php.c b/agent/tests/test_lib_aws_sdk_php.c index 8ddffce9d..91fa88b26 100644 --- a/agent/tests/test_lib_aws_sdk_php.c +++ b/agent/tests/test_lib_aws_sdk_php.c @@ -80,14 +80,14 @@ static void test_nr_lib_aws_sdk_php_add_supportability_service_metric(void) { static void test_nr_lib_aws_sdk_php_handle_version(void) { #define LIBRARY_NAME "aws/aws-sdk-php" -#define LIBRARY_MAJOR_VERSION "7" -#define LIBRARY_MAJOR_VERSION_2 "10" -#define LIBRARY_MAJOR_VERSION_3 "100" -#define LIBRARY_MAJOR_VERSION_4 "4.23" -#define LIBRARY_MAJOR_VERSION_55 "55.34" -#define LIBRARY_MAJOR_VERSION_6123 "6123.45" -#define LIBRARY_MAJOR_VERSION_0 "0.4.5" -#define PACKAGE_METRIC "Supportability/PHP/package/" LIBRARY_NAME + const char* library_versions[] + = {"7", "10", "100", "4.23", "55.34", "6123.45", "0.4.5"}; + nr_php_package_t* p = NULL; +#define TEST_DESCRIPTION_FMT \ + "nr_lib_aws_sdk_php_handle_version with library_versions[%ld]=%s: package " \ + "major version metric - %s" + char* test_description = NULL; + size_t i = 0; /* * If lib_aws_sdk_php_handle_version function is ever called, we have already @@ -95,73 +95,54 @@ static void test_nr_lib_aws_sdk_php_handle_version(void) { */ /* - * Aws/Sdk exists. Should return aws package metric with + * Aws/Sdk class exists. Should create aws package metric suggestion with * version */ - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null("version test 1: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC - "/" LIBRARY_MAJOR_VERSION "/detected")); - tlib_php_request_end(); + for (i = 0; i < sizeof(library_versions) / sizeof(library_versions[0]); i++) { + tlib_php_request_start(); - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_2); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null("version test 2: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC - "/" LIBRARY_MAJOR_VERSION_2 "/detected")); - tlib_php_request_end(); + declare_aws_sdk_class("Aws", "Sdk", library_versions[i]); + nr_lib_aws_sdk_php_handle_version(); - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_3); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null("version test 3: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC - "/" LIBRARY_MAJOR_VERSION_3 "/detected")); - tlib_php_request_end(); + p = nr_php_packages_get_package( + NRPRG(txn)->php_package_major_version_metrics_suggestions, + LIBRARY_NAME); - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_4); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null( - "version test 4: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC "/4/detected")); - tlib_php_request_end(); + test_description = nr_formatf(TEST_DESCRIPTION_FMT, i, library_versions[i], + "suggestion created"); + tlib_pass_if_not_null(test_description, p); + nr_free(test_description); - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_55); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null( - "version test 5: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC "/55/detected")); - tlib_php_request_end(); + test_description = nr_formatf(TEST_DESCRIPTION_FMT, i, library_versions[i], + "suggested version set"); + tlib_pass_if_str_equal(test_description, library_versions[i], + p->package_version); + nr_free(test_description); - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_6123); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null( - "version test 6: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC "/6123/detected")); - tlib_php_request_end(); - - tlib_php_request_start(); - declare_aws_sdk_class("Aws", "Sdk", LIBRARY_MAJOR_VERSION_0); - nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_not_null( - "version test 7: package metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC "/0/detected")); - tlib_php_request_end(); + tlib_php_request_end(); + } /* - * Aws/Sdk does not exist, should not return package metric if no version - * This case should never happen in real situations. + * Aws/Sdk class does not exist, should create package metric suggestion + * with PHP_PACKAGE_VERSION_UNKNOWN version. This case should never happen + * in real situations. */ tlib_php_request_start(); + nr_lib_aws_sdk_php_handle_version(); - tlib_pass_if_null("aws library metric created", - nrm_find(NRPRG(txn)->unscoped_metrics, PACKAGE_METRIC)); + + p = nr_php_packages_get_package( + NRPRG(txn)->php_package_major_version_metrics_suggestions, LIBRARY_NAME); + + tlib_pass_if_not_null( + "nr_lib_aws_sdk_php_handle_version when Aws\\Sdk class is not defined - " + "suggestion created", + p); + tlib_pass_if_str_equal( + "nr_lib_aws_sdk_php_handle_version when Aws\\Sdk class is not defined - " + "suggested version set to PHP_PACKAGE_VERSION_UNKNOWN", + PHP_PACKAGE_VERSION_UNKNOWN, p->package_version); + tlib_php_request_end(); } diff --git a/agent/tests/test_php_txn.c b/agent/tests/test_php_txn.c new file mode 100644 index 000000000..d0665bb26 --- /dev/null +++ b/agent/tests/test_php_txn.c @@ -0,0 +1,268 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "tlib_php.h" + +#include "php_agent.h" +#include "php_txn_private.h" + +#define LIBRARY_NAME "vendor_name/package_name" +#define LIBRARY_VERSION "1.2.3" +#define DEVEL_LIBRARY_VERSION "1.2.x-dev" +#define LIBRARY_MAJOR_VERSION "1" +#define COMPOSER_PACKAGE_VERSION "2.1.3" +#define COMPOSER_MAJOR_VERSION "2" +#define PACKAGE_METRIC_PREFIX "Supportability/PHP/package/" +#define PACKAGE_METRIC PACKAGE_METRIC_PREFIX LIBRARY_NAME + +tlib_parallel_info_t parallel_info = {.suggested_nthreads = 1, .state_size = 0}; + +nr_php_package_t php_package + = {.package_name = LIBRARY_NAME, + .package_version = LIBRARY_VERSION, + .source_priority = NR_PHP_PACKAGE_SOURCE_COMPOSER}; + +static void test_nr_php_txn_php_package_create_major_metric() { + nrtxn_t t; + nrtxn_t* txn = &t; + + txn->unscoped_metrics = nrm_table_create(10); + txn->php_packages = nr_php_packages_create(); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + tlib_php_request_start(); + + /* need to call callback with invalid values to make sure it doesnt crash + * code depends on txn and txn->php_packages existing so these are created + * above with the package suggestions data structure included for good measure + */ + + /* this tests these params in callback: + * suggested = NULL + * actual = NULL + * key = NULL + * txn = NULL + */ + nr_php_txn_php_package_create_major_metric(NULL, NULL, 0, NULL); + tlib_pass_if_int_equal("NULL txn, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* this tests these params in callback: + * suggested = NULL + * actual = NULL + * key != NULL + * txn != NULL + */ + nr_php_txn_php_package_create_major_metric(NULL, LIBRARY_NAME, + strlen(LIBRARY_NAME), (void*)txn); + tlib_pass_if_int_equal("NULL value, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* the key is not actually used by the callback - just the package name + * in the suggested package so this casee will still create a metric + */ + /* this tests these params in callback: + * suggested != NULL + * actual = NULL + * key = NULL + * txn = != NULL + */ + nr_php_txn_php_package_create_major_metric(&php_package, NULL, 0, (void*)txn); + tlib_pass_if_int_equal("NULL key, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + + /* cleanup */ + nr_php_packages_destroy(&txn->php_packages); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + nrm_table_destroy(&txn->unscoped_metrics); + + tlib_php_request_end(); +} + +static void test_nr_php_txn_create_packages_major_metrics() { + nrtxn_t t; + nrtxn_t* txn = &t; + + txn->unscoped_metrics = nrm_table_create(10); + txn->php_packages = nr_php_packages_create(); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + tlib_php_request_start(); + + /* invalid txn should not crash */ + nr_php_txn_create_packages_major_metrics(NULL); + tlib_pass_if_int_equal("NULL txn, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* test with valid txn no package suggestions */ + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("valid txn with no suggestions, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* + * Tests: + * 1. suggestion with NULL version, no packages + * 2. suggestion with PHP_PACKAGE_VERSION_UNKNOWN version, no packages + * 3. suggestion with known version, no packages + * 4. package with known version and suggestion with known version + * 5. package with known version and suggestion with unknown version + * 6. package with unknown version and suggestion with known version + * 7. package with unknown version and suggestion with unknown version + * 8. test that causes "actual" to be NULL in callback + * 9. package with known "dev" version with and suggestion with unknown version + */ + + /* 1. suggestion with NULL version, no packages */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, NULL); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with NULL version, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* 2. suggestion with PHP_PACKAGE_VERSION_UNKNOWN version, no packages + * also + * 8. test that causes "actual" to be NULL in callback + */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal( + "suggestion with PHP_PACKAGE_VERSION_UNKNOWN version, metric not created", + 0, nrm_table_size(txn->unscoped_metrics)); + + /* 3. suggestion with known version, no packages + * also + * 8. test that causes "actual" to be NULL in callback + */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + LIBRARY_VERSION); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with valid version, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + tlib_pass_if_not_null( + "php package major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); + + /* reset metrics */ + nrm_table_destroy(&txn->unscoped_metrics); + txn->unscoped_metrics = nrm_table_create(10); + + /* 4. package with known version and suggestion with known version + * + * add a package with a "better" version determined from composer api + * and use existing suggestion which has a different version + */ + nr_txn_add_php_package_from_source(txn, LIBRARY_NAME, + COMPOSER_PACKAGE_VERSION, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with valid version, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + tlib_pass_if_not_null( + "php package major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" COMPOSER_MAJOR_VERSION "/detected")); + + /* reset suggestions, leave package with known version in place */ + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + /* reset metrics */ + nrm_table_destroy(&txn->unscoped_metrics); + txn->unscoped_metrics = nrm_table_create(10); + + /* 5. package with known version and suggestion with unknown version + * + * add a suggestion with no version and test metric uses package version + */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with valid version, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + tlib_pass_if_not_null( + "php package major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" COMPOSER_MAJOR_VERSION "/detected")); + + /* reset everything */ + nrm_table_destroy(&txn->unscoped_metrics); + txn->unscoped_metrics = nrm_table_create(10); + nr_php_packages_destroy(&txn->php_packages); + txn->php_packages = nr_php_packages_create(); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + /* 6. package with unknown version and suggestion with known version */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + LIBRARY_VERSION); + nr_txn_add_php_package_from_source(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with valid version, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + tlib_pass_if_not_null( + "php package suggestion major version is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); + + /* reset everything */ + nrm_table_destroy(&txn->unscoped_metrics); + txn->unscoped_metrics = nrm_table_create(10); + nr_php_packages_destroy(&txn->php_packages); + txn->php_packages = nr_php_packages_create(); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + /* 7. package with unknown version and suggestion with unknown version */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + nr_txn_add_php_package_from_source(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal( + "suggestion and package w/o version, metric not created", 0, + nrm_table_size(txn->unscoped_metrics)); + + /* reset everything */ + nrm_table_destroy(&txn->unscoped_metrics); + txn->unscoped_metrics = nrm_table_create(10); + nr_php_packages_destroy(&txn->php_packages); + txn->php_packages = nr_php_packages_create(); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + txn->php_package_major_version_metrics_suggestions = nr_php_packages_create(); + + /* 9. package with known "dev" version with and suggestion with unknown version */ + nr_txn_suggest_package_supportability_metric(txn, LIBRARY_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); + nr_txn_add_php_package_from_source(txn, LIBRARY_NAME, + DEVEL_LIBRARY_VERSION, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_php_txn_create_packages_major_metrics(txn); + tlib_pass_if_int_equal("suggestion with valid 'dev' version, metric created", 1, + nrm_table_size(txn->unscoped_metrics)); + tlib_pass_if_not_null( + "php package suggestion major version with 'dev' is used for 'detected' metric", + nrm_find(txn->unscoped_metrics, + PACKAGE_METRIC "/" LIBRARY_MAJOR_VERSION "/detected")); + + + /* cleanup */ + nr_php_packages_destroy(&txn->php_packages); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); + nrm_table_destroy(&txn->unscoped_metrics); + + tlib_php_request_end(); +} + + +void test_main(void* p NRUNUSED) { + tlib_php_engine_create(""); + test_nr_php_txn_php_package_create_major_metric(); + test_nr_php_txn_create_packages_major_metrics(); + tlib_php_engine_destroy(); +} diff --git a/axiom/nr_php_packages.c b/axiom/nr_php_packages.c index 9c1f97ef8..b8a034086 100644 --- a/axiom/nr_php_packages.c +++ b/axiom/nr_php_packages.c @@ -23,7 +23,23 @@ typedef struct { bool package_added; } nr_php_package_json_builder_t; -nr_php_package_t* nr_php_package_create(char* name, char* version) { +static inline const char* nr_php_package_source_priority_to_string(const nr_php_package_source_priority_t source_priority) { + switch (source_priority) { + case NR_PHP_PACKAGE_SOURCE_SUGGESTION: + return "suggestion"; + case NR_PHP_PACKAGE_SOURCE_LEGACY: + return "legacy"; + case NR_PHP_PACKAGE_SOURCE_COMPOSER: + return "composer"; + default: + return "unknown"; + } +} + +nr_php_package_t* nr_php_package_create_with_source( + const char* name, + const char* version, + const nr_php_package_source_priority_t source_priority) { nr_php_package_t* p = NULL; if (NULL == name) { @@ -43,12 +59,17 @@ nr_php_package_t* nr_php_package_create(char* name, char* version) { PHP_PACKAGE_VERSION_UNKNOWN); // if null, version is set to an empty // string with a space according to spec } + p->source_priority = source_priority; - nrl_verbosedebug(NRL_INSTRUMENT, "Creating PHP Package '%s', version '%s'", - p->package_name, p->package_version); + nrl_verbosedebug(NRL_INSTRUMENT, "Creating PHP Package '%s', version '%s', source %s", + p->package_name, p->package_version, nr_php_package_source_priority_to_string(source_priority)); return p; } +nr_php_package_t* nr_php_package_create(const char* name, const char* version) { + return nr_php_package_create_with_source(name, version, NR_PHP_PACKAGE_SOURCE_LEGACY); +} + void nr_php_package_destroy(nr_php_package_t* p) { if (NULL != p) { nr_free(p->package_name); @@ -72,14 +93,15 @@ nr_php_packages_t* nr_php_packages_create() { return h; } -void nr_php_packages_add_package(nr_php_packages_t* h, nr_php_package_t* p) { +nr_php_package_t* nr_php_packages_add_package(nr_php_packages_t* h, + nr_php_package_t* p) { nr_php_package_t* package; if (NULL == h) { - return; + return NULL; } if (NULL == p || NULL == p->package_name || NULL == p->package_version) { - return; + return NULL; } // If package with the same key already exists, we will check if the value is @@ -87,15 +109,26 @@ void nr_php_packages_add_package(nr_php_packages_t* h, nr_php_package_t* p) { package = (nr_php_package_t*)nr_hashmap_get(h->data, p->package_name, nr_strlen(p->package_name)); if (NULL != package) { - if (0 != nr_strcmp(package->package_version, p->package_version)) { + if (package->source_priority <= p->source_priority && 0 != nr_strcmp(package->package_version, p->package_version)) { nr_free(package->package_version); package->package_version = nr_strdup(p->package_version); } nr_php_package_destroy(p); - return; + return package; } nr_hashmap_set(h->data, p->package_name, nr_strlen(p->package_name), p); + return p; +} + +void nr_php_packages_iterate(nr_php_packages_t* packages, + nr_php_packages_iter_t callback, + void* userdata) { + if (NULL == packages || NULL == callback) { + return; + } + + nr_hashmap_apply(packages->data, (nr_hashmap_apply_func_t)callback, userdata); } char* nr_php_package_to_json(nr_php_package_t* package) { diff --git a/axiom/nr_php_packages.h b/axiom/nr_php_packages.h index 118a63f79..f4945c43e 100644 --- a/axiom/nr_php_packages.h +++ b/axiom/nr_php_packages.h @@ -10,32 +10,65 @@ #include "util_random.h" #include "util_vector.h" #include "util_hashmap.h" +#include "util_strings.h" #define PHP_PACKAGE_VERSION_UNKNOWN " " +typedef enum { + NR_PHP_PACKAGE_SOURCE_SUGGESTION, + NR_PHP_PACKAGE_SOURCE_LEGACY, + NR_PHP_PACKAGE_SOURCE_COMPOSER +} nr_php_package_source_priority_t; + typedef struct _nr_php_package_t { char* package_name; char* package_version; + nr_php_package_source_priority_t source_priority; } nr_php_package_t; typedef struct _nr_php_packages_t { nr_hashmap_t* data; } nr_php_packages_t; +typedef void(nr_php_packages_iter_t)(void* value, + const char* name, + size_t name_len, + void* user_data); + /* - * Purpose : Create a new php package. If the name is null, then no package will + * Purpose : Create a new php package with desired source priority. If the name is null, then no package will * be created. If the version is null (version = NULL), then * the package will still be created and the version will be set to an * empty string with a space. * * Params : 1. Package name * 2. Package version + * 3. Package source priority (legacy or composer) * * Returns : A php package that has a name and version. If * nr_php_packages_add_package() is not called, then it must be freed * by nr_php_package_destroy() */ -extern nr_php_package_t* nr_php_package_create(char* name, char* version); +extern nr_php_package_t* nr_php_package_create_with_source( + const char* name, + const char* version, + const nr_php_package_source_priority_t source_priority); + +/* + * Purpose : Create a new php package with legacy source priority. If the name is null, then no package will + * be created. If the version is null (version = NULL), then + * the package will still be created and the version will be set to an + * empty string with a space. + * + * Params : 1. Package name + * 2. Package version + * + * Returns : A php package that has a name and version. If + * nr_php_packages_add_package() is not called, then it must be freed + * by nr_php_package_destroy() + */ +extern nr_php_package_t* nr_php_package_create(const char* name, + const char* version); /* * Purpose : Destroy/free php package @@ -64,10 +97,10 @@ extern nr_php_packages_t* nr_php_packages_create(void); * 2. A pointer to the php package that needs to be added to the * collection * - * Returns : Nothing + * Returns : pointer to added package on success or NULL otherwise. */ -extern void nr_php_packages_add_package(nr_php_packages_t* h, - nr_php_package_t* p); +extern nr_php_package_t* nr_php_packages_add_package(nr_php_packages_t* h, + nr_php_package_t* p); /* * Purpose : Destroy/free the collection @@ -118,6 +151,40 @@ static inline int nr_php_packages_has_package(nr_php_packages_t* h, return 0; } +/* + * Purpose : Retrieve a pointer to php package from the collection + * + * Params : 1. A pointer to nr_php_packages_t + * 2. The name of the package to retrieve + * + * Returns : Returns pointer to php package if the package exists or NULL + */ +static inline nr_php_package_t* nr_php_packages_get_package( + nr_php_packages_t* php_packages, + const char* package_name) { + if (NULL == package_name) { + return NULL; + } + + if (nrlikely(NULL != php_packages && NULL != php_packages->data)) { + return (nr_php_package_t*)nr_hashmap_get(php_packages->data, package_name, nr_strlen(package_name)); + } + return NULL; +} + +/* + * Purpose : Iterate over packages calling callback function + * + * Params : 1. A pointer to nr_php_packages_t + * 2. Callback function (nr_php_packages_iter_t) + * 3. Pointer to user data (can be NULL) + * + * Returns : Nothing + */ +void nr_php_packages_iterate(nr_php_packages_t* packages, + nr_php_packages_iter_t callback, + void* userdata); + /* * Purpose : Converts a package to a json * diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index c3667db81..774c44671 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -542,6 +542,7 @@ nrtxn_t* nr_txn_begin(nrapp_t* app, nt->custom_events = nr_analytics_events_create(app->limits.custom_events); nt->log_events = nr_log_events_create(app->limits.log_events); nt->php_packages = nr_php_packages_create(); + nt->php_package_major_version_metrics_suggestions = nr_php_packages_create(); /* * reset flag for creation of one-time logging metrics @@ -1246,6 +1247,7 @@ void nr_txn_destroy_fields(nrtxn_t* txn) { nr_segment_destroy_tree(txn->segment_root); nr_hashmap_destroy(&txn->parent_stacks); nr_php_packages_destroy(&txn->php_packages); + nr_php_packages_destroy(&txn->php_package_major_version_metrics_suggestions); nr_stack_destroy_fields(&txn->default_parent_stack); nr_slab_destroy(&txn->segment_slab); nr_minmax_heap_set_destructor(txn->segment_heap, NULL, NULL); @@ -3494,9 +3496,35 @@ void nr_txn_record_log_event(nrtxn_t* txn, nr_txn_add_logging_metrics(txn, log_level_name); } -void nr_txn_add_php_package(nrtxn_t* txn, - char* package_name, - char* package_version) { +nr_php_package_t* nr_txn_add_php_package_from_source( + nrtxn_t* txn, + char* package_name, + char* package_version, + const nr_php_package_source_priority_t source) { + nr_php_package_t* p = NULL; + + if (nrunlikely(NULL == txn)) { + return NULL; + } + + if (nr_strempty(package_name)) { + return NULL; + } + + p = nr_php_package_create_with_source(package_name, package_version, source); + return nr_php_packages_add_package(txn->php_packages, p); +} + +nr_php_package_t* nr_txn_add_php_package(nrtxn_t* txn, + char* package_name, + char* package_version) { + return nr_txn_add_php_package_from_source(txn, package_name, package_version, + NR_PHP_PACKAGE_SOURCE_LEGACY); +} + +void nr_txn_suggest_package_supportability_metric(nrtxn_t* txn, + const char* package_name, + const char* package_version) { nr_php_package_t* p = NULL; if (nrunlikely(NULL == txn)) { @@ -3507,6 +3535,11 @@ void nr_txn_add_php_package(nrtxn_t* txn, return; } - p = nr_php_package_create(package_name, package_version); - nr_php_packages_add_package(txn->php_packages, p); + nrl_verbosedebug(NRL_TXN, "Suggesting package %s %s", NRSAFESTR(package_name), + NRSAFESTR(package_version)); + + p = nr_php_package_create_with_source(package_name, package_version, + NR_PHP_PACKAGE_SOURCE_SUGGESTION); + nr_php_packages_add_package( + txn->php_package_major_version_metrics_suggestions, p); } diff --git a/axiom/nr_txn.h b/axiom/nr_txn.h index a6f942f66..8874260ec 100644 --- a/axiom/nr_txn.h +++ b/axiom/nr_txn.h @@ -203,6 +203,11 @@ typedef enum _nr_cpu_usage_t { NR_CPU_USAGE_COUNT = 2 } nr_cpu_usage_t; +typedef struct _nr_composer_info_t { + bool autoload_detected; + bool composer_detected; +} nr_composer_info_t; + /* * Possible transaction types, which go into the type bitfield in the nrtxn_t * struct. @@ -281,6 +286,9 @@ typedef struct _nrtxn_t { custom_events; /* Custom events created through the API. */ nr_log_events_t* log_events; /* Log events pool */ nr_php_packages_t* php_packages; /* Detected php packages */ + nr_php_packages_t* + php_package_major_version_metrics_suggestions; /* Suggested packages for + major metric creation */ nrtime_t user_cpu[NR_CPU_USAGE_COUNT]; /* User CPU usage */ nrtime_t sys_cpu[NR_CPU_USAGE_COUNT]; /* System CPU usage */ @@ -302,6 +310,7 @@ typedef struct _nrtxn_t { nr_distributed_trace_t* distributed_trace; /* distributed tracing metadata for the transaction */ nr_span_queue_t* span_queue; /* span queue when 8T is enabled */ + nr_composer_info_t composer_info; /* * flag to indicate if one time (per transaction) logging metrics @@ -1164,16 +1173,52 @@ static inline nr_segment_t* nr_txn_allocate_segment(nrtxn_t* txn) { } /* - * Purpose : Add php packages to transaction. This function should only be - * called when Vulnerability Management is enabled. + * Purpose : Add php package to transaction from desired source. This function + * should only be called when Vulnerability Management is enabled. + * + * Params : 1. The transaction + * 2. Package name + * 3. Package version + * 4. Source priority + * + * Returns : pointer to added package on success or NULL otherwise. + */ +nr_php_package_t* nr_txn_add_php_package_from_source( + nrtxn_t* txn, + char* package_name, + char* package_version, + const nr_php_package_source_priority_t source); + +/* + * Purpose : Add php package to transaction from legacy source. This function + * should only be called when Vulnerability Management is enabled. * * Params : 1. The transaction * 2. Package name * 3. Package version * + * Returns : pointer to added package on success or NULL otherwise. */ -void nr_txn_add_php_package(nrtxn_t* txn, - char* package_name, - char* package_version); +extern nr_php_package_t* nr_txn_add_php_package(nrtxn_t* txn, + char* package_name, + char* package_version); +/* + * Purpose : Add php package suggestion to transaction. This function + * can be used when Vulnerability Management is not enabled. It will + * add the package to the transaction's + * php_package_major_version_metrics_suggestions list. At the end of the + * transaction this list is traversed and any suggestions with a known version + * will have a package major version metric created. + * + * Params : 1. The transaction + * 2. Package name + * 3. Package version (can be NULL or PHP_PACKAGE_VERSION_UNKNOWN) + * + * Returns : Nothing. + */ +extern void nr_txn_suggest_package_supportability_metric( + nrtxn_t* txn, + const char* package_name, + const char* package_version); #endif /* NR_TXN_HDR */ diff --git a/axiom/tests/.gitignore b/axiom/tests/.gitignore index e2e2db564..22ee3b042 100644 --- a/axiom/tests/.gitignore +++ b/axiom/tests/.gitignore @@ -82,6 +82,7 @@ test_number_converter test_obfuscate test_object test_offsets +test_php_packages test_postgres test_quarantine test_random diff --git a/axiom/tests/test_php_packages.c b/axiom/tests/test_php_packages.c index 427ece058..bd2323b2f 100644 --- a/axiom/tests/test_php_packages.c +++ b/axiom/tests/test_php_packages.c @@ -192,6 +192,183 @@ static void test_php_package_without_version(void) { nr_php_packages_destroy(&hm); } +static void test_php_package_priority(void) { +#define PACKAGE_NAME "vendor/package" +#define NO_VERSION NULL +#define PACKAGE_VERSION "1.0.0" +#define COMPOSER_VERSION "1.0.1" +#define COMPOSER_VERSION_2 "2.0.1" + nr_php_package_t* legacy_package; + nr_php_package_t* composer_package; + nr_php_package_t* composer_package_2; + nr_php_package_t* p; + nr_php_packages_t* hm = NULL; + int count; + char* legacy_versions[] = {NO_VERSION, PACKAGE_VERSION}; + + // Package added with legacy priority first - version from composer should win + for (size_t i = 0; i < sizeof(legacy_versions) / sizeof(legacy_versions[0]); + i++) { + legacy_package = nr_php_package_create( + PACKAGE_NAME, legacy_versions[i]); // legacy priority + tlib_pass_if_int_equal("create package by uses legacy priority", + NR_PHP_PACKAGE_SOURCE_LEGACY, + legacy_package->source_priority); + composer_package = nr_php_package_create_with_source( + PACKAGE_NAME, COMPOSER_VERSION, + NR_PHP_PACKAGE_SOURCE_COMPOSER); // composer priority + tlib_pass_if_int_equal("create package by uses composer priority", + NR_PHP_PACKAGE_SOURCE_COMPOSER, + composer_package->source_priority); + + hm = nr_php_packages_create(); + // order of adding packages: legacy first, composer second + nr_php_packages_add_package(hm, legacy_package); + nr_php_packages_add_package(hm, composer_package); + + count = nr_php_packages_count(hm); + tlib_pass_if_int_equal("add same package", 1, count); + + p = nr_php_packages_get_package(hm, PACKAGE_NAME); + tlib_pass_if_not_null("package exists", p); + tlib_pass_if_str_equal("package version from composer wins", + COMPOSER_VERSION, p->package_version); + + nr_php_packages_destroy(&hm); + } + + // Package added with composer priority first - version from composer should + // win + for (size_t i = 0; i < sizeof(legacy_versions) / sizeof(legacy_versions[0]); + i++) { + legacy_package = nr_php_package_create( + PACKAGE_NAME, legacy_versions[i]); // legacy priority + tlib_pass_if_int_equal("create package by uses legacy priority", + NR_PHP_PACKAGE_SOURCE_LEGACY, + legacy_package->source_priority); + composer_package = nr_php_package_create_with_source( + PACKAGE_NAME, COMPOSER_VERSION, + NR_PHP_PACKAGE_SOURCE_COMPOSER); // composer priority + tlib_pass_if_int_equal("create package by uses composer priority", + NR_PHP_PACKAGE_SOURCE_COMPOSER, + composer_package->source_priority); + + hm = nr_php_packages_create(); + // order of adding packages: legacy first, composer second + nr_php_packages_add_package(hm, composer_package); + nr_php_packages_add_package(hm, legacy_package); + + count = nr_php_packages_count(hm); + tlib_pass_if_int_equal("add same package", 1, count); + + p = nr_php_packages_get_package(hm, PACKAGE_NAME); + tlib_pass_if_not_null("package exists", p); + tlib_pass_if_str_equal("package version from composer wins", + COMPOSER_VERSION, p->package_version); + + nr_php_packages_destroy(&hm); + } + + // Package added with composer priority only - last version from composer + // should win + composer_package = nr_php_package_create_with_source( + PACKAGE_NAME, COMPOSER_VERSION, + NR_PHP_PACKAGE_SOURCE_COMPOSER); // composer priority + tlib_pass_if_int_equal("create package by uses composer priority", + NR_PHP_PACKAGE_SOURCE_COMPOSER, + composer_package->source_priority); + + composer_package_2 = nr_php_package_create_with_source( + PACKAGE_NAME, COMPOSER_VERSION_2, + NR_PHP_PACKAGE_SOURCE_COMPOSER); // composer priority + tlib_pass_if_int_equal("create package by uses composer priority", + NR_PHP_PACKAGE_SOURCE_COMPOSER, + composer_package_2->source_priority); + + hm = nr_php_packages_create(); + // order of adding packages: composer first, composer second + nr_php_packages_add_package(hm, composer_package); + nr_php_packages_add_package(hm, composer_package_2); + + count = nr_php_packages_count(hm); + tlib_pass_if_int_equal("add same package", 1, count); + + p = nr_php_packages_get_package(hm, PACKAGE_NAME); + tlib_pass_if_not_null("package exists", p); + tlib_pass_if_str_equal("package version from last composer wins", + COMPOSER_VERSION_2, p->package_version); + + nr_php_packages_destroy(&hm); +} + +static void nr_php_packages_itereate_callback(void* value, + const char* key, + size_t key_len, + void* user_data) { + nr_php_package_t* package = value; + const char* name = key; + nrbuf_t* buf = (nrbuf_t*)user_data; + + if (NULL == buf) { + return; + } + + /* append name, len, version to string */ + nr_buffer_add(buf, name, key_len); + nr_buffer_add(buf, NR_PSTR(",")); + nr_buffer_add(buf, package->package_version, + nr_strlen(package->package_version)); + nr_buffer_add(buf, NR_PSTR("\n")); +} + +static void test_php_package_iterate(void) { + nr_php_package_t* package1; + nr_php_package_t* package2; + nr_php_package_t* package3; + nr_php_packages_t* hm = nr_php_packages_create(); + nrbuf_t* buf; + int count; + + // Test: create multiple new packages and add to hashmap + package1 = nr_php_package_create("name1", "name1_version"); + package2 = nr_php_package_create("name2", "name2_version"); + package3 = nr_php_package_create("name3", "name3_version"); + + nr_php_packages_add_package(hm, package1); + nr_php_packages_add_package(hm, package2); + nr_php_packages_add_package(hm, package3); + + count = nr_php_packages_count(hm); + + tlib_pass_if_int_equal("package count", 3, count); + + /* tests with invalid values + * NOTE: nr_buffer_cptr(buf) will return NULL if no data is in the buffer + */ + buf = nr_buffer_create(0, 0); + nr_php_packages_iterate(NULL, nr_php_packages_itereate_callback, (void*)buf); + tlib_pass_if_null("iterate with NULL hashmap", nr_buffer_cptr(buf)); + nr_php_packages_iterate(hm, nr_php_packages_itereate_callback, NULL); + tlib_pass_if_null("iterate with NULL userdata", nr_buffer_cptr(buf)); + nr_php_packages_iterate(hm, NULL, (void*)buf); + tlib_pass_if_null("iterate with NULL callback", nr_buffer_cptr(buf)); + nr_php_packages_iterate(NULL, NULL, NULL); + tlib_pass_if_null("iterate with all NULL", nr_buffer_cptr(buf)); + nr_buffer_destroy(&buf); + + /* test with valid values */ + buf = nr_buffer_create(0, 0); + nr_php_packages_iterate(hm, nr_php_packages_itereate_callback, (void*)buf); + nr_buffer_add(buf, NR_PSTR("\0")); + tlib_pass_if_str_equal("iterate created proper string", + "name1,name1_version\nname2,name2_version\nname3,name3_version\n", nr_buffer_cptr(buf)); + nr_buffer_destroy(&buf); + + nr_php_packages_destroy(&hm); +} + + + tlib_parallel_info_t parallel_info = {.suggested_nthreads = -1, .state_size = 0}; @@ -203,4 +380,6 @@ void test_main(void* p NRUNUSED) { test_php_packages_to_json(); test_php_package_exists_in_hashmap(); test_php_package_without_version(); -} \ No newline at end of file + test_php_package_priority(); + test_php_package_iterate(); +} diff --git a/axiom/tests/test_txn.c b/axiom/tests/test_txn.c index 59b19f9b0..9230a416a 100644 --- a/axiom/tests/test_txn.c +++ b/axiom/tests/test_txn.c @@ -8597,6 +8597,8 @@ static void test_nr_txn_add_php_package(void) { char* package_name4 = "Wordpress"; char* package_version4 = PHP_PACKAGE_VERSION_UNKNOWN; nrtxn_t* txn = new_txn(0); + nr_php_package_t* p1 = NULL; + nr_php_package_t* p2 = NULL; /* * NULL parameters: ensure it does not crash @@ -8621,6 +8623,130 @@ static void test_nr_txn_add_php_package(void) { nr_free(json); nr_txn_destroy(&txn); + + txn = new_txn(0); + p1 = nr_txn_add_php_package(txn, package_name1, package_version1); + p2 = nr_txn_add_php_package(txn, package_name1, package_version2); + tlib_pass_if_ptr_equal( + "same package name, different version, add returns same pointer", p1, p2); + nr_txn_destroy(&txn); +} + +static void test_nr_txn_add_php_package_from_source(void) { + char* json; + char* package_name1 = "Laravel"; + char* package_version1 = "8.83.27"; + char* package_name2 = "Slim"; + char* package_version2 = "4.12.0"; + char* package_name3 = "Drupal"; + char* package_version3 = NULL; + char* package_name4 = "Wordpress"; + char* package_version4 = PHP_PACKAGE_VERSION_UNKNOWN; + nrtxn_t* txn = new_txn(0); + nr_php_package_t* p1 = NULL; + nr_php_package_t* p2 = NULL; + + /* + * NULL parameters: ensure it does not crash + */ + nr_txn_add_php_package_from_source(NULL, NULL, NULL, 0); + nr_txn_add_php_package_from_source(NULL, package_name1, package_version1, 0); + nr_txn_add_php_package_from_source(txn, NULL, package_version1, 0); + nr_txn_add_php_package_from_source(txn, package_name1, NULL, 0); + + // Test: add php packages to transaction + nr_txn_add_php_package_from_source(txn, package_name1, package_version1, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_txn_add_php_package_from_source(txn, package_name2, package_version2, + NR_PHP_PACKAGE_SOURCE_LEGACY); + nr_txn_add_php_package_from_source(txn, package_name3, package_version3, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + nr_txn_add_php_package_from_source(txn, package_name4, package_version4, + NR_PHP_PACKAGE_SOURCE_LEGACY); + json = nr_php_packages_to_json(txn->php_packages); + + tlib_pass_if_str_equal("correct json", + "[[\"Laravel\",\"8.83.27\",{}]," + "[\"Drupal\",\" \",{}],[\"Wordpress\",\" \",{}]," + "[\"Slim\",\"4.12.0\",{}]]", + json); + + nr_free(json); + nr_txn_destroy(&txn); + + txn = new_txn(0); + p1 = nr_txn_add_php_package_from_source(txn, package_name1, package_version1, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + p2 = nr_txn_add_php_package_from_source(txn, package_name1, package_version2, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + tlib_pass_if_ptr_equal( + "same package name, different version, add returns same pointer", p1, p2); + nr_txn_destroy(&txn); + + txn = new_txn(0); + p1 = nr_txn_add_php_package_from_source(txn, package_name1, package_version1, + NR_PHP_PACKAGE_SOURCE_LEGACY); + p2 = nr_txn_add_php_package_from_source(txn, package_name1, package_version2, + NR_PHP_PACKAGE_SOURCE_COMPOSER); + tlib_pass_if_ptr_equal( + "same package name, different version, add returns different pointer", p1, + p2); + tlib_pass_if_str_equal("composer version used", package_version2, + p2->package_version); + + nr_txn_destroy(&txn); +} + +static void test_nr_txn_suggest_package_supportability_metric(void) { + char* json; + char* package_name1 = "Laravel"; + char* package_version1 = "8.83.27"; + char* package_name2 = "Slim"; + char* package_version2 = "4.12.0"; + char* package_name3 = "Drupal"; + char* package_version3 = NULL; + char* package_name4 = "Wordpress"; + char* package_version4 = PHP_PACKAGE_VERSION_UNKNOWN; + nrtxn_t* txn = new_txn(0); + nr_php_package_t* p1 = NULL; + nr_php_package_t* p2 = NULL; + + /* + * NULL parameters: ensure it does not crash + */ + nr_txn_suggest_package_supportability_metric(NULL, NULL, NULL); + nr_txn_suggest_package_supportability_metric(NULL, package_name1, + package_version1); + nr_txn_suggest_package_supportability_metric(txn, NULL, package_version1); + nr_txn_suggest_package_supportability_metric(txn, package_name1, NULL); + + // Test: add php packages to transaction + nr_txn_suggest_package_supportability_metric(txn, package_name1, + package_version1); + nr_txn_suggest_package_supportability_metric(txn, package_name2, + package_version2); + nr_txn_suggest_package_supportability_metric(txn, package_name3, + package_version3); + nr_txn_suggest_package_supportability_metric(txn, package_name4, + package_version4); + json = nr_php_packages_to_json( + txn->php_package_major_version_metrics_suggestions); + + tlib_pass_if_str_equal("correct json", + "[[\"Laravel\",\"8.83.27\",{}]," + "[\"Drupal\",\" \",{}],[\"Wordpress\",\" \",{}]," + "[\"Slim\",\"4.12.0\",{}]]", + json); + + nr_free(json); + nr_txn_destroy(&txn); + + txn = new_txn(0); + p1 = nr_txn_add_php_package(txn, package_name1, package_version1); + p2 = nr_txn_add_php_package(txn, package_name1, package_version2); + tlib_pass_if_ptr_equal( + "same package name, different version, add returns same pointer", p1, p2); + nr_txn_destroy(&txn); } tlib_parallel_info_t parallel_info @@ -8725,4 +8851,6 @@ void test_main(void* p NRUNUSED) { test_record_log_event(); test_txn_log_configuration(); test_nr_txn_add_php_package(); + test_nr_txn_add_php_package_from_source(); + test_nr_txn_suggest_package_supportability_metric(); } diff --git a/daemon/internal/newrelic/integration/php_packages.go b/daemon/internal/newrelic/integration/php_packages.go index 375954b0d..fc9a10a59 100644 --- a/daemon/internal/newrelic/integration/php_packages.go +++ b/daemon/internal/newrelic/integration/php_packages.go @@ -31,12 +31,13 @@ type PhpPackagesCollection struct { // PHP packages config describes how to collect the JSON for the packages installed // for the current test case type PhpPackagesConfiguration struct { - path string - command string - supportedListFile string - overrideVersionsFile string - expectedPackages []string - packageNameOnly []string + path string // + command string // command to run to detect packages + supportedListFile string // JSON file containing list of packages we expect agent to detect + overrideVersionsFile string // JSON file containing overrides for expected package versions + expectedPackages []string // manual override of packages we expect to detect + packageNameOnly []string // list of packages which only have a name because agent cannot determine the version + expectAllDetected bool // flag to indicate we expect all packages detected by the command "command" } // composer package JSON @@ -159,16 +160,22 @@ func NewPhpPackagesCollection(path string, config []byte) (*PhpPackagesCollectio } } - if supportedOK && expectedOK { - return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - cannot specify 'supported_packages' and 'expected packages' - got %+v", params) + // or "expect_all" which means we expect the agent to detect all the packages that the "command" option would detect + _, expectAllOK := params["expect_all"] + + if (supportedOK && expectedOK) || (supportedOK && expectAllOK) || (expectedOK && expectAllOK) { + return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - must specify one of 'supported_packages', "+ + "'expected packages' or 'expect_all' - got %+v", params) } - if !supportedOK && !expectedOK { - return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - must specify 'supported_packages' or 'expected packages' - got %+v", params) + if !supportedOK && !expectedOK && !expectAllOK { + return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - must specify 'supported_packages' or 'expected packages' "+ + "or 'expect_all' - got %+v", params) } - if supportedOK && !commandOK { - return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - must specify 'command' option with `supported_packages` - got %+v", params) + if (supportedOK || expectAllOK) && !commandOK { + return nil, fmt.Errorf("Improper EXPECT_PHP_PACKAGES config - must specify 'command' option with `supported_packages` / "+ + "'expect_all' - got %+v", params) } // optional option to specify which packages will only have a name because agent cannot determine the version @@ -209,7 +216,8 @@ func NewPhpPackagesCollection(path string, config []byte) (*PhpPackagesCollectio supportedListFile: supportedListFile, overrideVersionsFile: overrideVersionsFile, expectedPackages: expectedPackagesArr, - packageNameOnly: packageNameOnlyArr}, + packageNameOnly: packageNameOnlyArr, + expectAllDetected: expectAllOK}, } return p, nil @@ -296,18 +304,27 @@ func (pkgs *PhpPackagesCollection) GatherInstalledPackages() ([]PhpPackage, erro var supported []string // get list of packages we expected the agent to detect - // this can be one of 2 scenarios: + // this can be one of 3 scenarios: // 1) test case used the "supported_packages" option which gives a JSON file which // lists all the packages the agent can detect // 2) test case used the "expected_packages" options which provides a comma separated // list of packages we expect the agent to detect + // 3) test case used the "expect_all" option which means we expect the agent to + // detect all the packages that the "command" option would detect + // + // Options #1 and #2 are mutually exclusive, and are intended for testing the legacy VM detection + // mechanism where the agent looks for "magic" files of a package and examinew internals of the + // package to determine its version. // - // Option #1 is preferable as it provides the most comprehensive view of what the agent can do. + // Option #1 is preferable when it available as it provides the most comprehensive view of what the agent can do. // // Option #2 is needed because some test cases do not exercise all the packages which are // installed and so the agent will not detect everything for that test case run which it could // theorectically detect if the test case used all the available packages installed. // + // Option #3 is used when testing the agent's ability to detect packages using the Composer API. In + // this case we expect the agent to detect the exact same packages as composer would detect. + // // Once the list of packages the agent is expected to detect is created it is used to filter // down the package list returned by running the "command" (usually composer) option for the // test case provided. @@ -318,8 +335,9 @@ func (pkgs *PhpPackagesCollection) GatherInstalledPackages() ([]PhpPackage, erro } } else if 0 < len(pkgs.config.expectedPackages) { supported = pkgs.config.expectedPackages - } else { - return nil, fmt.Errorf("Error determining expected packages - supported_packages and expected_packages are both empty") + } else if !pkgs.config.expectAllDetected { + return nil, fmt.Errorf("Error determining expected packages - supported_packages and expected_packages are both empty " + + "and expect_all is false") } splitCmd := strings.Split(pkgs.config.command, " ") @@ -339,7 +357,7 @@ func (pkgs *PhpPackagesCollection) GatherInstalledPackages() ([]PhpPackage, erro json.Unmarshal([]byte(out), &detected) for _, v := range detected.Installed { //fmt.Printf("composer detected %s %s\n", v.Name, v.Version) - if StringSliceContains(supported, v.Name) { + if pkgs.config.expectAllDetected || StringSliceContains(supported, v.Name) { var version string // remove any 'v' from front of version string @@ -371,6 +389,18 @@ func (pkgs *PhpPackagesCollection) GatherInstalledPackages() ([]PhpPackage, erro if 0 < len(version) { pkgs.packages = append(pkgs.packages, PhpPackage{"wordpress", version}) } + } else if 1 < len(splitCmd) && "composer-show.php" == splitCmd[1] { + lines := strings.Split(string(out), "\n") + version := "" + for _, line := range lines { + //fmt.Printf("line is |%s|\n", line) + splitLine := strings.Split(line, "=>") + if 2 == len(splitLine) { + name := strings.TrimSpace(splitLine[0]) + version = strings.TrimSpace(splitLine[1]) + pkgs.packages = append(pkgs.packages, PhpPackage{name, version}) + } + } } else { return nil, fmt.Errorf("ERROR - unknown method '%s'\n", splitCmd[0]) } diff --git a/daemon/internal/newrelic/integration/test.go b/daemon/internal/newrelic/integration/test.go index 631be4615..3e70e769a 100644 --- a/daemon/internal/newrelic/integration/test.go +++ b/daemon/internal/newrelic/integration/test.go @@ -637,6 +637,7 @@ func (t *Test) comparePhpPackages(harvest *newrelic.Harvest) { var expectedPkgsCollection *PhpPackagesCollection var expectNullPkgs bool var version_overrides map[string]interface{} + var subsetMatch bool = false if nil != t.phpPackagesConfig { var err error @@ -656,6 +657,19 @@ func (t *Test) comparePhpPackages(harvest *newrelic.Harvest) { t.Fatal(err) return } + + // Determine if we expect an exact match between expected and actual packages + // when using the composer API in the agent to detect packages it is possible + // it will return packages which the "composer show" command does not. These + // are usually virtual or other types of packages which "composer show" + // decides to not show. + // + // Currently the test handles this by listing all the packages that the agent + // detected but "composer show" did not as "Notes" on the test results. + // + // Tests for the legacy package detection mechanism still expect an exact match. + // + subsetMatch = expectedPkgsCollection.config.expectAllDetected } } else { // no configuration given for package (no EXPECT_PHP_PACKAGES in test case) so don't run test @@ -690,22 +704,44 @@ func (t *Test) comparePhpPackages(harvest *newrelic.Harvest) { if nil == expectedPackages { t.Fail(fmt.Errorf("No expected PHP packages, harvest contains %+v\n", actualPackages)) } - // compare expected and actual lists of packages + // Compare expected and actual lists of packages // since package names should be identical, iterate over // expected list and compare element by element with same // position in actual list. Name and version should match. // this works because the functions which generate these // lists sort them by package name for us - if len(expectedPackages) != len(actualPackages) { + // + // As explained above - if testing results from the Composer API + // agent detection mechanism, we may not get an exact match so + // we relax the test that the lengths of the two lists are the same + if !subsetMatch && (len(expectedPackages) != len(actualPackages)) { t.Fail(fmt.Errorf("Expected and actual php packages differ in length %d vs %d: expected %+v actual %+v", len(expectedPackages), len(actualPackages), expectedPackages, actualPackages)) return } for i, _ := range expectedPackages { - if expectedPackages[i].Name == actualPackages[i].Name { + var matchingIdx int = -1 + for j, pkg := range actualPackages { + //fmt.Printf("Comparing %s to %s\n", pkg.Name, expectedPackages[i].Name) + if pkg.Name == expectedPackages[i].Name { + //fmt.Printf("Match - index = %d\n", j) + matchingIdx = j + break + } + } + + //fmt.Printf("MatchingIdx: %d\n", matchingIdx) + //fmt.Printf("expectedPatckages[%d]: %+v\n", i, expectedPackages[i]) + // if -1 != matchingIdx { + // fmt.Printf("actualPackages[%d]: %+v\n", matchingIdx, actualPackages[matchingIdx]) + // } else { + // fmt.Printf("no match in actualPackages!\n") + // } + + if -1 != matchingIdx { testPackageNameOnly := false if nil != expectedPkgsCollection.config.packageNameOnly { - testPackageNameOnly = StringSliceContains(expectedPkgsCollection.config.packageNameOnly, actualPackages[i].Name) + testPackageNameOnly = StringSliceContains(expectedPkgsCollection.config.packageNameOnly, actualPackages[matchingIdx].Name) if testPackageNameOnly { t.AddNote(fmt.Sprintf("Tested package name only for packages: %+v", expectedPkgsCollection.config.packageNameOnly)) } @@ -720,23 +756,41 @@ func (t *Test) comparePhpPackages(harvest *newrelic.Harvest) { } if testPackageNameOnly { - if " " != actualPackages[i].Version { + if " " != actualPackages[matchingIdx].Version { t.Fail(fmt.Errorf("Expected no package version and a package version was detected - expected \" \" actual %+v. ", - actualPackages[i].Version)) + actualPackages[matchingIdx].Version)) return } else { continue } } - if expected_version == actualPackages[i].Version { + if expected_version == actualPackages[matchingIdx].Version { continue + } else { + t.Fail(fmt.Errorf("Expected version %s does not match actual version %s for package %s", + expected_version, actualPackages[matchingIdx].Version, expectedPackages[i].Name)) + return } } - t.Fail(fmt.Errorf("Expected and actual Php packages do not match: expected %+v actual %+v. Complete expected %v actual %v.", - expectedPackages[i], actualPackages[i], expectedPackages, actualPackages)) + t.Fail(fmt.Errorf("Expected Php packages do not match any actual packages: expected %+v\nComplete:\nexpected %v\nactual %v.\n", + expectedPackages[i], expectedPackages, actualPackages)) return } + + // create notes for all packages in the actual list not in the expected list + for ii, _ := range actualPackages { + var found bool = false + for _, pkg := range expectedPackages { + if pkg.Name == actualPackages[ii].Name { + found = true + break + } + } + if !found { + t.AddNote(fmt.Sprintf("Detected package not in expected: %+v", actualPackages[ii])) + } + } } else { if nil != expectedPackages { t.Fail(fmt.Errorf("Expected PHP packages %+v, harvest contains none\n", expectedPackages)) diff --git a/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/autoload.php b/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-00/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ) + ) + ); diff --git a/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/autoload.php b/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-01/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ) + ) + ); diff --git a/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/autoload.php b/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-broken-composer-02/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-composer-throwing-error/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-composer-throwing-error/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-composer-throwing-error/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ) + ) + ); diff --git a/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/autoload.php b/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-composer-throwing-exception/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ) + ) + ); diff --git a/tests/integration/autoloader/autoload-with-composer/vendor/autoload.php b/tests/integration/autoloader/autoload-with-composer/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/autoload-with-composer/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/autoload-with-composer/vendor/composer/autoload_real.php b/tests/integration/autoloader/autoload-with-composer/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/autoload-with-composer/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ) + ) + ); diff --git a/tests/integration/autoloader/autoload-without-composer/vendor/autoload.php b/tests/integration/autoloader/autoload-without-composer/vendor/autoload.php new file mode 100644 index 000000000..0a6947fef --- /dev/null +++ b/tests/integration/autoloader/autoload-without-composer/vendor/autoload.php @@ -0,0 +1,12 @@ + 1) { + $installedVersions = $argv[1]; +} + +include $installedVersions; +if ($argc > 2) { + $installed = Composer\InstalledVersions::getAllRawData(); + $package = $argv[2]; + $version = ltrim($installed[0]['versions'][$package]['pretty_version'], 'v'); + echo "$package => $version\n"; +} else { + Composer\InstalledVersions::show(); +} diff --git a/tests/integration/autoloader/packages-with-broken-composer-00/vendor/autoload.php b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/autoload.php new file mode 100644 index 000000000..01d206c0f --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/autoload.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/packages-with-broken-composer-00/vendor/composer/autoload_real.php b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ), + 'symfony/http-kernel' => array( + 'pretty_version' => '5.4.5', + 'version' => '5.4.5.0', + 'type' => 'library' + ), + ) + ); diff --git a/tests/integration/autoloader/packages-with-broken-composer-00/vendor/symfony/http-kernel/HttpKernel.php b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/symfony/http-kernel/HttpKernel.php new file mode 100644 index 000000000..2cceb6ac7 --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-00/vendor/symfony/http-kernel/HttpKernel.php @@ -0,0 +1,12 @@ + $info) { + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/packages-with-broken-composer-01/vendor/composer/autoload_real.php b/tests/integration/autoloader/packages-with-broken-composer-01/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-01/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked data: installed packages and their versions + 'versions' => array( + 'vendor1/package1' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'pretty_version' => '2.1.5', + 'version' => '2.1.5.0', + 'type' => 'library' + ), + 'laravel/framework' => array( + 'pretty_version' => '11.4.5', + 'version' => '11.4.5', + 'type' => 'library' + ), + ) + ); diff --git a/tests/integration/autoloader/packages-with-broken-composer-01/vendor/laravel/framework/src/Illuminate/Foundation/Application.php b/tests/integration/autoloader/packages-with-broken-composer-01/vendor/laravel/framework/src/Illuminate/Foundation/Application.php new file mode 100644 index 000000000..3c6718e89 --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-01/vendor/laravel/framework/src/Illuminate/Foundation/Application.php @@ -0,0 +1,25 @@ + $info) { + if (!is_string($package)) { + continue; + } + if (!is_array($info)) { + continue; + } + if (!array_key_exists('pretty_version', $info)) { + continue; + } + if (!is_string($info['pretty_version'])) { + continue; + } + $version = ltrim($info['pretty_version'], 'v'); + echo "$package => $version\n"; + } + } +} diff --git a/tests/integration/autoloader/packages-with-broken-composer-02/vendor/composer/autoload_real.php b/tests/integration/autoloader/packages-with-broken-composer-02/vendor/composer/autoload_real.php new file mode 100644 index 000000000..014c86e9a --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-02/vendor/composer/autoload_real.php @@ -0,0 +1,9 @@ + array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'type' => 'project' + ), + // Mocked invalid package data: + // - package without name and version + // - package without name but with version + // - package with name but without version + // Mocked valid package data: + // - package with name and version + 'versions' => array( + array( + 'version' => '1.1.3.0', + 'type' => 'library' + ), + array( + 'pretty_version' => 'v2.1.3', + 'version' => '2.1.3.0', + 'type' => 'library' + ), + 'vendor2/package2' => array( + 'version' => '3.1.5.0', + 'type' => 'library' + ), + 'laravel/framework' => array( + 'pretty_version' => '11.4.5', + 'version' => '11.4.5', + 'type' => 'library' + ), + ) + ); diff --git a/tests/integration/autoloader/packages-with-broken-composer-02/vendor/laravel/framework/src/Illuminate/Foundation/Application.php b/tests/integration/autoloader/packages-with-broken-composer-02/vendor/laravel/framework/src/Illuminate/Foundation/Application.php new file mode 100644 index 000000000..3c6718e89 --- /dev/null +++ b/tests/integration/autoloader/packages-with-broken-composer-02/vendor/laravel/framework/src/Illuminate/Foundation/Application.php @@ -0,0 +1,25 @@ +emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_cat.php b/tests/integration/logging/monolog2/test_monolog_cat.php index d96e38aec..b192b9ce9 100644 --- a/tests/integration/logging/monolog2/test_monolog_cat.php +++ b/tests/integration/logging/monolog2/test_monolog_cat.php @@ -56,7 +56,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -183,4 +183,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_context_simple.php b/tests/integration/logging/monolog2/test_monolog_context_simple.php index 769694845..a0f0b7260 100644 --- a/tests/integration/logging/monolog2/test_monolog_context_simple.php +++ b/tests/integration/logging/monolog2/test_monolog_context_simple.php @@ -59,7 +59,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], diff --git a/tests/integration/logging/monolog2/test_monolog_decoration_and_forwarding.php b/tests/integration/logging/monolog2/test_monolog_decoration_and_forwarding.php index 1737a919c..82ad4be61 100644 --- a/tests/integration/logging/monolog2/test_monolog_decoration_and_forwarding.php +++ b/tests/integration/logging/monolog2/test_monolog_decoration_and_forwarding.php @@ -113,7 +113,7 @@ [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/api/get_linking_metadata"}, [16, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -257,4 +257,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_disable_metrics.php b/tests/integration/logging/monolog2/test_monolog_disable_metrics.php index 95b84d636..eaed5d5d4 100644 --- a/tests/integration/logging/monolog2/test_monolog_disable_metrics.php +++ b/tests/integration/logging/monolog2/test_monolog_disable_metrics.php @@ -51,7 +51,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -153,4 +153,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_drop_empty.php b/tests/integration/logging/monolog2/test_monolog_drop_empty.php index 8139e3606..5d48030ca 100644 --- a/tests/integration/logging/monolog2/test_monolog_drop_empty.php +++ b/tests/integration/logging/monolog2/test_monolog_drop_empty.php @@ -57,7 +57,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -171,4 +171,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_large_message_limit.php b/tests/integration/logging/monolog2/test_monolog_large_message_limit.php index d7c9b677a..7a0e1eacd 100644 --- a/tests/integration/logging/monolog2/test_monolog_large_message_limit.php +++ b/tests/integration/logging/monolog2/test_monolog_large_message_limit.php @@ -40,7 +40,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -78,4 +78,4 @@ function test_logging() { } } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_large_message_limit_drops.php b/tests/integration/logging/monolog2/test_monolog_large_message_limit_drops.php index 0dfe1dc2d..313e73edd 100644 --- a/tests/integration/logging/monolog2/test_monolog_large_message_limit_drops.php +++ b/tests/integration/logging/monolog2/test_monolog_large_message_limit_drops.php @@ -40,7 +40,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1666, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -78,4 +78,4 @@ function test_logging() { } } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_limit_log_events.php b/tests/integration/logging/monolog2/test_monolog_limit_log_events.php index c9106b2ea..ccc75de41 100644 --- a/tests/integration/logging/monolog2/test_monolog_limit_log_events.php +++ b/tests/integration/logging/monolog2/test_monolog_limit_log_events.php @@ -58,7 +58,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -161,4 +161,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_limit_zero_events.php b/tests/integration/logging/monolog2/test_monolog_limit_zero_events.php index 6ff0fa7d1..573850d3a 100644 --- a/tests/integration/logging/monolog2/test_monolog_limit_zero_events.php +++ b/tests/integration/logging/monolog2/test_monolog_limit_zero_events.php @@ -58,7 +58,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -101,4 +101,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid1.php b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid1.php index f760b19ac..c346aa55e 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid1.php +++ b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid1.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid2.php b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid2.php index ada730ed7..ab55e0359 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid2.php +++ b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid2.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid3.php b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid3.php index cdd99bc5f..616eb81f8 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid3.php +++ b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid3.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid4.php b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid4.php index 354108a09..0f13144eb 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid4.php +++ b/tests/integration/logging/monolog2/test_monolog_log_events_max_samples_stored_invalid4.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_level_filter.php b/tests/integration/logging/monolog2/test_monolog_log_level_filter.php index 939dd9cf5..fa7902395 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_level_filter.php +++ b/tests/integration/logging/monolog2/test_monolog_log_level_filter.php @@ -60,7 +60,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -171,4 +171,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog2/test_monolog_log_level_filter_invalid.php b/tests/integration/logging/monolog2/test_monolog_log_level_filter_invalid.php index d2eac9410..22107fd98 100644 --- a/tests/integration/logging/monolog2/test_monolog_log_level_filter_invalid.php +++ b/tests/integration/logging/monolog2/test_monolog_log_level_filter_invalid.php @@ -61,7 +61,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/2/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -172,4 +172,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_basic.php b/tests/integration/logging/monolog3/test_monolog_basic.php index 5cbc3a1da..0e494b078 100644 --- a/tests/integration/logging/monolog3/test_monolog_basic.php +++ b/tests/integration/logging/monolog3/test_monolog_basic.php @@ -56,7 +56,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -200,4 +200,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_cat.php b/tests/integration/logging/monolog3/test_monolog_cat.php index dcf557213..12b0c76ae 100644 --- a/tests/integration/logging/monolog3/test_monolog_cat.php +++ b/tests/integration/logging/monolog3/test_monolog_cat.php @@ -56,7 +56,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -184,4 +184,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_context_simple.php b/tests/integration/logging/monolog3/test_monolog_context_simple.php index 1e77e6d25..ddcfd65f9 100644 --- a/tests/integration/logging/monolog3/test_monolog_context_simple.php +++ b/tests/integration/logging/monolog3/test_monolog_context_simple.php @@ -59,7 +59,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], diff --git a/tests/integration/logging/monolog3/test_monolog_decoration_and_forwarding.php b/tests/integration/logging/monolog3/test_monolog_decoration_and_forwarding.php index fa0bbb6cb..3d8edcc7c 100644 --- a/tests/integration/logging/monolog3/test_monolog_decoration_and_forwarding.php +++ b/tests/integration/logging/monolog3/test_monolog_decoration_and_forwarding.php @@ -113,7 +113,7 @@ [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/api/get_linking_metadata"}, [16, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -257,4 +257,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_disable_metrics.php b/tests/integration/logging/monolog3/test_monolog_disable_metrics.php index cb5beb8e1..11bad2177 100644 --- a/tests/integration/logging/monolog3/test_monolog_disable_metrics.php +++ b/tests/integration/logging/monolog3/test_monolog_disable_metrics.php @@ -51,7 +51,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -153,4 +153,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_drop_empty.php b/tests/integration/logging/monolog3/test_monolog_drop_empty.php index 61937fb9f..6a470653b 100644 --- a/tests/integration/logging/monolog3/test_monolog_drop_empty.php +++ b/tests/integration/logging/monolog3/test_monolog_drop_empty.php @@ -57,7 +57,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -171,4 +171,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_large_message_limit.php b/tests/integration/logging/monolog3/test_monolog_large_message_limit.php index 191800f49..50b2a26a5 100644 --- a/tests/integration/logging/monolog3/test_monolog_large_message_limit.php +++ b/tests/integration/logging/monolog3/test_monolog_large_message_limit.php @@ -40,7 +40,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -78,4 +78,4 @@ function test_logging() { } } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_large_message_limit_drops.php b/tests/integration/logging/monolog3/test_monolog_large_message_limit_drops.php index eed9a410a..c2913419d 100644 --- a/tests/integration/logging/monolog3/test_monolog_large_message_limit_drops.php +++ b/tests/integration/logging/monolog3/test_monolog_large_message_limit_drops.php @@ -40,7 +40,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1666, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -78,4 +78,4 @@ function test_logging() { } } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_limit_log_events.php b/tests/integration/logging/monolog3/test_monolog_limit_log_events.php index b1f72e6b6..b5ffaf258 100644 --- a/tests/integration/logging/monolog3/test_monolog_limit_log_events.php +++ b/tests/integration/logging/monolog3/test_monolog_limit_log_events.php @@ -58,7 +58,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -161,4 +161,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_limit_zero_events.php b/tests/integration/logging/monolog3/test_monolog_limit_zero_events.php index 38abfe890..4b65d64f3 100644 --- a/tests/integration/logging/monolog3/test_monolog_limit_zero_events.php +++ b/tests/integration/logging/monolog3/test_monolog_limit_zero_events.php @@ -58,7 +58,7 @@ [{"name": "OtherTransactionTotalTime"}, [1, "??", "??", "??", "??", "??"]], [{"name": "OtherTransactionTotalTime/php__FILE__"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], @@ -101,4 +101,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid1.php b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid1.php index f33d832af..f94ea94af 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid1.php +++ b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid1.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/LocalDecorating/PHP/disabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid2.php b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid2.php index 73c70e58e..5d0363243 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid2.php +++ b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid2.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid3.php b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid3.php index 72ca4b06b..8b451bdea 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid3.php +++ b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid3.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid4.php b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid4.php index 2f60d6bc1..fe4185197 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid4.php +++ b/tests/integration/logging/monolog3/test_monolog_log_events_max_samples_stored_invalid4.php @@ -45,7 +45,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [833, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -81,4 +81,4 @@ function test_logging() { } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_level_filter.php b/tests/integration/logging/monolog3/test_monolog_log_level_filter.php index 529ef1459..69d482e9b 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_level_filter.php +++ b/tests/integration/logging/monolog3/test_monolog_log_level_filter.php @@ -60,7 +60,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -171,4 +171,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging(); diff --git a/tests/integration/logging/monolog3/test_monolog_log_level_filter_invalid.php b/tests/integration/logging/monolog3/test_monolog_log_level_filter_invalid.php index e5387616f..649cd5acf 100644 --- a/tests/integration/logging/monolog3/test_monolog_log_level_filter_invalid.php +++ b/tests/integration/logging/monolog3/test_monolog_log_level_filter_invalid.php @@ -61,7 +61,7 @@ [{"name": "Supportability/Logging/Forwarding/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/Metrics/PHP/enabled"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/Logging/PHP/Monolog/enabled"}, [1, "??", "??", "??", "??", "??"]], - [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [8, "??", "??", "??", "??", "??"]], + [{"name": "Supportability/PHP/package/monolog/monolog/3/detected"}, [1, "??", "??", "??", "??", "??"]], [{"name": "Supportability/library/Monolog/detected"}, [1, "??", "??", "??", "??", "??"]] ] ] @@ -172,4 +172,4 @@ function test_logging() { $logger->emergency("emergency"); } -test_logging(); \ No newline at end of file +test_logging();