From 1291a76ff1281c200de07a230c329a4ab12ff8fd Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 6 Aug 2024 07:50:10 -0700 Subject: [PATCH 1/4] chore: Bump version to 11.1 (#945) --- VERSION | 2 +- axiom/nr_version.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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/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); From a95eb5120aab89b7ea075adb9009fc11ee095610 Mon Sep 17 00:00:00 2001 From: Michael Fulbright <89205663+mfulb@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:46:56 -0400 Subject: [PATCH 2/4] fix(testing): Fixes count check for apdex metrics (#946) The current code for EXPECT_METRICS_EXIST would verify the count of any metric was >0 before passing the test. However, with apdex metrics the first field is not the count of metrics but the count of the number of times the transaction time was less than apdex_t. This change allows for the count to be 0 for apdex metrics. --- daemon/internal/newrelic/integration/test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/daemon/internal/newrelic/integration/test.go b/daemon/internal/newrelic/integration/test.go index 0f9342030..f80b3e986 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 } From 010f1f19f4a32bd19b58e113bd98b0accd76ea63 Mon Sep 17 00:00:00 2001 From: Michael Fulbright <89205663+mfulb@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:41:19 -0400 Subject: [PATCH 3/4] chore(agent): Changes code to use NR string routines (#949) Switches to use nr_strlcpy and nr_strcpy instead of libc versions for better platform generality. --- agent/lib_aws_sdk_php.c | 4 ++-- axiom/nr_distributed_trace.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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); From 0ba870b7b7f434884c9f863668cc53f9e7c0de02 Mon Sep 17 00:00:00 2001 From: Michael Fulbright <89205663+mfulb@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:47:04 -0400 Subject: [PATCH 4/4] feat(agent): Adds supportability metrics for PHP and agent version (#947) Adds supportability metrics for the agent and PHP version. I did clean up some ZTS macros as well but I think it is obvious what is a real change and what isnt. --------- Co-authored-by: Michal Nowacki --- agent/Makefile.frag | 12 +- agent/php_newrelic.c | 5 +- agent/php_txn.c | 45 ++++++ agent/php_txn_private.h | 29 ++++ agent/tests/test_txn.c | 136 +++++++++++++++++- daemon/cmd/integration_runner/main.go | 8 ++ daemon/internal/newrelic/integration/test.go | 2 + daemon/internal/newrelic/integration/util.go | 33 +++++ .../test_php_and_agent_version_metrics.php | 27 ++++ 9 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 daemon/internal/newrelic/integration/util.go create mode 100644 tests/integration/supportability/test_php_and_agent_version_metrics.php 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/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/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 f80b3e986..36c21472a 100644 --- a/daemon/internal/newrelic/integration/test.go +++ b/daemon/internal/newrelic/integration/test.go @@ -756,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 @@ + +