Skip to content

Commit

Permalink
feat(agent): Add RabbitMQ instrumentation using the php-amqplib library
Browse files Browse the repository at this point in the history
Initial commit does the following:
* Detect library via magic file
* Detect package and version information.
* Basic unit tests
  • Loading branch information
zsistla committed Jan 18, 2025
1 parent 996dcc9 commit 2df782f
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 1 deletion.
1 change: 1 addition & 0 deletions agent/Makefile.frag
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ TEST_BINARIES = \
tests/test_internal_instrument \
tests/test_hash \
tests/test_lib_aws_sdk_php \
tests/test_lib_php_ampqlib \
tests/test_memcached \
tests/test_mongodb \
tests/test_monolog \
Expand Down
2 changes: 1 addition & 1 deletion agent/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ if test "$PHP_NEWRELIC" = "yes"; then
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_composer.c"
lib_composer.c lib_php_amqplib.c"
PHP_NEW_EXTENSION(newrelic, $FRAMEWORKS $LIBRARIES $NEWRELIC_AGENT, $ext_shared,, $(NEWRELIC_CFLAGS))

PHP_SUBST(NEWRELIC_CFLAGS)
Expand Down
1 change: 1 addition & 0 deletions agent/fw_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern void nr_guzzle4_enable(TSRMLS_D);
extern void nr_guzzle6_enable(TSRMLS_D);
extern void nr_laminas_http_enable(TSRMLS_D);
extern void nr_mongodb_enable(TSRMLS_D);
extern void nr_php_amqplib_enable();
extern void nr_phpunit_enable(TSRMLS_D);
extern void nr_predis_enable(TSRMLS_D);
extern void nr_zend_http_enable(TSRMLS_D);
Expand Down
82 changes: 82 additions & 0 deletions agent/lib_php_amqplib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

/*
* Functions relating to instrumenting the AWS-SDK-PHP.
* https://github.com/aws/aws-sdk-php
*/
#include "php_agent.h"
#include "php_call.h"
#include "php_hash.h"
#include "php_wrapper.h"
#include "fw_hooks.h"
#include "fw_support.h"
#include "util_logging.h"
#include "lib_php_amqplib.h"

#define PHP_PACKAGE_NAME "php-amqplib/php-amqplib"

/*
* nr_php_amqplib_handle_version will automatically load the class if it isn't
* loaded yet and then evaluate the string. To avoid the VERY unlikely but not
* impossible fatal error if the file/class isn't loaded yet, we need to wrap
* the call in a try/catch block and make it a lambda so that we avoid fatal
* errors.
*/
void nr_php_amqplib_handle_version() {
char* version = NULL;
zval retval;
int result = FAILURE;

result = zend_eval_string(
"(function() {"
" $nr_php_amqplib_version = '';"
" try {"
" $nr_php_amqplib_version = PhpAmqpLib\\Package::VERSION;"
" } catch (Throwable $e) {"
" }"
" return $nr_php_amqplib_version;"
"})();",
&retval, "Get nr_php_amqplib_version");

/* See if we got a non-empty/non-null string for version. */
if (SUCCESS == result) {
if (nr_php_is_zval_non_empty_string(&retval)) {
version = Z_STRVAL(retval);
}
}

if (NRINI(vulnerability_management_package_detection_enabled)) {
/* Add php package to transaction */
nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME, version);
}

nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME,
version);

zval_dtor(&retval);
}

/*
*
* Version detection will be called directly from Aws\Sdk.php
*/
void nr_php_amqplib_enable() {
/*
* Set the UNKNOWN package first, so it doesn't overwrite what we find with
* nr_lib_aws_sdk_php_handle_version.
*/
if (NRINI(vulnerability_management_package_detection_enabled)) {
nr_txn_add_php_package(NRPRG(txn), PHP_PACKAGE_NAME,
PHP_PACKAGE_VERSION_UNKNOWN);
}

/* Extract the version for aws-sdk 3+ */
nr_php_amqplib_handle_version();

/* Called when initializing all Clients */
// nr_php_wrap_user_function(NR_PSTR("Aws\\AwsClient::parseClass"),
// nr_create_aws_service_metric);
}
13 changes: 13 additions & 0 deletions agent/lib_php_amqplib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Functions relating to instrumenting AWS-SDK-PHP.
*/
#ifndef LIB_PHP_AMQPLIB
#define LIB_PHP_AMQPLIB

extern void nr_aws_php_amqplib_enable();
extern void nr_php_amqplib_handle_version();

#endif /* LIB_PHP_AMQPLIB */
4 changes: 4 additions & 0 deletions agent/php_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,10 @@ static nr_library_table_t libraries[] = {

{"MongoDB", NR_PSTR("mongodb/src/client.php"), nr_mongodb_enable},

/* php-amqplib RabbitMQ >= 3.7 */
{"php-amqplib", NR_PSTR("phpamqplib/connection/abstractconnection.php"),
nr_php_amqplib_enable},

/*
* The first path is for Composer installs, the second is for
* /usr/local/bin.
Expand Down
110 changes: 110 additions & 0 deletions agent/tests/test_lib_php_amqplib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include "tlib_php.h"

#include "php_agent.h"
#include "lib_php_amqplib.h"
#include "fw_support.h"

tlib_parallel_info_t parallel_info
= {.suggested_nthreads = -1, .state_size = 0};

#if ZEND_MODULE_API_NO > ZEND_7_1_X_API_NO

static void declare_php_amqplib_package_class(const char* ns,
const char* klass,
const char* sdk_version) {
char* source = nr_formatf(
"namespace %s;"
"class %s{"
"const VERSION = '%s';"
"}",
ns, klass, sdk_version);

tlib_php_request_eval(source);

nr_free(source);
}

static void test_nr_lib_php_amqplib_handle_version(void) {
#define LIBRARY_NAME "php-amqplib/php-amqplib"
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_php_amqplib_handle_version with library_versions[%ld]=%s: package " \
"major version metric - %s"
char* test_description = NULL;
size_t i = 0;

/*
* If lib_php_amqplib_handle_version function is ever called, we have already
* detected the php-amqplib library.
*/

/*
* PhpAmqpLib/Package class exists. Should create php-amqplib package metric
* suggestion with version
*/
for (i = 0; i < sizeof(library_versions) / sizeof(library_versions[0]); i++) {
tlib_php_request_start();

declare_php_amqplib_package_class("PhpAmqpLib", "Package",
library_versions[i]);
nr_lib_php_amqplib_handle_version();

p = nr_php_packages_get_package(
NRPRG(txn)->php_package_major_version_metrics_suggestions,
LIBRARY_NAME);

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);

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_end();
}

/*
* PhpAmqpLib/Package 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_php_amqplib_handle_version();

p = nr_php_packages_get_package(
NRPRG(txn)->php_package_major_version_metrics_suggestions, LIBRARY_NAME);

tlib_pass_if_not_null(
"nr_lib_php_amqplib_handle_version when PhpAmqpLib\\Package class is not "
"defined - "
"suggestion created",
p);
tlib_pass_if_str_equal(
"nr_lib_php_amqplib_handle_version when PhpAmqpLib\\Package class is not "
"defined - "
"suggested version set to PHP_PACKAGE_VERSION_UNKNOWN",
PHP_PACKAGE_VERSION_UNKNOWN, p->package_version);

tlib_php_request_end();
}

void test_main(void* p NRUNUSED) {
tlib_php_engine_create("");
test_nr_lib_php_amqplib_handle_version();
tlib_php_engine_destroy();
}
#else
void test_main(void* p NRUNUSED) {}
#endif

0 comments on commit 2df782f

Please sign in to comment.