diff --git a/VERSION b/VERSION index 4a68b557e..68d8f15e2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -11.0.0 \ No newline at end of file +11.1.0 diff --git a/agent/Makefile.frag b/agent/Makefile.frag index def094486..1cfe1606c 100644 --- a/agent/Makefile.frag +++ b/agent/Makefile.frag @@ -49,13 +49,17 @@ $(PHP_MODULES): .libs/deps.mk newrelic.la: $(PHP_AXIOM)/libaxiom.a # -# The version number is needed by php_newrelic.c as a static string literal, +# The version number is needed by several source files as a static string literal, # so it can be placed in the module entry. # include ../make/version.mk + php_newrelic.lo: CPPFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\"" php_newrelic.lo: ../VERSION +php_txn.lo: CPPFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\"" +php_txn.lo: ../VERSION + # # Unit tests! # @@ -261,6 +265,12 @@ ifeq (/opt/nr/lamp/lib,$(findstring /opt/nr/lamp/lib,$(PHP_EMBED_LIBRARY))) endif endif +# +# Need agent version for test_txn +# +tests/test_txn.o: EXTRA_CFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\"" +tests/test_txn.o: ../VERSION + # # Used when linking test binaries. # diff --git a/agent/lib_aws_sdk_php.c b/agent/lib_aws_sdk_php.c index d9055690d..cff08dbfd 100644 --- a/agent/lib_aws_sdk_php.c +++ b/agent/lib_aws_sdk_php.c @@ -88,9 +88,9 @@ void nr_lib_aws_sdk_php_add_supportability_service_metric( } cp = buf; - strcpy(cp, PHP_AWS_SDK_SERVICE_NAME_METRIC_PREFIX); + nr_strcpy(cp, PHP_AWS_SDK_SERVICE_NAME_METRIC_PREFIX); cp += PHP_AWS_SDK_SERVICE_NAME_METRIC_PREFIX_LEN - 1; - strlcpy(cp, service_name, MAX_AWS_SERVICE_NAME_LEN); + nr_strlcpy(cp, service_name, MAX_AWS_SERVICE_NAME_LEN); nrm_force_add(NRPRG(txn) ? NRTXN(unscoped_metrics) : 0, buf, 0); } diff --git a/agent/php_newrelic.c b/agent/php_newrelic.c index 210c04428..912dff365 100644 --- a/agent/php_newrelic.c +++ b/agent/php_newrelic.c @@ -120,8 +120,8 @@ ZEND_BEGIN_ARG_INFO_EX(newrelic_arginfo_void, 0, 0, 0) ZEND_END_ARG_INFO() #endif /* PHP 8.0+ */ -ZEND_BEGIN_ARG_INFO_EX(newrelic_get_request_metadata_arginfo, 0, 0, 0) -ZEND_ARG_INFO(0, transport) +ZEND_BEGIN_ARG_INFO_EX(newrelic_get_request_metadata_arginfo, 0, 0, 0) +ZEND_ARG_INFO(0, transport) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(newrelic_add_custom_parameter_arginfo, 0, 0, 2) @@ -223,7 +223,6 @@ ZEND_BEGIN_ARG_INFO_EX(newrelic_set_user_id_arginfo, 0, 0, 1) ZEND_ARG_INFO(0, uuid) ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO_EX(newrelic_set_error_group_callback_arginfo, 0, 0, 1) ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO() diff --git a/agent/php_txn.c b/agent/php_txn.c index cdfa1269f..785007b41 100644 --- a/agent/php_txn.c +++ b/agent/php_txn.c @@ -669,6 +669,48 @@ static void nr_php_txn_send_metrics_once(nrtxn_t* txn TSRMLS_DC) { #undef FMT_BOOL } +void nr_php_txn_create_agent_version_metric(nrtxn_t* txn) { + if (NULL == txn) { + return; + } + + nrm_force_add(NRTXN(unscoped_metrics), + "Supportability/PHP/AgentVersion/" NR_VERSION, 0); +} + +void nr_php_txn_create_php_version_metric(nrtxn_t* txn, const char* version) { + char* metric_name = NULL; + + if (NULL == txn) { + return; + } + + if (nr_strempty(version)) { + return; + } + + metric_name = nr_formatf("Supportability/PHP/Version/%s", version); + nrm_force_add(NRTXN(unscoped_metrics), metric_name, 0); + nr_free(metric_name); +} + +void nr_php_txn_create_agent_php_version_metrics(nrtxn_t* txn) { + char* version = NULL; + + if (NULL == txn) { + return; + } + nr_php_txn_create_agent_version_metric(txn); + + if (!nr_strempty(NR_PHP_PROCESS_GLOBALS(php_version))) { + version = NR_PHP_PROCESS_GLOBALS(php_version); + } else { + version = "unknown"; + } + + nr_php_txn_create_php_version_metric(txn, version); +} + nr_status_t nr_php_txn_begin(const char* appnames, const char* license TSRMLS_DC) { nrtxnopt_t opts; @@ -1120,6 +1162,9 @@ nr_status_t nr_php_txn_end(int ignoretxn, int in_post_deactivate TSRMLS_DC) { "Supportability/execute/allocated_segment_count", nr_txn_allocated_segment_count(txn)); + /* Agent and PHP version metrics*/ + nr_php_txn_create_agent_php_version_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 743adc06f..bf49eb107 100644 --- a/agent/php_txn_private.h +++ b/agent/php_txn_private.h @@ -36,3 +36,32 @@ nrobj_t* nr_php_txn_get_supported_security_policy_settings(); * Params : 1. The current transaction. */ extern void nr_php_txn_handle_fpm_error(nrtxn_t* txn TSRMLS_DC); + +/* + * Purpose : Create and record metrics for the PHP and agent versions. + * + * Params : 1. The current transaction. + * + * Notes : This function relies on NR_VERSION and the value of + * NRPRG(php_version) to create the metrics. + */ +extern void nr_php_txn_create_agent_php_version_metrics(nrtxn_t* txn); + +/* + * Purpose : Create and record metric for a specific agent version. + * + * Params : 1. The current transaction. + * + * Notes : This function relies on the value of the macro NR_VERSION + * to create. + */ +extern void nr_php_txn_create_agent_version_metric(nrtxn_t* txn); + +/* + * Purpose : Create and record metric for a specific PHP version. + * + * Params : 1. The current transaction. + * 2. The PHP agent version. + */ +extern void nr_php_txn_create_php_version_metric(nrtxn_t* txn, + const char* version); diff --git a/agent/tests/test_txn.c b/agent/tests/test_txn.c index 3209e3c27..50c4ff8bc 100644 --- a/agent/tests/test_txn.c +++ b/agent/tests/test_txn.c @@ -161,6 +161,133 @@ static void test_max_segments_config_values(TSRMLS_D) { tlib_php_request_end(); } +#define PHP_VERSION_METRIC_BASE "Supportability/PHP/Version" +#define AGENT_VERSION_METRIC_BASE "Supportability/PHP/AgentVersion" + +static void test_create_php_version_metric() { + nrtxn_t* txn; + int count; + + tlib_php_request_start(); + txn = NRPRG(txn); + + count = nrm_table_size(txn->unscoped_metrics); + + /* Test invalid values are properly handled */ + nr_php_txn_create_php_version_metric(NULL, NULL); + tlib_pass_if_int_equal("PHP version metric shouldnt be created 1", count, + nrm_table_size(txn->unscoped_metrics)); + + nr_php_txn_create_php_version_metric(txn, NULL); + tlib_pass_if_int_equal("PHP version metric shouldnt be created 2", count, + nrm_table_size(txn->unscoped_metrics)); + + nr_php_txn_create_php_version_metric(NULL, "7.4.0"); + tlib_pass_if_int_equal("PHP version metric shouldnt be created 3", count, + nrm_table_size(txn->unscoped_metrics)); + + nr_php_txn_create_php_version_metric(txn, ""); + tlib_pass_if_int_equal("PHP version metric shouldnt be created 4", count, + nrm_table_size(txn->unscoped_metrics)); + + /* test valid values */ + nr_php_txn_create_php_version_metric(txn, "7.4.0"); + tlib_pass_if_int_equal("PHP version metric should be create", count + 1, + nrm_table_size(txn->unscoped_metrics)); + + const nrmetric_t* metric + = nrm_find(txn->unscoped_metrics, PHP_VERSION_METRIC_BASE "/7.4.0"); + const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric); + + tlib_pass_if_not_null("PHP version metric found", metric); + tlib_pass_if_str_equal("PHP version metric name check", metric_name, + PHP_VERSION_METRIC_BASE "/7.4.0"); + + tlib_php_request_end(); +} + +static void test_create_agent_version_metric() { + nrtxn_t* txn; + int count; + + tlib_php_request_start(); + txn = NRPRG(txn); + + count = nrm_table_size(txn->unscoped_metrics); + + /* Test invalid values are properly handled */ + nr_php_txn_create_agent_version_metric(NULL); + tlib_pass_if_int_equal("Agent version metric shouldnt be created - txn is NULL", count, + nrm_table_size(txn->unscoped_metrics)); + + /* Test valid values */ + nr_php_txn_create_agent_version_metric(txn); + tlib_pass_if_int_equal("Agent version metric should be created - txn is not NULL", count + 1, + nrm_table_size(txn->unscoped_metrics)); + + const nrmetric_t* metric + = nrm_find(txn->unscoped_metrics, AGENT_VERSION_METRIC_BASE "/" NR_VERSION); + const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric); + + tlib_pass_if_not_null("Agent version metric found", metric); + tlib_pass_if_str_equal("Agent version metric name check", metric_name, + AGENT_VERSION_METRIC_BASE "/" NR_VERSION); + + tlib_php_request_end(); +} + +static void test_create_agent_php_version_metrics() { + nrtxn_t* txn; + + /* + * Test : Create agent PHP version metrics. + */ + tlib_php_request_start(); + txn = NRPRG(txn); + + zval* expected_php_zval = tlib_php_request_eval_expr("phpversion();"); + + char* php_version_name = nr_formatf(PHP_VERSION_METRIC_BASE "/%s", + Z_STRVAL_P(expected_php_zval)); + + nr_php_zval_free(&expected_php_zval); + + char* agent_version_name + = nr_formatf(AGENT_VERSION_METRIC_BASE "/%s", NR_VERSION); + + nr_php_txn_create_agent_php_version_metrics(txn); + + /* Test the PHP version metric creation */ + const nrmetric_t* metric = nrm_find(txn->unscoped_metrics, php_version_name); + const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric); + + tlib_pass_if_not_null("happy path: PHP version metric created", metric); + tlib_pass_if_not_null("happy path: PHP version metric name created", + metric_name); + + tlib_pass_if_str_equal("happy path: PHP version metric name check", + metric_name, php_version_name); + + /* Test the agent version metric creation*/ + metric = nrm_find(txn->unscoped_metrics, agent_version_name); + metric_name = nrm_get_name(txn->unscoped_metrics, metric); + + tlib_pass_if_not_null("happy path: Agent version metric created", metric); + tlib_pass_if_not_null("happy path: Agent version metric name created", + metric_name); + + tlib_pass_if_str_equal("happy path: Agent version metric name check", + metric_name, agent_version_name); + + nr_free(agent_version_name); + nr_free(php_version_name); + + tlib_php_request_end(); +} + +#undef PHP_VERSION_METRIC_BASE +#undef AGENT_VERSION_METRIC_BASE + tlib_parallel_info_t parallel_info = {.suggested_nthreads = 1, .state_size = 0}; void test_main(void* p NRUNUSED) { @@ -175,8 +302,11 @@ void test_main(void* p NRUNUSED) { tlib_php_engine_create( "newrelic.transaction_events.attributes.include=request.uri" PTSRMLS_CC); - test_handle_fpm_error(TSRMLS_C); - test_max_segments_config_values(TSRMLS_C); + test_handle_fpm_error(); + test_max_segments_config_values(); + test_create_php_version_metric(); + test_create_agent_version_metric(); + test_create_agent_php_version_metrics(); - tlib_php_engine_destroy(TSRMLS_C); + tlib_php_engine_destroy(); } diff --git a/axiom/nr_distributed_trace.c b/axiom/nr_distributed_trace.c index bdc587e24..25fcd27d5 100644 --- a/axiom/nr_distributed_trace.c +++ b/axiom/nr_distributed_trace.c @@ -497,7 +497,7 @@ void nr_distributed_trace_set_trace_id(nr_distributed_trace_t* dt, for (int i = 0; i < padding; i++) { dest[i] = '0'; } - strcpy(dest + padding, trace_id); + nr_strcpy(dest + padding, trace_id); dt->trace_id = dest; } else { dt->trace_id = nr_strdup(trace_id); diff --git a/axiom/nr_version.c b/axiom/nr_version.c index 8f4a3646d..018770a1a 100644 --- a/axiom/nr_version.c +++ b/axiom/nr_version.c @@ -46,8 +46,9 @@ * wallflower 06May2024 (10.20) * xerophyllum 20May2024 (10.21) * yarrow 26Jun2024 (10.22) + * zinnia 30Jul2024 (11.0) */ -#define NR_CODENAME "zinnia" +#define NR_CODENAME "amethyst" const char* nr_version(void) { return NR_STR2(NR_VERSION); diff --git a/daemon/cmd/integration_runner/main.go b/daemon/cmd/integration_runner/main.go index 40f472af4..f1a65a402 100644 --- a/daemon/cmd/integration_runner/main.go +++ b/daemon/cmd/integration_runner/main.go @@ -376,6 +376,14 @@ func main() { // Env vars common to all tests. ctx.Env["EXTERNAL_HOST"] = externalHost + ctx.Env["PHP_VERSION"] = integration.GetPHPVersion() + + agent_extension, ok := ctx.Settings["extension"] + if !ok { + agent_extension = "newrelic.so" + } + ctx.Env["AGENT_VERSION"] = integration.GetAgentVersion(agent_extension) + handler, err := startDaemon("unix", *flagPort, flagSecurityToken.String(), flagSecuityPolicies.String()) if err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/daemon/internal/newrelic/integration/test.go b/daemon/internal/newrelic/integration/test.go index 0f9342030..36c21472a 100644 --- a/daemon/internal/newrelic/integration/test.go +++ b/daemon/internal/newrelic/integration/test.go @@ -544,7 +544,12 @@ func (t *Test) compareMetricsExist(harvest *newrelic.Harvest) { actualCount := int64(math.Round(actualData.([]interface{})[0].(float64))) metricPasses := false - if (count == -1 && actualCount > 0) || (actualCount == count) { + + // apdex metrics can have a count of 0 since the count field is + // actually the "satisfied" count, not a total count of metric + // as it is for other types of metrics + apdex_metric := strings.HasPrefix(expected, "Apdex/") + if (count == -1 && (apdex_metric || actualCount > 0)) || (actualCount == count) { metricPasses = true } @@ -751,6 +756,8 @@ var ( regexp.MustCompile(`^Supportability\/InstrumentedFunction`), regexp.MustCompile(`^Supportability\/TxnData\/.*`), regexp.MustCompile(`^Supportability/C/NewrelicVersion/.*`), + regexp.MustCompile(`^Supportability/PHP/Version/.*`), + regexp.MustCompile(`^Supportability/PHP/AgentVersion/.*`), } ) diff --git a/daemon/internal/newrelic/integration/util.go b/daemon/internal/newrelic/integration/util.go new file mode 100644 index 000000000..25ab9462f --- /dev/null +++ b/daemon/internal/newrelic/integration/util.go @@ -0,0 +1,33 @@ +// +// Copyright 2020 New Relic Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +// + +package integration + +import ( + "fmt" + "os/exec" +) + +func GetPHPVersion() string { + cmd := exec.Command("php", "-r", "echo PHP_VERSION;") + + output, err := cmd.Output() + if err != nil { + fmt.Printf("Failed to get PHP version: %v\n", err) + return "failed" + } + + return string(output) +} + +func GetAgentVersion(agent_extension string) string { + cmd := exec.Command("php", "-d", "extension="+agent_extension, "-r", "echo phpversion('newrelic');") + + output, err := cmd.Output() + if err != nil { + return fmt.Errorf("Failed to get agent version: %v", err).Error() + } + return string(output) +} diff --git a/tests/integration/supportability/test_php_and_agent_version_metrics.php b/tests/integration/supportability/test_php_and_agent_version_metrics.php new file mode 100644 index 000000000..bc63110f8 --- /dev/null +++ b/tests/integration/supportability/test_php_and_agent_version_metrics.php @@ -0,0 +1,27 @@ + +