Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(agent): fix mongodb instrumentation for PHP 8.0+ #878

Merged
merged 11 commits into from
Jun 21, 2024
168 changes: 167 additions & 1 deletion agent/lib_mongodb.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ void nr_mongodb_get_host_and_port_path_or_id(zval* server,
}
}

#if ZEND_MODULE_API_NO < ZEND_8_0_X_API_NO \
|| defined OVERWRITE_ZEND_EXECUTE_DATA
NR_PHP_WRAPPER(nr_mongodb_operation) {
const char* this_klass = "MongoDB\\Operation\\Executable";
zval* collection = NULL;
Expand Down Expand Up @@ -173,7 +175,169 @@ NR_PHP_WRAPPER(nr_mongodb_operation) {
}
NR_PHP_WRAPPER_END

void nr_mongodb_enable(TSRMLS_D) {
#else

NR_PHP_WRAPPER(nr_mongodb_operation_before) {
(void)wraprec;
nr_segment_t* segment = NULL;
segment = nr_segment_start(NRPRG(txn), NULL, NULL);
lavarou marked this conversation as resolved.
Show resolved Hide resolved
if (NULL != segment) {
segment->wraprec = auto_segment->wraprec;
}
}
zsistla marked this conversation as resolved.
Show resolved Hide resolved
NR_PHP_WRAPPER_END

NR_PHP_WRAPPER(nr_mongodb_operation_after) {
const char* this_klass = "MongoDB\\Operation\\Executable";
zval* collection = NULL;
zval* database = NULL;
zval* server = NULL;
zval* this_var = NULL;
bool discard_segment = false;
nr_datastore_instance_t instance = {
.host = NULL,
.port_path_or_id = NULL,
.database_name = NULL,
};

// tell the compiler to ignore the cast from const char * to char *
// to save having to do a strdup operation
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
nr_segment_datastore_params_t params = {
zsistla marked this conversation as resolved.
Show resolved Hide resolved
.collection = NULL,
.datastore = {
.type = NR_DATASTORE_MONGODB,
},
.operation = (char *)wraprec->extra,
.instance = &instance,
.callbacks = {
.backtrace = nr_php_backtrace_callback,
},
};
#pragma GCC diagnostic pop
/*
* We check for the interface all Collection operations extend, rather than
* their specific class. Not all operations have the properties we need but
* the ones we hook do (as of mongo-php-library v.1.1).
*/
this_var = nr_php_scope_get(NR_EXECUTE_ORIG_ARGS);
if (!nr_php_object_instanceof_class(this_var, this_klass)) {
nrl_verbosedebug(NRL_FRAMEWORK, "%s: operation is not %s", __func__,
this_klass);
discard_segment = true;
goto leave;
}

collection = nr_php_get_zval_object_property(this_var, "collectionName");
if (nr_php_is_zval_valid_string(collection)) {
params.collection = Z_STRVAL_P(collection);
}

database = nr_php_get_zval_object_property(this_var, "databaseName");
if (nr_php_is_zval_valid_string(database)) {
instance.database_name = Z_STRVAL_P(database);
}

server = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS);
nr_mongodb_get_host_and_port_path_or_id(server, &instance.host,
&instance.port_path_or_id);

leave:
if (discard_segment) {
nr_segment_discard(&auto_segment);
} else {
nr_segment_datastore_end(&auto_segment, &params);
}
nr_php_arg_release(&server);
nr_php_scope_release(&this_var);
nr_free(instance.host);
nr_free(instance.port_path_or_id);
}
NR_PHP_WRAPPER_END

#endif /* OAPI */

void nr_mongodb_enable() {
#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \
&& !defined OVERWRITE_ZEND_EXECUTE_DATA

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Aggregate::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "aggregate");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\BulkWrite::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "bulkWrite");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Count::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "count");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\CreateIndexes::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "createIndexes");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Delete::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "delete");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Distinct::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "distinct");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\DropCollection::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "dropCollection");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\DropIndexes::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "dropIndexes");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Find::execute"), nr_mongodb_operation_before,
nr_mongodb_operation_after, nr_mongodb_operation_after, "find");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\FindAndModify::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "findAndModify");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\InsertMany::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "insertMany");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\InsertOne::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "insertOne");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\ListIndexes::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "listIndexes");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\Update::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "update");

nr_php_wrap_user_function_before_after_clean_extra(
NR_PSTR("MongoDB\\Operation\\DatabaseCommand::execute"),
nr_mongodb_operation_before, nr_mongodb_operation_after,
nr_mongodb_operation_after, "databaseCommand");

#else /* Non-OAPI */

/*
* We instrument interesting methods on the MongoDB\Collection class via their
* associated MongoDB\Operation classes.
Expand Down Expand Up @@ -265,6 +429,8 @@ void nr_mongodb_enable(TSRMLS_D) {
NR_PSTR("MongoDB\\Operation\\DatabaseCommand::execute"),
nr_mongodb_operation, "databaseCommand" TSRMLS_CC);

#endif /* OAPI */

if (NRINI(vulnerability_management_package_detection_enabled)) {
nr_txn_add_php_package(NRPRG(txn), "mongodb/mongodb",
PHP_PACKAGE_VERSION_UNKNOWN);
Expand Down
21 changes: 21 additions & 0 deletions agent/php_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@ nruserfn_t* nr_php_wrap_user_function_before_after_clean(
return wraprec;
}

nruserfn_t* nr_php_wrap_user_function_before_after_clean_extra(
lavarou marked this conversation as resolved.
Show resolved Hide resolved
const char* name,
size_t namelen,
nrspecialfn_t before_callback,
nrspecialfn_t after_callback,
nrspecialfn_t clean_callback,
const char* extra) {
nruserfn_t* wraprec = nr_php_wrap_user_function_before_after_clean(
name, namelen, before_callback, after_callback, clean_callback);

if (nrunlikely(NULL == wraprec)) {
nrl_warning(NRL_INSTRUMENT, "%s: unable to wrap '%s'", __func__,
NRSAFESTR(name));
return wraprec;
}

wraprec->extra = extra;

return wraprec;
}

nruserfn_t* nr_php_wrap_callable_before_after_clean(
zend_function* callable,
nrspecialfn_t before_callback,
Expand Down
8 changes: 8 additions & 0 deletions agent/php_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ extern nruserfn_t* nr_php_wrap_callable_before_after_clean(
nrspecialfn_t before_callback,
nrspecialfn_t after_callback,
nrspecialfn_t clean_callback);

extern nruserfn_t* nr_php_wrap_user_function_before_after_clean_extra(
const char* name,
size_t namelen,
nrspecialfn_t before_callback,
nrspecialfn_t after_callback,
nrspecialfn_t clean_callback,
const char* extra);
#endif
extern nruserfn_t* nr_php_wrap_user_function(const char* name,
size_t namelen,
Expand Down
9 changes: 0 additions & 9 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ services:
ports:
- "11211:11211"
container_name: memcached
# mongodb:
# image: mongo:latest
# restart: always
# ports:
# - "27019:27019"
postgres:
image: postgres
restart: always
Expand All @@ -57,8 +52,6 @@ services:
environment:
MEMCACHE_HOST: memcached

# MONGO_HOST: mongodb

MYSQL_DB: database
MYSQL_USER: admin
MYSQL_PASSWD: admin
Expand Down Expand Up @@ -86,8 +79,6 @@ services:
environment:
MEMCACHE_HOST: memcached

# MONGO_HOST: mongodb

MYSQL_DB: database
MYSQL_USER: admin
MYSQL_PASSWD: admin
Expand Down
8 changes: 0 additions & 8 deletions tests/include/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ function isset_or($check, $alternate = NULL)
$MYSQL_SERVER = $MYSQL_HOST . ":" . $MYSQL_PORT;
}

if (class_exists('MongoClient')) {
$MONGO_HOST = isset_or('MONGO_HOST', MongoClient::DEFAULT_HOST);
$MONGO_PORT = isset_or('MONGO_PORT', MongoClient::DEFAULT_PORT);
} else {
$MONGO_HOST = null;
$MONGO_PORT = null;
}

$MEMCACHE_HOST = isset_or('MEMCACHE_HOST', '127.0.0.1');
$MEMCACHE_PORT = isset_or('MEMCACHE_PORT', '11211');

Expand Down
14 changes: 0 additions & 14 deletions tests/integration/mongo/mongo.inc

This file was deleted.

18 changes: 0 additions & 18 deletions tests/integration/mongo/skipif.inc

This file was deleted.

55 changes: 0 additions & 55 deletions tests/integration/mongo/test_execute.php

This file was deleted.

Loading