Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ZNeumann committed Feb 5, 2025
1 parent 996dcc9 commit 783790d
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
110 changes: 110 additions & 0 deletions agent/lib_aws_sdk_php.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@
#include "fw_support.h"
#include "util_logging.h"
#include "lib_aws_sdk_php.h"
#include "nr_segment_external.h"

#define PHP_PACKAGE_NAME "aws/aws-sdk-php"
#define AWS_ARN_REGEX "(arn:(aws[a-zA-Z-]*)?:lambda:)?" \
"((?<region>[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}):)?" \
"((?<accountId>\\d{12}):)?" \
"(function:)?" \
"(?<functionName>[a-zA-Z0-9-\\.]+)" \
"(:(?<qualifier>\\$LATEST|[a-zA-Z0-9-]+))?"

/*
* In a normal course of events, the following line will always work
Expand Down Expand Up @@ -115,6 +122,103 @@ NR_PHP_WRAPPER(nr_create_aws_service_metric) {
}
NR_PHP_WRAPPER_END

/*
* LambdaClient::invoke
* This is called when an instance is invoking a lambda function
* for AWS serveless execution.
*/
NR_PHP_WRAPPER(nr_aws_lambda_invoke_before) {
nr_segment_t* segment = nr_segment_start(NRPRG(txn), NULL, NULL);
segment->wraprec = auto_segment->wraprec;
}
NR_PHP_WRAPPER_END

NR_PHP_WRAPPER(nr_aws_lambda_invoke_after) {
nr_segment_external_params_t external_params
= {.library = "aws_sdk"};

zval** retval_ptr = NR_GET_RETURN_VALUE_PTR;

// Only instrument on successful invokation
if (retval_ptr != NULL) {
char* arn = NULL;
char* function_name = NULL;
char* region = NULL;
char* qualifier = NULL;
char* accountID = NULL;
zval* this_obj = NULL;

// Extract all information possible from the passed lambda identifier
zval* lambda_arg = nr_php_get_user_func_arg(1, NR_EXECUTE_ORIG_ARGS);
nr_regex_substrings_t* matches = nr_regex_match_capture(NRPRG(aws_arn_regex),
Z_STRVAL_P(lambda_arg),
Z_STRLEN_P(lambda_arg));
function_name = nr_regex_substrings_get_named(matches, "functionName");
accountID = nr_regex_substrings_get_named(matches, "accountId");
region = nr_regex_substrings_get_named(matches, "region");
qualifier = nr_regex_substrings_get_named(matches, "qualifier");

this_obj = NR_PHP_USER_FN_THIS();

// suppliment missing information with API calls
if (function_name == NULL) {
// Cannot get the needed data. Function name is required in the
// argument, so this won't happen in normal operation
} else {
if (accountID == NULL) {
accountID = NRINI(aws_account_id);
}
if (region == NULL) {
zval* region_zval = nr_php_call(this_obj, "getRegion");
if (region_zval) {
region = Z_STRVAL_P(region_zval);
}
}
if (qualifier == NULL) {
zval* qualifier_zval = nr_php_call(this_obj, "getQualifier");
if (qualifier_zval) {
qualifier = Z_STRVAL_P(qualifier_zval);
}
}
}

// construct the arn
if (accountID && region) {
if (qualifier) {
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s:%s", region, accountID, function_name, qualifier);
} else {
arn = nr_formatf("arn:aws:lambda:%s:%s:function:%s", region, accountID, function_name);
}

// end the segment
external_params.status = Z_LVAL_P(nr_php_zend_hash_find(Z_ARRVAL_P(*retval_ptr), "StatusCode"));
zval* metadata = nr_php_zend_hash_find(Z_ARRVAL_P(*retval_ptr), "@metadata");
external_params.uri = Z_STRVAL_P(nr_php_zend_hash_find(Z_ARRVAL_P(metadata), "effectiveUri"));
nr_attributes_agent_add_string(auto_segment->attributes,
NR_ATTRIBUTE_DESTINATION_SPAN, "cloud.platform" , "aws_lambda");
nr_attributes_agent_add_string(auto_segment->attributes,
NR_ATTRIBUTE_DESTINATION_SPAN, "cloud.resource_id", arn);
nr_segment_external_end(&auto_segment, &external_params);
} else {
nr_segment_discard(&auto_segment);
}

nr_regex_substrings_destroy(&matches);
nr_free(arn);
nr_free(function_name);
nr_free(region);
nr_free(qualifier);
nr_free(accountID);
} else {
nr_segment_discard(&auto_segment);
}
}
NR_PHP_WRAPPER_END

static nr_regex_t* compile_arn_regex() {
return nr_regex_create(AWS_ARN_REGEX, 0, 0);
}

/*
* The ideal file to begin immediate detection of the aws-sdk is:
* aws-sdk-php/src/functions.php
Expand Down Expand Up @@ -158,8 +262,14 @@ void nr_aws_sdk_php_enable() {

/* Extract the version for aws-sdk 3+ */
nr_lib_aws_sdk_php_handle_version();
NRPRG(aws_arn_regex) = compile_arn_regex();

/* Called when initializing all Clients */
nr_php_wrap_user_function(NR_PSTR("Aws\\AwsClient::parseClass"),
nr_create_aws_service_metric);
nr_php_wrap_user_function_before_after_clean(
NR_PSTR("Aws\\Lambda\\LambdaClient::invoke"),
nr_aws_lambda_invoke_before,
nr_aws_lambda_invoke_after,
nr_aws_lambda_invoke_after);
}
3 changes: 3 additions & 0 deletions agent/php_newrelic.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ bool check_cufa; /* Whether we need to check cufa because we are
char* wordpress_tag; /* The current WordPress tag */
#endif //OAPI

nr_regex_t* aws_arn_regex; /* Regex pattern for AWS ARNs */
nrinistr_t aws_account_id; /* TBD */

nr_matcher_t* wordpress_plugin_matcher; /* Matcher for plugin filenames */
nr_matcher_t* wordpress_theme_matcher; /* Matcher for theme filenames */
nr_matcher_t* wordpress_core_matcher; /* Matcher for plugin filenames */
Expand Down
2 changes: 2 additions & 0 deletions agent/php_rshutdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ int nr_php_post_deactivate(void) {

nr_php_exception_filters_destroy(&NRPRG(exception_filters));

nr_regex_destroy(&NRPRG(aws_arn_regex));

nr_matcher_destroy(&NRPRG(wordpress_plugin_matcher));
nr_matcher_destroy(&NRPRG(wordpress_core_matcher));
nr_matcher_destroy(&NRPRG(wordpress_theme_matcher));
Expand Down

0 comments on commit 783790d

Please sign in to comment.