Skip to content

Commit bd4922f

Browse files
ZNeumannlavarou
andauthored
feat(agent): optionally pad agent generated trace_ids (#929)
When the agent generates trace id based on the information it received in HTTP headers, trace id will have 32 characters. However when the agent generates the trace id for internal use only, the trace id has 16 characters. This PR adds an INI setting that when set, the agent will left pad its internally used trace id with '0' so that the trace id has 32 characters. --------- Co-authored-by: Michal Nowacki <[email protected]>
1 parent e87c38a commit bd4922f

File tree

13 files changed

+204
-8
lines changed

13 files changed

+204
-8
lines changed

agent/php_newrelic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ nrinibool_t
542542
nrinibool_t
543543
distributed_tracing_exclude_newrelic_header; /* newrelic.distributed_tracing_exclude_newrelic_header
544544
*/
545+
nrinibool_t
546+
distributed_tracing_pad_trace_id; /* newrelic.distributed_tracing.pad_trace_id */
545547
nrinibool_t span_events_enabled; /* newrelic.span_events_enabled */
546548
nriniuint_t
547549
span_events_max_samples_stored; /* newrelic.span_events.max_samples_stored

agent/php_nrini.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2879,6 +2879,21 @@ STD_PHP_INI_ENTRY_EX("newrelic.distributed_tracing_exclude_newrelic_header",
28792879
newrelic_globals,
28802880
0)
28812881

2882+
/*
2883+
* This setting is not documented and affects the length of the interally used
2884+
* trace id. This INI setting should not be modified unless requested by
2885+
* customer.
2886+
*/
2887+
STD_PHP_INI_ENTRY_EX("newrelic.distributed_tracing.pad_trace_id",
2888+
"", // default is false represented as an empty string -
2889+
// see notes about PHP INI parser
2890+
NR_PHP_REQUEST,
2891+
nr_boolean_mh,
2892+
distributed_tracing_pad_trace_id,
2893+
zend_newrelic_globals,
2894+
newrelic_globals,
2895+
nr_enabled_disabled_dh)
2896+
28822897
/**
28832898
* Flag to turn the span events on/off
28842899
* When on, the agent will create span events. Span events require that

agent/php_txn.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ nr_status_t nr_php_txn_begin(const char* appnames,
748748
opts.allow_raw_exception_messages = NRINI(allow_raw_exception_messages);
749749
opts.custom_parameters_enabled = NRINI(custom_parameters_enabled);
750750
opts.distributed_tracing_enabled = NRINI(distributed_tracing_enabled);
751+
opts.distributed_tracing_pad_trace_id
752+
= NRINI(distributed_tracing_pad_trace_id);
751753
opts.distributed_tracing_exclude_newrelic_header
752754
= NRINI(distributed_tracing_exclude_newrelic_header);
753755
opts.span_events_enabled = NRINI(span_events_enabled);

agent/scripts/newrelic.ini.private.template

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,14 @@
193193
; hooks instrumented.
194194
;
195195
;newrelic.framework.wordpress.hooks_skip_filename=""
196+
197+
; Setting: newrelic.distributed_tracing.pad_trace_id
198+
; Type : bool
199+
; Scope : per-directory
200+
; Default: false
201+
; Info : If set to true, the distributed trace's id generated by the agent,
202+
; which is only meant to be used internally by New Relic, will be left
203+
; padded with '0's to have the length of 32 characters. This will increase
204+
; the amount of data sent to New Relic.
205+
;
206+
;newrelic.distributed_tracing.pad_trace_id = false

axiom/nr_distributed_trace.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,14 +481,30 @@ void nr_distributed_trace_set_app_id(nr_distributed_trace_t* dt,
481481
}
482482

483483
void nr_distributed_trace_set_trace_id(nr_distributed_trace_t* dt,
484-
const char* trace_id) {
484+
const char* trace_id,
485+
bool do_padding) {
485486
if (NULL == dt) {
486487
return;
487488
}
488489

489490
nr_free(dt->trace_id);
490491
if (trace_id) {
491-
dt->trace_id = nr_strdup(trace_id);
492+
if (nrunlikely(do_padding)) {
493+
int len = nr_strlen(trace_id);
494+
if (len < NR_TRACE_ID_MAX_SIZE) {
495+
int padding = NR_TRACE_ID_MAX_SIZE - len;
496+
char* dest = (char*)nr_malloc(NR_TRACE_ID_MAX_SIZE + 1);
497+
for (int i = 0; i < padding; i++) {
498+
dest[i] = '0';
499+
}
500+
strcpy(dest + padding, trace_id);
501+
dt->trace_id = dest;
502+
} else {
503+
dt->trace_id = nr_strdup(trace_id);
504+
}
505+
} else {
506+
dt->trace_id = nr_strdup(trace_id);
507+
}
492508
}
493509
}
494510

axiom/nr_distributed_trace.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include "util_time.h"
1313
#include "util_object.h"
1414

15+
/* This is the maximum size of trace id that the backend will accept */
16+
#define NR_TRACE_ID_MAX_SIZE 32
17+
1518
static const char NR_DISTRIBUTED_TRACE_ACCEPT_SUCCESS[]
1619
= "Supportability/DistributedTrace/AcceptPayload/Success";
1720
static const char NR_DISTRIBUTED_TRACE_ACCEPT_EXCEPTION[]
@@ -242,9 +245,12 @@ extern void nr_distributed_trace_set_app_id(nr_distributed_trace_t* dt,
242245
*
243246
* Params : 1. The distributed trace.
244247
* 2. The trace id.
248+
* 3. Bool where true indicates to left pad the trace_id
249+
* with '0's to make it NR_TRACE_ID_MAX_SIZE characters
245250
*/
246251
void nr_distributed_trace_set_trace_id(nr_distributed_trace_t* dt,
247-
const char* trace_id);
252+
const char* trace_id,
253+
bool do_padding);
248254

249255
/*
250256
* Purpose : Set the distributed trace priority.

axiom/nr_txn.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,8 @@ nrtxn_t* nr_txn_begin(nrapp_t* app,
633633
*/
634634
guid = nr_guid_create(app->rnd);
635635
nr_distributed_trace_set_txn_id(nt->distributed_trace, guid);
636-
nr_distributed_trace_set_trace_id(nt->distributed_trace, guid);
636+
nr_distributed_trace_set_trace_id(nt->distributed_trace, guid,
637+
opts->distributed_tracing_pad_trace_id);
637638

638639
nr_distributed_trace_set_trusted_key(
639640
nt->distributed_trace,

axiom/nr_txn.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ typedef struct _nrtxnopt_t {
9191

9292
int distributed_tracing_enabled; /* Whether distributed tracing functionality
9393
is enabled */
94+
bool distributed_tracing_pad_trace_id; /* whether to pad internally generated
95+
trace_id to NR_TRACE_ID_MAX_SIZE
96+
characters */
9497
bool distributed_tracing_exclude_newrelic_header; /* Whether distributed
9598
tracing outbound headers
9699
should omit newrelic

axiom/tests/test_distributed_trace.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,46 @@ static void test_distributed_trace_create_trace_parent_header(void) {
16701670
nr_free(actual);
16711671
}
16721672

1673+
static void test_distributed_trace_set_trace_id(const bool pad_trace_id) {
1674+
nr_distributed_trace_t dt = {0};
1675+
// clang-format off
1676+
const char* t_input[] = {
1677+
"", // empty string
1678+
"1234567890", // 10 characters
1679+
"1234567890abcdef", // 16 characters
1680+
"1234567890abcdef1234567890abcdef", // 32 characters
1681+
"1234567890123456789012345678901234567890123456789012345678901234567890" // 64 characters
1682+
};
1683+
const char* t_padded[] = {
1684+
"00000000000000000000000000000000", // empty string lpadded to NR_TRACE_ID_MAX_SIZE with '0'
1685+
"00000000000000000000001234567890", // 10 characters lpadded to NR_TRACE_ID_MAX_SIZE with '0'
1686+
"00000000000000001234567890abcdef", // 16 characters lpadded to NR_TRACE_ID_MAX_SIZE with '0'
1687+
"1234567890abcdef1234567890abcdef", // 32 characters - no padding done
1688+
"1234567890123456789012345678901234567890123456789012345678901234567890" // 64 characters - no padding
1689+
};
1690+
// clang-format on
1691+
1692+
/*
1693+
* Test : NULL input => no trace id generated
1694+
*/
1695+
nr_distributed_trace_set_trace_id(&dt, NULL, pad_trace_id);
1696+
tlib_pass_if_null("NULL trace id", dt.trace_id);
1697+
1698+
/*
1699+
* Test : valid input => trace id generated
1700+
*/
1701+
for (long unsigned int i = 0; i < sizeof(t_input) / sizeof(t_input[0]); i++) {
1702+
const char* expected = t_input[i];
1703+
if (pad_trace_id) {
1704+
expected = t_padded[i];
1705+
}
1706+
nr_distributed_trace_set_trace_id(&dt, t_input[i], pad_trace_id);
1707+
tlib_pass_if_not_null("trace id is set", dt.trace_id);
1708+
tlib_pass_if_str_equal("trace id has correct value", dt.trace_id, expected);
1709+
nr_free(dt.trace_id);
1710+
}
1711+
}
1712+
16731713
tlib_parallel_info_t parallel_info = {.suggested_nthreads = 2, .state_size = 0};
16741714

16751715
void test_main(void* p NRUNUSED) {
@@ -1707,4 +1747,6 @@ void test_main(void* p NRUNUSED) {
17071747

17081748
test_create_trace_state_header();
17091749
test_distributed_trace_create_trace_parent_header();
1750+
test_distributed_trace_set_trace_id(false);
1751+
test_distributed_trace_set_trace_id(true);
17101752
}

axiom/tests/test_txn.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,7 @@ static void test_begin(void) {
17051705
opts->max_segments = 0;
17061706
opts->span_queue_batch_size = 1000;
17071707
opts->span_queue_batch_timeout = 1 * NR_TIME_DIVISOR;
1708+
opts->distributed_tracing_pad_trace_id = false;
17081709

17091710
app->rnd = nr_random_create();
17101711
nr_random_seed(app->rnd, 345345);
@@ -5940,6 +5941,10 @@ static void test_create_w3c_traceparent_header(void) {
59405941

59415942
nr_memset(&txn, 0, sizeof(nrtxn_t));
59425943
txn.options.span_events_enabled = true;
5944+
// default value for padding can be used for this test, because other
5945+
// test (test_distributed_trace_create_trace_parent_header) already
5946+
// covers using trace_id of different lengths when w3c header is created.
5947+
txn.options.distributed_tracing_pad_trace_id = false;
59435948
txn.status.recording = true;
59445949
txn.rnd = nr_random_create();
59455950
txn.status.recording = 1;
@@ -5969,7 +5974,9 @@ static void test_create_w3c_traceparent_header(void) {
59695974
/*
59705975
* Test : valid string random guid
59715976
*/
5972-
nr_distributed_trace_set_trace_id(txn.distributed_trace, "meatballs!");
5977+
nr_distributed_trace_set_trace_id(
5978+
txn.distributed_trace, "meatballs!",
5979+
txn.options.distributed_tracing_pad_trace_id);
59735980
actual = nr_txn_create_w3c_traceparent_header(&txn, segment);
59745981
expected = "00-0000000000000000000000meatballs!-";
59755982
tlib_pass_if_not_null("random guid", nr_strstr(actual, expected));
@@ -6280,6 +6287,10 @@ static void test_txn_accept_distributed_trace_payload_w3c(void) {
62806287
txn.app_connect_reply = nro_new_hash();
62816288
txn.unscoped_metrics = nrm_table_create(0);
62826289
nro_set_hash_string(txn.app_connect_reply, "trusted_account_key", "123");
6290+
// default value for padding can be used for this test, because other
6291+
// test (test_distributed_trace_create_trace_parent_header) already
6292+
// covers using trace_id of different lengths when w3c header is created.
6293+
txn.options.distributed_tracing_pad_trace_id = false;
62836294

62846295
#define TEST_TXN_ACCEPT_DT_PAYLOAD_RESET \
62856296
txn.distributed_trace->inbound.set = 0; \
@@ -6725,7 +6736,9 @@ static void test_txn_accept_distributed_trace_payload_w3c(void) {
67256736
TEST_TXN_ACCEPT_DT_PAYLOAD_RESET
67266737
nr_distributed_trace_destroy(&txn.distributed_trace);
67276738
txn.distributed_trace = nr_distributed_trace_create();
6728-
nr_distributed_trace_set_trace_id(txn.distributed_trace, "35ff77");
6739+
nr_distributed_trace_set_trace_id(
6740+
txn.distributed_trace, "35ff77",
6741+
txn.options.distributed_tracing_pad_trace_id);
67296742
traceparent = nr_txn_create_w3c_traceparent_header(&txn, NULL);
67306743
nr_free(traceparent);
67316744

@@ -7525,6 +7538,7 @@ static void test_get_current_trace_id(void) {
75257538
char* trace_id;
75267539
nrtxn_t* txn;
75277540
const char* txn_id;
7541+
const char* dt_trace_id;
75287542

75297543
/* setup and start txn */
75307544
nr_memset(&app, 0, sizeof(app));
@@ -7540,7 +7554,7 @@ static void test_get_current_trace_id(void) {
75407554
nr_txn_get_current_trace_id(NULL));
75417555

75427556
/*
7543-
* Test : Correct trace id
7557+
* Test : trace id == txn_id with default pad_trace_id setting - no padding
75447558
*/
75457559
txn_id = nr_txn_get_guid(txn);
75467560
trace_id = nr_txn_get_current_trace_id(txn);
@@ -7564,6 +7578,28 @@ static void test_get_current_trace_id(void) {
75647578
nr_txn_get_current_trace_id(txn));
75657579

75667580
nr_txn_destroy(&txn);
7581+
7582+
/* setup and start txn */
7583+
nr_memset(&app, 0, sizeof(app));
7584+
nr_memset(&opts, 0, sizeof(opts));
7585+
app.state = NR_APP_OK;
7586+
opts.distributed_tracing_enabled = 1;
7587+
opts.distributed_tracing_pad_trace_id = true;
7588+
txn = nr_txn_begin(&app, &opts, NULL);
7589+
/*
7590+
* Test : trace id != txn_id with trace_id padding enabled
7591+
*/
7592+
txn_id = nr_txn_get_guid(txn);
7593+
trace_id = nr_txn_get_current_trace_id(txn);
7594+
dt_trace_id = nr_distributed_trace_get_trace_id(txn->distributed_trace);
7595+
tlib_fail_if_null("txn id", txn_id);
7596+
tlib_fail_if_str_equal("txn_id != trace_id", txn_id, trace_id);
7597+
tlib_pass_if_str_equal("txn_id = ltrim(trace_id)", txn_id,
7598+
trace_id + (nr_strlen(trace_id) - NR_GUID_SIZE));
7599+
tlib_pass_if_str_equal("trace_id = dt_trace_id", trace_id, dt_trace_id);
7600+
nr_free(trace_id);
7601+
7602+
nr_txn_destroy(&txn);
75677603
}
75687604

75697605
static void test_get_current_span_id(void) {

0 commit comments

Comments
 (0)