Skip to content

Commit 0ba870b

Browse files
mfulblavarou
andauthored
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 <[email protected]>
1 parent 010f1f1 commit 0ba870b

File tree

9 files changed

+290
-7
lines changed

9 files changed

+290
-7
lines changed

agent/Makefile.frag

+11-1
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ $(PHP_MODULES): .libs/deps.mk
4949
newrelic.la: $(PHP_AXIOM)/libaxiom.a
5050

5151
#
52-
# The version number is needed by php_newrelic.c as a static string literal,
52+
# The version number is needed by several source files as a static string literal,
5353
# so it can be placed in the module entry.
5454
#
5555
include ../make/version.mk
56+
5657
php_newrelic.lo: CPPFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\""
5758
php_newrelic.lo: ../VERSION
5859

60+
php_txn.lo: CPPFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\""
61+
php_txn.lo: ../VERSION
62+
5963
#
6064
# Unit tests!
6165
#
@@ -261,6 +265,12 @@ ifeq (/opt/nr/lamp/lib,$(findstring /opt/nr/lamp/lib,$(PHP_EMBED_LIBRARY)))
261265
endif
262266
endif
263267

268+
#
269+
# Need agent version for test_txn
270+
#
271+
tests/test_txn.o: EXTRA_CFLAGS += -DNR_VERSION="\"$(AGENT_VERSION)\""
272+
tests/test_txn.o: ../VERSION
273+
264274
#
265275
# Used when linking test binaries.
266276
#

agent/php_newrelic.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ ZEND_BEGIN_ARG_INFO_EX(newrelic_arginfo_void, 0, 0, 0)
120120
ZEND_END_ARG_INFO()
121121
#endif /* PHP 8.0+ */
122122

123-
ZEND_BEGIN_ARG_INFO_EX(newrelic_get_request_metadata_arginfo, 0, 0, 0)
124-
ZEND_ARG_INFO(0, transport)
123+
ZEND_BEGIN_ARG_INFO_EX(newrelic_get_request_metadata_arginfo, 0, 0, 0)
124+
ZEND_ARG_INFO(0, transport)
125125
ZEND_END_ARG_INFO()
126126

127127
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)
223223
ZEND_ARG_INFO(0, uuid)
224224
ZEND_END_ARG_INFO()
225225

226-
227226
ZEND_BEGIN_ARG_INFO_EX(newrelic_set_error_group_callback_arginfo, 0, 0, 1)
228227
ZEND_ARG_INFO(0, callback)
229228
ZEND_END_ARG_INFO()

agent/php_txn.c

+45
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,48 @@ static void nr_php_txn_send_metrics_once(nrtxn_t* txn TSRMLS_DC) {
669669
#undef FMT_BOOL
670670
}
671671

672+
void nr_php_txn_create_agent_version_metric(nrtxn_t* txn) {
673+
if (NULL == txn) {
674+
return;
675+
}
676+
677+
nrm_force_add(NRTXN(unscoped_metrics),
678+
"Supportability/PHP/AgentVersion/" NR_VERSION, 0);
679+
}
680+
681+
void nr_php_txn_create_php_version_metric(nrtxn_t* txn, const char* version) {
682+
char* metric_name = NULL;
683+
684+
if (NULL == txn) {
685+
return;
686+
}
687+
688+
if (nr_strempty(version)) {
689+
return;
690+
}
691+
692+
metric_name = nr_formatf("Supportability/PHP/Version/%s", version);
693+
nrm_force_add(NRTXN(unscoped_metrics), metric_name, 0);
694+
nr_free(metric_name);
695+
}
696+
697+
void nr_php_txn_create_agent_php_version_metrics(nrtxn_t* txn) {
698+
char* version = NULL;
699+
700+
if (NULL == txn) {
701+
return;
702+
}
703+
nr_php_txn_create_agent_version_metric(txn);
704+
705+
if (!nr_strempty(NR_PHP_PROCESS_GLOBALS(php_version))) {
706+
version = NR_PHP_PROCESS_GLOBALS(php_version);
707+
} else {
708+
version = "unknown";
709+
}
710+
711+
nr_php_txn_create_php_version_metric(txn, version);
712+
}
713+
672714
nr_status_t nr_php_txn_begin(const char* appnames,
673715
const char* license TSRMLS_DC) {
674716
nrtxnopt_t opts;
@@ -1120,6 +1162,9 @@ nr_status_t nr_php_txn_end(int ignoretxn, int in_post_deactivate TSRMLS_DC) {
11201162
"Supportability/execute/allocated_segment_count",
11211163
nr_txn_allocated_segment_count(txn));
11221164

1165+
/* Agent and PHP version metrics*/
1166+
nr_php_txn_create_agent_php_version_metrics(txn);
1167+
11231168
/* Add CPU and memory metrics */
11241169
nr_php_resource_usage_sampler_end(TSRMLS_C);
11251170

agent/php_txn_private.h

+29
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,32 @@ nrobj_t* nr_php_txn_get_supported_security_policy_settings();
3636
* Params : 1. The current transaction.
3737
*/
3838
extern void nr_php_txn_handle_fpm_error(nrtxn_t* txn TSRMLS_DC);
39+
40+
/*
41+
* Purpose : Create and record metrics for the PHP and agent versions.
42+
*
43+
* Params : 1. The current transaction.
44+
*
45+
* Notes : This function relies on NR_VERSION and the value of
46+
* NRPRG(php_version) to create the metrics.
47+
*/
48+
extern void nr_php_txn_create_agent_php_version_metrics(nrtxn_t* txn);
49+
50+
/*
51+
* Purpose : Create and record metric for a specific agent version.
52+
*
53+
* Params : 1. The current transaction.
54+
*
55+
* Notes : This function relies on the value of the macro NR_VERSION
56+
* to create.
57+
*/
58+
extern void nr_php_txn_create_agent_version_metric(nrtxn_t* txn);
59+
60+
/*
61+
* Purpose : Create and record metric for a specific PHP version.
62+
*
63+
* Params : 1. The current transaction.
64+
* 2. The PHP agent version.
65+
*/
66+
extern void nr_php_txn_create_php_version_metric(nrtxn_t* txn,
67+
const char* version);

agent/tests/test_txn.c

+133-3
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,133 @@ static void test_max_segments_config_values(TSRMLS_D) {
161161
tlib_php_request_end();
162162
}
163163

164+
#define PHP_VERSION_METRIC_BASE "Supportability/PHP/Version"
165+
#define AGENT_VERSION_METRIC_BASE "Supportability/PHP/AgentVersion"
166+
167+
static void test_create_php_version_metric() {
168+
nrtxn_t* txn;
169+
int count;
170+
171+
tlib_php_request_start();
172+
txn = NRPRG(txn);
173+
174+
count = nrm_table_size(txn->unscoped_metrics);
175+
176+
/* Test invalid values are properly handled */
177+
nr_php_txn_create_php_version_metric(NULL, NULL);
178+
tlib_pass_if_int_equal("PHP version metric shouldnt be created 1", count,
179+
nrm_table_size(txn->unscoped_metrics));
180+
181+
nr_php_txn_create_php_version_metric(txn, NULL);
182+
tlib_pass_if_int_equal("PHP version metric shouldnt be created 2", count,
183+
nrm_table_size(txn->unscoped_metrics));
184+
185+
nr_php_txn_create_php_version_metric(NULL, "7.4.0");
186+
tlib_pass_if_int_equal("PHP version metric shouldnt be created 3", count,
187+
nrm_table_size(txn->unscoped_metrics));
188+
189+
nr_php_txn_create_php_version_metric(txn, "");
190+
tlib_pass_if_int_equal("PHP version metric shouldnt be created 4", count,
191+
nrm_table_size(txn->unscoped_metrics));
192+
193+
/* test valid values */
194+
nr_php_txn_create_php_version_metric(txn, "7.4.0");
195+
tlib_pass_if_int_equal("PHP version metric should be create", count + 1,
196+
nrm_table_size(txn->unscoped_metrics));
197+
198+
const nrmetric_t* metric
199+
= nrm_find(txn->unscoped_metrics, PHP_VERSION_METRIC_BASE "/7.4.0");
200+
const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric);
201+
202+
tlib_pass_if_not_null("PHP version metric found", metric);
203+
tlib_pass_if_str_equal("PHP version metric name check", metric_name,
204+
PHP_VERSION_METRIC_BASE "/7.4.0");
205+
206+
tlib_php_request_end();
207+
}
208+
209+
static void test_create_agent_version_metric() {
210+
nrtxn_t* txn;
211+
int count;
212+
213+
tlib_php_request_start();
214+
txn = NRPRG(txn);
215+
216+
count = nrm_table_size(txn->unscoped_metrics);
217+
218+
/* Test invalid values are properly handled */
219+
nr_php_txn_create_agent_version_metric(NULL);
220+
tlib_pass_if_int_equal("Agent version metric shouldnt be created - txn is NULL", count,
221+
nrm_table_size(txn->unscoped_metrics));
222+
223+
/* Test valid values */
224+
nr_php_txn_create_agent_version_metric(txn);
225+
tlib_pass_if_int_equal("Agent version metric should be created - txn is not NULL", count + 1,
226+
nrm_table_size(txn->unscoped_metrics));
227+
228+
const nrmetric_t* metric
229+
= nrm_find(txn->unscoped_metrics, AGENT_VERSION_METRIC_BASE "/" NR_VERSION);
230+
const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric);
231+
232+
tlib_pass_if_not_null("Agent version metric found", metric);
233+
tlib_pass_if_str_equal("Agent version metric name check", metric_name,
234+
AGENT_VERSION_METRIC_BASE "/" NR_VERSION);
235+
236+
tlib_php_request_end();
237+
}
238+
239+
static void test_create_agent_php_version_metrics() {
240+
nrtxn_t* txn;
241+
242+
/*
243+
* Test : Create agent PHP version metrics.
244+
*/
245+
tlib_php_request_start();
246+
txn = NRPRG(txn);
247+
248+
zval* expected_php_zval = tlib_php_request_eval_expr("phpversion();");
249+
250+
char* php_version_name = nr_formatf(PHP_VERSION_METRIC_BASE "/%s",
251+
Z_STRVAL_P(expected_php_zval));
252+
253+
nr_php_zval_free(&expected_php_zval);
254+
255+
char* agent_version_name
256+
= nr_formatf(AGENT_VERSION_METRIC_BASE "/%s", NR_VERSION);
257+
258+
nr_php_txn_create_agent_php_version_metrics(txn);
259+
260+
/* Test the PHP version metric creation */
261+
const nrmetric_t* metric = nrm_find(txn->unscoped_metrics, php_version_name);
262+
const char* metric_name = nrm_get_name(txn->unscoped_metrics, metric);
263+
264+
tlib_pass_if_not_null("happy path: PHP version metric created", metric);
265+
tlib_pass_if_not_null("happy path: PHP version metric name created",
266+
metric_name);
267+
268+
tlib_pass_if_str_equal("happy path: PHP version metric name check",
269+
metric_name, php_version_name);
270+
271+
/* Test the agent version metric creation*/
272+
metric = nrm_find(txn->unscoped_metrics, agent_version_name);
273+
metric_name = nrm_get_name(txn->unscoped_metrics, metric);
274+
275+
tlib_pass_if_not_null("happy path: Agent version metric created", metric);
276+
tlib_pass_if_not_null("happy path: Agent version metric name created",
277+
metric_name);
278+
279+
tlib_pass_if_str_equal("happy path: Agent version metric name check",
280+
metric_name, agent_version_name);
281+
282+
nr_free(agent_version_name);
283+
nr_free(php_version_name);
284+
285+
tlib_php_request_end();
286+
}
287+
288+
#undef PHP_VERSION_METRIC_BASE
289+
#undef AGENT_VERSION_METRIC_BASE
290+
164291
tlib_parallel_info_t parallel_info = {.suggested_nthreads = 1, .state_size = 0};
165292

166293
void test_main(void* p NRUNUSED) {
@@ -175,8 +302,11 @@ void test_main(void* p NRUNUSED) {
175302
tlib_php_engine_create(
176303
"newrelic.transaction_events.attributes.include=request.uri" PTSRMLS_CC);
177304

178-
test_handle_fpm_error(TSRMLS_C);
179-
test_max_segments_config_values(TSRMLS_C);
305+
test_handle_fpm_error();
306+
test_max_segments_config_values();
307+
test_create_php_version_metric();
308+
test_create_agent_version_metric();
309+
test_create_agent_php_version_metrics();
180310

181-
tlib_php_engine_destroy(TSRMLS_C);
311+
tlib_php_engine_destroy();
182312
}

daemon/cmd/integration_runner/main.go

+8
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,14 @@ func main() {
376376
// Env vars common to all tests.
377377
ctx.Env["EXTERNAL_HOST"] = externalHost
378378

379+
ctx.Env["PHP_VERSION"] = integration.GetPHPVersion()
380+
381+
agent_extension, ok := ctx.Settings["extension"]
382+
if !ok {
383+
agent_extension = "newrelic.so"
384+
}
385+
ctx.Env["AGENT_VERSION"] = integration.GetAgentVersion(agent_extension)
386+
379387
handler, err := startDaemon("unix", *flagPort, flagSecurityToken.String(), flagSecuityPolicies.String())
380388
if err != nil {
381389
fmt.Fprintln(os.Stderr, err)

daemon/internal/newrelic/integration/test.go

+2
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,8 @@ var (
756756
regexp.MustCompile(`^Supportability\/InstrumentedFunction`),
757757
regexp.MustCompile(`^Supportability\/TxnData\/.*`),
758758
regexp.MustCompile(`^Supportability/C/NewrelicVersion/.*`),
759+
regexp.MustCompile(`^Supportability/PHP/Version/.*`),
760+
regexp.MustCompile(`^Supportability/PHP/AgentVersion/.*`),
759761
}
760762
)
761763

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// Copyright 2020 New Relic Corporation. All rights reserved.
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
6+
package integration
7+
8+
import (
9+
"fmt"
10+
"os/exec"
11+
)
12+
13+
func GetPHPVersion() string {
14+
cmd := exec.Command("php", "-r", "echo PHP_VERSION;")
15+
16+
output, err := cmd.Output()
17+
if err != nil {
18+
fmt.Printf("Failed to get PHP version: %v\n", err)
19+
return "failed"
20+
}
21+
22+
return string(output)
23+
}
24+
25+
func GetAgentVersion(agent_extension string) string {
26+
cmd := exec.Command("php", "-d", "extension="+agent_extension, "-r", "echo phpversion('newrelic');")
27+
28+
output, err := cmd.Output()
29+
if err != nil {
30+
return fmt.Errorf("Failed to get agent version: %v", err).Error()
31+
}
32+
return string(output)
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
<?php
3+
/*
4+
* Copyright 2020 New Relic Corporation. All rights reserved.
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
/*DESCRIPTION
9+
Verify the PHP version and agent version metrics are created properly.
10+
*/
11+
12+
/*EXPECT_METRICS_EXIST
13+
Supportability/PHP/Version/ENV[PHP_VERSION], 1
14+
Supportability/PHP/AgentVersion/ENV[AGENT_VERSION], 1
15+
*/
16+
17+
/*EXPECT_TRACED_ERRORS
18+
null
19+
*/
20+
21+
if (!extension_loaded('newrelic')) {
22+
die("fail: New Relic PHP extension is not loaded. Exiting...\n");
23+
exit;
24+
}
25+
26+
echo "PHP Version: " . phpversion() . "\n";
27+
echo "Agent Version: " . phpversion('newrelic') . "\n";

0 commit comments

Comments
 (0)