From 52bc28425254a04031046f7d4e9da9831bf02f7a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 14:24:13 -0700 Subject: [PATCH 01/63] feat(agent): Add nr_message_segment.o to Makefile --- axiom/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axiom/Makefile b/axiom/Makefile index 34b45c229..aef7c069c 100644 --- a/axiom/Makefile +++ b/axiom/Makefile @@ -17,7 +17,6 @@ # Useful variables: # # AR: The archiver used to build a static library (default: ar). -# CC: The C compiler to use (default: gcc). # CFLAGS: Flags to give the C compiler when building object files. # @@ -113,6 +112,7 @@ OBJS := \ nr_segment_children.o \ nr_segment_datastore.o \ nr_segment_external.o \ + nr_segment_message.o \ nr_segment_private.o \ nr_segment_terms.o \ nr_segment_traces.o \ From 11d5f20e7d7154c2b2fc3a64ce0c30583d9e95e9 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:23:21 -0700 Subject: [PATCH 02/63] feat(agent): Add message segment to enums, unions, structs Set segment type enum Create nr_segment_message_t struct Add to the nr_segment_typed_attributes_t union --- axiom/nr_segment.h | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 56d972579..b708c5274 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -34,7 +34,8 @@ typedef struct _nrtxn_t nrtxn_t; typedef enum _nr_segment_type_t { NR_SEGMENT_CUSTOM, NR_SEGMENT_DATASTORE, - NR_SEGMENT_EXTERNAL + NR_SEGMENT_EXTERNAL, + NR_SEGMENT_MESSAGE } nr_segment_type_t; /* @@ -109,6 +110,16 @@ typedef struct _nr_segment_external_t { uint64_t status; } nr_segment_external_t; +typedef struct _nr_segment_message_t { + char* transaction_guid; + char* action; /* MUST be one of: produce, consume */ + char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ + char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary + Topic, Exchange */ + uint64_t destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp */ +} nr_segment_message_t; + typedef struct _nr_segment_metric_t { char* name; bool scoped; @@ -132,6 +143,7 @@ typedef struct _nr_segment_error_t { typedef union { nr_segment_datastore_t datastore; nr_segment_external_t external; + nr_segment_message_t message; } nr_segment_typed_attributes_t; typedef struct _nr_segment_t { @@ -179,8 +191,8 @@ typedef struct _nr_segment_t { int priority; /* Used to determine which segments are preferred for span event creation */ nr_segment_typed_attributes_t* typed_attributes; /* Attributes specific to - external or datastore - segments. */ + external, datastore, + or message segments. */ nr_segment_error_t* error; /* segment error attributes */ #if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \ && !defined OVERWRITE_ZEND_EXECUTE_DATA /* PHP 8.0+ and OAPI */ @@ -314,6 +326,17 @@ extern bool nr_segment_set_datastore(nr_segment_t* segment, */ extern bool nr_segment_set_external(nr_segment_t* segment, const nr_segment_external_t* external); + +/* + * Purpose : Mark the segment as being a message segment. + * + * Params : 1. The pointer to the segment. + * 2. The message attributes, which will be copied into the segment. + * + * Returns : true if successful, false otherwise. + */ +extern bool nr_segment_set_message(nr_segment_t* segment, + const nr_segment_message_t* message); /* * Purpose : Add a child to a segment. * From a4effd7a8143c9b64e572159767bfdef731e59dd Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:41:05 -0700 Subject: [PATCH 03/63] fix(agent): typo --- axiom/nr_segment.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index b708c5274..780f04a15 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -111,12 +111,11 @@ typedef struct _nr_segment_external_t { } nr_segment_external_t; typedef struct _nr_segment_message_t { - char* transaction_guid; char* action; /* MUST be one of: produce, consume */ char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary Topic, Exchange */ - uint64_t destination_name; /* The name of the Queue, Topic, or Exchange; + char* destination_name; /* The name of the Queue, Topic, or Exchange; otherwise, Temp */ } nr_segment_message_t; From 892400303dbdc636e8a262e3e040a8d44587f955 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:57:13 -0700 Subject: [PATCH 04/63] feat(agent): Destroy Message Segment metadata --- axiom/nr_segment_private.c | 13 +++++++++++++ axiom/nr_segment_private.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index a60865afd..4a9629d18 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -39,6 +39,17 @@ void nr_segment_external_destroy_fields(nr_segment_external_t* external) { nr_free(external->procedure); } +void nr_segment_message_destroy_fields(nr_segment_message_t* message) { + if (nrunlikely(NULL == message)) { + return; + } + + nr_free(message->action); + nr_free(message->library); + nr_free(message->destination_type); + nr_free(message->destination_name); +} + void nr_segment_destroy_typed_attributes( nr_segment_type_t type, nr_segment_typed_attributes_t** attributes) { @@ -54,6 +65,8 @@ void nr_segment_destroy_typed_attributes( nr_segment_datastore_destroy_fields(&attrs->datastore); } else if (NR_SEGMENT_EXTERNAL == type) { nr_segment_external_destroy_fields(&attrs->external); + } else if (NR_SEGMENT_MESSAGE == type) { + nr_segment_message_destroy_fields(&attrs->external); } nr_free(attrs); diff --git a/axiom/nr_segment_private.h b/axiom/nr_segment_private.h index 70b499795..b2d6fe2c4 100644 --- a/axiom/nr_segment_private.h +++ b/axiom/nr_segment_private.h @@ -33,6 +33,13 @@ void nr_segment_datastore_destroy_fields(nr_segment_datastore_t* datastore); */ void nr_segment_external_destroy_fields(nr_segment_external_t* external); +/* + * Purpose : Free all data related to a segment's message metadata. + * + * Params : 1. A pointer to a segment's nr_segment_message_t structure. + */ +void nr_segment_message_destroy_fields(nr_segment_message_t* message); + /* * Purpose : Free all data related to a segment metric. * From 5402097b813413acfba4c61f9c9b69873a7de950 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 19:32:17 -0700 Subject: [PATCH 05/63] feat(agent): Add message typed attributes to a hash in the buffer --- axiom/nr_segment_traces.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index 846d89a55..ecde6173e 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -162,6 +162,15 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, ext->transaction_guid, false); add_hash_key_value_to_buffer_int(buf, "status", &ext->status); } break; + case NR_SEGMENT_MESSAGE: { + const nr_segment_message_t* message = &segment->typed_attributes->message; + add_hash_key_value_to_buffer(buf, "action", message->action, false); + add_hash_key_value_to_buffer(buf, "library", message->library, false); + add_hash_key_value_to_buffer(buf, "destination_type", + message->destination_type, false); + add_hash_key_value_to_buffer(buf, "destination_name", + message->destination_name, false); + } break; case NR_SEGMENT_CUSTOM: default: break; From 21217c3d400cc3c1f0d623541040dc23c2ac0790 Mon Sep 17 00:00:00 2001 From: ZNeumann Date: Wed, 30 Oct 2024 13:23:34 -0600 Subject: [PATCH 06/63] feat(agent): add message parameters ini (#981) --- agent/php_newrelic.h | 6 ++++++ agent/php_nrini.c | 11 +++++++++++ agent/scripts/newrelic.ini.template | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/agent/php_newrelic.h b/agent/php_newrelic.h index 1860b5167..6afaf531a 100644 --- a/agent/php_newrelic.h +++ b/agent/php_newrelic.h @@ -596,6 +596,12 @@ nrinibool_t nrinibool_t vulnerability_management_composer_api_enabled; /* newrelic.vulnerability_management.composer_api.enabled */ +/* + * Configuration options for recording Messaging APIs + */ +nrinibool_t + message_tracer_segment_parameters_enabled; /* newrelic.segment_tracer.segment_parameters.enabled */ + #if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO /* * pid and user_function_wrappers are used to store user function wrappers. diff --git a/agent/php_nrini.c b/agent/php_nrini.c index 6c21d1bdf..4a2f7c471 100644 --- a/agent/php_nrini.c +++ b/agent/php_nrini.c @@ -3100,6 +3100,17 @@ STD_PHP_INI_ENTRY_EX("newrelic.vulnerability_management.composer_api.enabled", newrelic_globals, nr_enabled_disabled_dh) +/* + * Messaging API + */ +STD_PHP_INI_ENTRY_EX("newrelic.message_tracer.segment_parameters.enabled", + "1", + NR_PHP_REQUEST, + nr_boolean_mh, + message_tracer_segment_parameters_enabled, + zend_newrelic_globals, + newrelic_globals, + nr_enabled_disabled_dh) PHP_INI_END() /* } */ void nr_php_register_ini_entries(int module_number TSRMLS_DC) { diff --git a/agent/scripts/newrelic.ini.template b/agent/scripts/newrelic.ini.template index 4ed06a091..b406628a9 100644 --- a/agent/scripts/newrelic.ini.template +++ b/agent/scripts/newrelic.ini.template @@ -1341,3 +1341,14 @@ newrelic.daemon.logfile = "/var/log/newrelic/newrelic-daemon.log" ; to gather package information for vulnerability management. ; ;newrelic.vulnerability_management.composer_api.enabled = false + +; Setting: newrelic.message_tracer.segment_parameters.enabled +; Type : boolean +; Scope : per-directory +; Default: true +; Info : If this setting is true, then message parameters will be captured and +; stored on their respective segments. While enabled, specific attributes +; can be filtered by using newrelic.attributes.include/exclude and +; newrelic.span_events.attributes.include/exclude +; +;newrelic.message_tracer.segment_parameters.enabled = true From 1dda889da1b20356bd4ce33062e2c130d1c85316 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 26 Nov 2024 10:37:41 -0700 Subject: [PATCH 07/63] feat(agent): Add entity relationship building attributes to message segment. --- axiom/nr_segment.h | 27 +++++++++++++++++++++------ axiom/nr_segment_private.c | 8 +++++--- axiom/nr_segment_traces.c | 14 ++++++++++---- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 780f04a15..ab07993e3 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -111,12 +111,27 @@ typedef struct _nr_segment_external_t { } nr_segment_external_t; typedef struct _nr_segment_message_t { - char* action; /* MUST be one of: produce, consume */ - char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ - char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary - Topic, Exchange */ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp */ + /* + * Attributes needed for entity relationship building. + * Compare to OTEL attributes: + * https://opentelemetry.io/docs/specs/semconv/attributes-registry/cloud/ + * cloud.account.id, cloud.region, messaging.system and server.address are + * used to create relationships between APM and cloud services. It may not + * make sense to add these attributes unless they are used for creating one of + * the relationships in Entity Relationships. + */ + + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ + char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS + relationship.*/ + char* cloud_account_id; /*The cloud provider account ID. Needed for SQS + relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ + char* server_address; /* the server domain name or IP address. Needed for + MQBROKER relationship.*/ + } nr_segment_message_t; typedef struct _nr_segment_metric_t { diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index 4a9629d18..7b574006f 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -44,10 +44,12 @@ void nr_segment_message_destroy_fields(nr_segment_message_t* message) { return; } - nr_free(message->action); - nr_free(message->library); - nr_free(message->destination_type); nr_free(message->destination_name); + nr_free(message->messaging_system); + nr_free(message->cloud_region); + nr_free(message->cloud_account_id); + nr_free(message->cloud_resource_id); + nr_free(message->server_address); } void nr_segment_destroy_typed_attributes( diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index ecde6173e..b5b370d06 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -164,12 +164,18 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, } break; case NR_SEGMENT_MESSAGE: { const nr_segment_message_t* message = &segment->typed_attributes->message; - add_hash_key_value_to_buffer(buf, "action", message->action, false); - add_hash_key_value_to_buffer(buf, "library", message->library, false); - add_hash_key_value_to_buffer(buf, "destination_type", - message->destination_type, false); add_hash_key_value_to_buffer(buf, "destination_name", message->destination_name, false); + add_hash_key_value_to_buffer(buf, "messaging_system", + message->messaging_system, false); + add_hash_key_value_to_buffer(buf, "cloud_region", message->cloud_region, + false); + add_hash_key_value_to_buffer(buf, "cloud_account_id", + message->cloud_account_id, false); + add_hash_key_value_to_buffer(buf, "cloud_resource_id", + message->cloud_resource_id, false); + add_hash_key_value_to_buffer(buf, "server_address", + message->server_address, false); } break; case NR_SEGMENT_CUSTOM: default: From d47ff537a25639c611f2cc30217d3c6e4b0ac32e Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 2 Dec 2024 07:14:12 -0700 Subject: [PATCH 08/63] feat(agent): Add message attribute functionality for message spans * Create enums for message attributes attributes * Add MESSAGE enum to nr_span_category_t span category * create nr_span_event_set_message --- axiom/nr_span_event.c | 29 +++++++++++++++++++++++++++++ axiom/nr_span_event.h | 27 ++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 965b297d9..58d8ab231 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -328,6 +328,35 @@ void nr_span_event_set_external_status(nr_span_event_t* event, nro_set_hash_ulong(event->agent_attributes, "http.statusCode", status); } +void nr_span_event_set_message(nr_span_event_t* event, + nr_span_event_message_member_t member, + const char* new_value) { + if (NULL == event || NULL == new_value) { + return; + } + + switch (member) { + case NR_SPAN_MESSAGE_DESTINATION_NAME: + nro_set_hash_string(event->agent_attributes, "messaging.destination.name", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_REGION: + nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: + nro_set_hash_string(event->intrinsics, "cloud.account.id", new_value); + break; + case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: + nro_set_hash_string(event->agent_attributes, "messaging.system", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: + nro_set_hash_string(event->agent_attributes, "cloud.resource_id", new_value); + break; + case NR_SPAN_MESSAGE_SERVER_ADDRESS: + nro_set_hash_string(event->intrinsics, "server.address", new_value); + break; + } +} + /* * Getters. * diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 74ee2119c..37c9873e4 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -21,7 +21,8 @@ typedef struct _nr_span_event_t nr_span_event_t; typedef enum { NR_SPAN_GENERIC, NR_SPAN_HTTP, - NR_SPAN_DATASTORE + NR_SPAN_DATASTORE, + NR_SPAN_MESSAGE } nr_span_category_t; /* @@ -44,6 +45,18 @@ typedef enum { NR_SPAN_EXTERNAL_METHOD } nr_span_event_external_member_t; +/* + * Fields that can be set on message spans. + */ +typedef enum { + NR_SPAN_MESSAGE_DESTINATION_NAME, + NR_SPAN_MESSAGE_CLOUD_REGION, + NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, + NR_SPAN_MESSAGE_MESSAGING_SYSTEM, + NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + NR_SPAN_MESSAGE_SERVER_ADDRESS +} nr_span_event_message_member_t; + /* * The parent attributes that can be set on service entry spans. * parent.transportDuration is set in @@ -170,6 +183,18 @@ extern void nr_span_event_set_external(nr_span_event_t* event, extern void nr_span_event_set_external_status(nr_span_event_t* event, const uint64_t status); +/* + * Purpose : Set a message attribute. + * + * Params : 1. The target Span Event that should be changed. + * 2. The message attribute to be set. + * 3. The string value that the field will be after the function has + * executed. + */ +extern void nr_span_event_set_message(nr_span_event_t* event, + nr_span_event_message_member_t member, + const char* new_value); + /* * Purpose : Set a user attribute. * From 149064c2a915e751676086474245cae5e376352e Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 3 Dec 2024 14:41:41 -0700 Subject: [PATCH 09/63] feat(agent): Add nr_span_event_set_spankind create `nr_span_event_set_spankind` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for generic,http,datastore the logic of nr_span_event_set_category is overloaded because according agent-specs/Span-Events.md, span.kind could only ever be “client” for datastore and http spans and empty for generic spans. I debated extracting all the logic and making nr_span_event_set_spankind calls for those categories in nr_segment.c; however, since the span.kind values are always the same for those span categories, I left it in for now. Message spans however, will call nr_span_event_set_spankind separately and nr_span_event_set_category will only be used to set the category. --- axiom/nr_span_event.c | 50 +++++++++++++++++++++++++++++++++---------- axiom/nr_span_event.h | 22 +++++++++++++++++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 58d8ab231..df9cdc494 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -141,20 +141,45 @@ void nr_span_event_set_category(nr_span_event_t* event, switch (category) { case NR_SPAN_DATASTORE: nro_set_hash_string(event->intrinsics, "category", "datastore"); - nro_set_hash_string(event->intrinsics, "span.kind", "client"); + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); break; case NR_SPAN_GENERIC: nro_set_hash_string(event->intrinsics, "category", "generic"); - if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { - nro_set_hash_none(event->intrinsics, "span.kind"); - } - break; + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND) break; case NR_SPAN_HTTP: nro_set_hash_string(event->intrinsics, "category", "http"); + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + break; + + case NR_SPAN_MESSAGE: + nro_set_hash_string(event->intrinsics, "category", "message"); + break; + } +} + +void nr_span_event_set_spankind(nr_span_event_t* event, + nr_span_spankind_t spankind) { + if (NULL == event) { + return; + } + + switch (spankind) { + case NR_SPAN_PRODUCER: + nro_set_hash_string(event->intrinsics, "span.kind", "producer"); + break; + case NR_SPAN_CLIENT: nro_set_hash_string(event->intrinsics, "span.kind", "client"); break; + case NR_SPAN_CONSUMER: + nro_set_hash_string(event->intrinsics, "span.kind", "consumer"); + break; + case NR_SPAN_NO_SPANKIND: + if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { + nro_set_hash_none(event->intrinsics, "span.kind"); + } + break; } } @@ -329,15 +354,16 @@ void nr_span_event_set_external_status(nr_span_event_t* event, } void nr_span_event_set_message(nr_span_event_t* event, - nr_span_event_message_member_t member, - const char* new_value) { + nr_span_event_message_member_t member, + const char* new_value) { if (NULL == event || NULL == new_value) { return; } switch (member) { case NR_SPAN_MESSAGE_DESTINATION_NAME: - nro_set_hash_string(event->agent_attributes, "messaging.destination.name", new_value); + nro_set_hash_string(event->agent_attributes, "messaging.destination.name", + new_value); break; case NR_SPAN_MESSAGE_CLOUD_REGION: nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); @@ -346,12 +372,14 @@ void nr_span_event_set_message(nr_span_event_t* event, nro_set_hash_string(event->intrinsics, "cloud.account.id", new_value); break; case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: - nro_set_hash_string(event->agent_attributes, "messaging.system", new_value); + nro_set_hash_string(event->agent_attributes, "messaging.system", + new_value); break; case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: - nro_set_hash_string(event->agent_attributes, "cloud.resource_id", new_value); + nro_set_hash_string(event->agent_attributes, "cloud.resource_id", + new_value); break; - case NR_SPAN_MESSAGE_SERVER_ADDRESS: + case NR_SPAN_MESSAGE_SERVER_ADDRESS: nro_set_hash_string(event->intrinsics, "server.address", new_value); break; } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 37c9873e4..2ce236537 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -25,6 +25,26 @@ typedef enum { NR_SPAN_MESSAGE } nr_span_category_t; +/* + * The spankinds a span may fall into. + * This is set according to: + * 1) guidelines in agent-specs which state datastore and http spans set + * span.kind to client and further states that generic span.kind is unset + * + * 2) for message spans follow guidance here: + * https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/ + * which states that span.kind is + * a) producer when the operation type is create or send(if the context is + * create) b) client when the operation type is create or send(if the context is + * NOT create) c) consumer when the operation type is process + */ +typedef enum { + NR_SPAN_PRODUCER, + NR_SPAN_CLIENT, + NR_SPAN_CONSUMER, + NR_SPAN_NO_SPANKIND +} nr_span_spankind_t; + /* * Fields that can be set on datastore spans. */ @@ -128,6 +148,8 @@ extern void nr_span_event_set_transaction_name(nr_span_event_t* event, const char* transaction_name); extern void nr_span_event_set_category(nr_span_event_t* event, nr_span_category_t category); +extern void nr_span_event_set_category(nr_span_event_t* event, + nr_span_category_t category); extern void nr_span_event_set_timestamp(nr_span_event_t* event, nrtime_t time); extern void nr_span_event_set_duration(nr_span_event_t* event, nrtime_t duration); From 870830edb5746a1ce55fd1f814196f11c99ffc89 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 3 Dec 2024 15:53:39 -0700 Subject: [PATCH 10/63] feat(agent): Add span handling for message segments add message_type to nr_segment_message_t to inform the spankind since message_type is on nr_segment_message_t, give a default in case the message span is created but the nr_segment_message_t is not accessible added function nr_populate_message_spans added function nr_segment_set_message added message segment handling to nr_segment_to_span_event --- axiom/nr_segment.c | 64 +++++++++++++++++++++++++++++++++++++++++-- axiom/nr_segment.h | 5 ++-- axiom/nr_span_event.c | 2 ++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index fa91cf1b7..294839343 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -313,6 +313,35 @@ static void nr_populate_http_spans(nr_span_event_t* span_event, segment->typed_attributes->external.status); } +static void nr_populate_message_spans(nr_span_event_t* span_event, + const nr_segment_t* segment) { + nr_span_event_set_category(span_event, NR_SPAN_MESSAGE); + + if (nrunlikely(NULL == segment || NULL == segment->typed_attributes)) { + return; + } + + nr_span_event_set_spankind(span_event, + segment->typed_attributes->message_type); + + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_DESTINATION_NAME, + segment->typed_attributes->message.destination_name); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, + segment->typed_attributes->message.messaging_system); + nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION, + segment->typed_attributes->message.cloud_region); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, + segment->typed_attributes->message.cloud_account_id); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + segment->typed_attributes->message.cloud_resource_id); + nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS, + segment->typed_attributes->message.server_address); +} + static nr_status_t add_user_attribute_to_span_event(const char* key, const nrobj_t* val, void* ptr) { @@ -431,8 +460,8 @@ nr_span_event_t* nr_segment_to_span_event(nr_segment_t* segment) { nr_span_event_set_trusted_parent_id( event, nr_distributed_trace_inbound_get_trusted_parent_id( segment->txn->distributed_trace)); - nr_span_event_set_parent_id(event, - nr_distributed_trace_inbound_get_guid(segment->txn->distributed_trace)); + nr_span_event_set_parent_id(event, nr_distributed_trace_inbound_get_guid( + segment->txn->distributed_trace)); nr_span_event_set_transaction_name(event, segment->txn->name); @@ -482,6 +511,10 @@ nr_span_event_t* nr_segment_to_span_event(nr_segment_t* segment) { nr_populate_http_spans(event, segment); break; + case NR_SEGMENT_MESSAGE: + nr_populate_message_spans(event, segment); + break; + case NR_SEGMENT_CUSTOM: nr_span_event_set_category(event, NR_SPAN_GENERIC); break; @@ -599,6 +632,33 @@ bool nr_segment_set_external(nr_segment_t* segment, return true; } +bool nr_segment_set_message(nr_segment_t* segment, + const nr_segment_external_t* message) { + if (nrunlikely((NULL == segment) || (NULL == message))) { + return false; + } + + nr_segment_destroy_typed_attributes(segment->type, + &segment->typed_attributes); + segment->type = NR_SEGMENT_MESSAGE; + segment->typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + + // clang-format off + // Initialize the fields of the message attributes, one field per line. + segment->typed_attributes->message = (nr_segment_message_t){ + .message_type = message->message_type, + .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, + .destination_name = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, + .destination_name = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, + .destination_name = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, + .destination_name = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, + .destination_name = message->server_address ? nr_strdup(message->server_address) : NULL, + }; + // clang-format on + + return true; +} + bool nr_segment_add_child(nr_segment_t* parent, nr_segment_t* child) { if (nrunlikely((NULL == parent) || (NULL == child))) { return false; diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index ab07993e3..19b078d97 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -121,8 +121,9 @@ typedef struct _nr_segment_message_t { * the relationships in Entity Relationships. */ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + nr_span_spankind_t message_type; /*The type of message, producer/consumer.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index df9cdc494..ada4538dd 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -155,6 +155,8 @@ void nr_span_event_set_category(nr_span_event_t* event, case NR_SPAN_MESSAGE: nro_set_hash_string(event->intrinsics, "category", "message"); + /* give it a default value in case we exit before spankind is set*/ + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); break; } } From 76b66b0f4b4b392545fdbd3823e5c441fa545e97 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 5 Dec 2024 15:56:50 -0700 Subject: [PATCH 11/63] feat(agent): Add new ini value to opts so axiom can see it Add the message_tracer_segment_parameters_enabled value to opts for use in axiom. --- agent/php_txn.c | 4 +++- axiom/nr_txn.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/agent/php_txn.c b/agent/php_txn.c index b5b57975c..bc0ea6b7e 100644 --- a/agent/php_txn.c +++ b/agent/php_txn.c @@ -854,6 +854,8 @@ nr_status_t nr_php_txn_begin(const char* appnames, opts.log_forwarding_log_level = NRINI(log_forwarding_log_level); opts.log_events_max_samples_stored = NRINI(log_events_max_samples_stored); opts.log_metrics_enabled = NRINI(log_metrics_enabled); + opts.message_tracer_segment_parameters_enabled + = NRINI(message_tracer_segment_parameters_enabled); /* * Enable the behaviour whereby asynchronous time is discounted from the total @@ -1165,7 +1167,7 @@ nr_status_t nr_php_txn_end(int ignoretxn, int in_post_deactivate TSRMLS_DC) { #if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \ && !defined OVERWRITE_ZEND_EXECUTE_DATA nr_segment_t* segment = nr_txn_get_current_segment(NRPRG(txn), NULL); - while(NULL != segment && segment != NRTXN(segment_root)) { + while (NULL != segment && segment != NRTXN(segment_root)) { nr_segment_end(&segment); segment = nr_txn_get_current_segment(NRPRG(txn), NULL); } diff --git a/axiom/nr_txn.h b/axiom/nr_txn.h index 8874260ec..55871f1b1 100644 --- a/axiom/nr_txn.h +++ b/axiom/nr_txn.h @@ -132,6 +132,8 @@ typedef struct _nrtxnopt_t { size_t log_events_max_samples_stored; /* The maximum number of log events per transaction */ bool log_metrics_enabled; /* Whether log metrics are enabled */ + bool message_tracer_segment_parameters_enabled; /* Determines whether to add + message attr */ } nrtxnopt_t; typedef enum _nrtxnstatus_cross_process_t { From 8d9d949f4c4128dd9a6c876d01a32865668545e3 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 5 Dec 2024 19:00:18 -0700 Subject: [PATCH 12/63] feat(axiom): Add nr_segment_message functionality Includes creating metrics and ending the message segment. --- axiom/nr_segment.c | 17 ++- axiom/nr_segment.h | 7 +- axiom/nr_segment_message.c | 223 +++++++++++++++++++++++++++++++++++++ axiom/nr_segment_message.h | 59 ++++++++++ axiom/nr_segment_private.c | 2 +- axiom/nr_span_event.c | 4 +- axiom/nr_span_event.h | 6 +- 7 files changed, 301 insertions(+), 17 deletions(-) create mode 100644 axiom/nr_segment_message.c create mode 100644 axiom/nr_segment_message.h diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index 294839343..9a7dba1c9 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -322,8 +322,7 @@ static void nr_populate_message_spans(nr_span_event_t* span_event, } nr_span_event_set_spankind(span_event, - segment->typed_attributes->message_type); - + segment->typed_attributes->message.message_action); nr_span_event_set_message( span_event, NR_SPAN_MESSAGE_DESTINATION_NAME, segment->typed_attributes->message.destination_name); @@ -633,7 +632,7 @@ bool nr_segment_set_external(nr_segment_t* segment, } bool nr_segment_set_message(nr_segment_t* segment, - const nr_segment_external_t* message) { + const nr_segment_message_t* message) { if (nrunlikely((NULL == segment) || (NULL == message))) { return false; } @@ -646,13 +645,13 @@ bool nr_segment_set_message(nr_segment_t* segment, // clang-format off // Initialize the fields of the message attributes, one field per line. segment->typed_attributes->message = (nr_segment_message_t){ - .message_type = message->message_type, + .message_action = message->message_action, .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, - .destination_name = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, - .destination_name = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, - .destination_name = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, - .destination_name = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, - .destination_name = message->server_address ? nr_strdup(message->server_address) : NULL, + .cloud_region = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, + .cloud_account_id = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, + .messaging_system = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, + .cloud_resource_id = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, + .server_address = message->server_address ? nr_strdup(message->server_address) : NULL, }; // clang-format on diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 19b078d97..66b53ce5e 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -121,9 +121,10 @@ typedef struct _nr_segment_message_t { * the relationships in Entity Relationships. */ - nr_span_spankind_t message_type; /*The type of message, producer/consumer.*/ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + nr_span_spankind_t + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c new file mode 100644 index 000000000..6efcd1072 --- /dev/null +++ b/axiom/nr_segment_message.c @@ -0,0 +1,223 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nr_axiom.h" + +#include + +#include "nr_header.h" +#include "nr_segment_message.h" +#include "nr_segment_private.h" +#include "util_strings.h" +#include "util_url.h" + +/* + * Purpose : Set all the typed message attributes on the segment. + */ +static void nr_segment_message_set_attrs( + nr_segment_t* segment, + const nr_segment_message_params_t* params, + nrtxnopt_t options) { + nr_segment_message_t message_attributes = {0}; + + message_attributes.message_action = params->message_action; + + if (options.message_tracer_segment_parameters_enabled) { + message_attributes.destination_name = params->destination_name; + message_attributes.cloud_region = params->cloud_region; + message_attributes.cloud_account_id = params->cloud_account_id; + message_attributes.messaging_system = params->messaging_system; + message_attributes.cloud_resource_id = params->cloud_resource_id; + message_attributes.server_address = params->server_address; + } + + nr_segment_set_message(segment, &message_attributes); +} + +/* + * Purpose : Create metrics for a completed message call and set the segment + * name. + * + * Metrics created during this call + * ---------------------------------------------------------------------------------- + * MessageBroker/all Unscoped + * Always MessageBroker/{library}/all Scoped Always + * + * Metrics created based on MessageBroker/all (in nr_txn_create_rollup_metrics) + * ---------------------------------------------------------------------------------- + * MessageBroker/allWeb Unscoped Web + * MessageBroker/allOther Unscoped + * non-Web + * + * Segment name + * ----------------------------------------------------------------------------------- + * MessageBroker/{library}/all Always + * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * + * + * These metrics are dictated by the spec located here: + * https://source.datanerd.us/agents/agent-specs/blob/master/APIs/messaging.md#metrics + * When the destination is temporary (such as a temporary queue, or a temporary + * topic), the destination name MUST be omitted. The metric segment 'Named' MUST + * be replaced with 'Temp'. The DestinationType segment SHOULD NOT contain + * "Temporary". Thus, "Temporary " should be removed from the destination type + * enum before metric use. Examples: MessageBroker/JMS/Queue/Produce/Temp, + * MessageBroker/JMS/Topic/Produce/Temp + * + * Further note that for pull-style messaging, the transaction segment name MUST + * be equal to the scoped metric name (e.g., + * MessageBroker/JMS/Queue/Produce/Named/SortQueue) + * + * + * Params : 1. The message segment. + * 2. Message parameters + * 3. Duration of the segment + * + * Returns : the scoped metric that was created. Caller is responsible for + * freeing this value. + */ + +static char* nr_segment_message_create_metrics( + nr_segment_t* segment, + const nr_segment_message_params_t* message_params, + nrtime_t duration) { + const char* action_string = NULL; + const char* destination_type_string = NULL; + char* rollup_metric = NULL; + char* scoped_metric = NULL; + + if (NULL == segment) { + return NULL; + } + + if (NULL == message_params || NULL == message_params->library) { + return NULL; + } + + /* Rollup metric. + * + * This has to be created on the transaction in order to create + * MessageBroker/allWeb and MessageBroker/allOther and to calculate + * messageDuration later on. + */ + + nrm_force_add(segment->txn->unscoped_metrics, "MessageBroker/all", duration); + + rollup_metric = nr_formatf("MessageBroker/%s/all", message_params->library); + nrm_force_add(segment->txn->unscoped_metrics, rollup_metric, duration); + nr_free(rollup_metric); + + /* + * Note: although the concept of Temporary queues/topics is detailed in the + * spec, in practice, we are unlikely to encounter it as it is currently only + * meaningful with JMS (Java Message Service). It is added here for adherence + * with spec. + */ + + if (NR_SPAN_PRODUCER == message_params->message_action) { + action_string = "Produce"; + } else if (NR_SPAN_CONSUMER == message_params->message_action) { + action_string = "Consume"; + } else { + action_string = "Unknown"; + } + + switch (message_params->destination_type) { + case NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE: + case NR_MESSAGE_DESTINATION_TYPE_QUEUE: + destination_type_string = "Queue"; + break; + case NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC: + case NR_MESSAGE_DESTINATION_TYPE_TOPIC: + destination_type_string = "Topic"; + break; + case NR_MESSAGE_DESTINATION_TYPE_EXCHANGE: + destination_type_string = "Exchange"; + break; + default: + destination_type_string = "Unknown"; + break; + } + /* + * Create the scoped metric + * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + */ + if (NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE == message_params->destination_type + || NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC + == message_params->destination_type) { + scoped_metric + = nr_formatf("MessageBroker/%s/%s/%s/Temp", message_params->library, + destination_type_string, action_string); + } else { + scoped_metric = nr_formatf( + "MessageBroker/%s/%s/%s/Named/%s", message_params->library, + destination_type_string, action_string, + message_params->destination_name ? message_params->destination_name + : "Unknown"); + } + + nr_segment_add_metric(segment, scoped_metric, true); + + /* + * The scoped metric will be used as the segment name. + */ + return scoped_metric; +} + +bool nr_segment_message_end(nr_segment_t** segment_ptr, + const nr_segment_message_params_t* message_params) { + bool rv = false; + nr_segment_t* segment; + nrtime_t duration = 0; + char* scoped_metric = NULL; + + if (NULL == segment_ptr) { + return false; + } + + segment = *segment_ptr; + + if (NULL == segment || NULL == message_params || NULL == segment->txn) { + return false; + } + + /* + * We don't want message segments to have any children, as + * this would scramble the exclusive time calculation. + * Additionally, because it makes http calls under the hood, + * we don't want additional external calls created for this same txn. + * Therefore, we delete all children of the message segment. + */ + if (segment) { + for (size_t i = 0; i < nr_segment_children_size(&segment->children); i++) { + nr_segment_t* child = nr_segment_children_get(&segment->children, i); + nr_segment_discard(&child); + } + } + + nr_segment_message_set_attrs(segment, message_params, segment->txn->options); + + /* + * We set the end time here because we need the duration, (nr_segment_end will + * not overwrite this value if it's already set). + */ + if (!segment->stop_time) { + segment->stop_time + = nr_time_duration(nr_txn_start_time(segment->txn), nr_get_time()); + } + duration = nr_time_duration(segment->start_time, segment->stop_time); + + scoped_metric + = nr_segment_message_create_metrics(segment, message_params, duration); + nr_segment_set_name(segment, scoped_metric); + + rv = nr_segment_end(&segment); + + nr_free(scoped_metric); + + return rv; +} diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h new file mode 100644 index 000000000..d6b38b8ee --- /dev/null +++ b/axiom/nr_segment_message.h @@ -0,0 +1,59 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NR_SEGMENT_MESSAGE_HDR +#define NR_SEGMENT_MESSAGE_HDR + +#include "nr_segment.h" + +/* + * Note: + * CAT is EOLed and this feature is not compatible with CAT. + */ + +typedef enum _nr_segment_message_destination_type_t { + NR_MESSAGE_DESTINATION_TYPE_QUEUE, + NR_MESSAGE_DESTINATION_TYPE_TOPIC, + NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, + NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, + NR_MESSAGE_DESTINATION_TYPE_EXCHANGE +} nr_segment_message_destination_type_t; + +typedef struct { + /* All strings are null-terminated. When unset, the strings are ingored. */ + + /* Only used for creating metrics. */ + + char* library; /* Library; Possible values are SQS, SNS, RabbitMQ, JMS */ + nr_segment_message_destination_type_t + destination_type; /* Named/temp queue/topic/exchange */ + + /* Used for creating message attributes. */ + nr_span_spankind_t + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ + char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS + relationship.*/ + char* cloud_account_id; /*The cloud provider account ID. Needed for SQS + relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ + char* server_address; /* the server domain name or IP address. Needed for + MQBROKER relationship.*/ + +} nr_segment_message_params_t; + +/* + * Purpose : End a message segment and record metrics. + * + * Params : 1. nr_segment_message_params_t + * + * Returns: true on success. + */ +extern bool nr_segment_message_end(nr_segment_t** segment, + const nr_segment_message_params_t* params); + +#endif diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index 7b574006f..283ec0067 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -68,7 +68,7 @@ void nr_segment_destroy_typed_attributes( } else if (NR_SEGMENT_EXTERNAL == type) { nr_segment_external_destroy_fields(&attrs->external); } else if (NR_SEGMENT_MESSAGE == type) { - nr_segment_message_destroy_fields(&attrs->external); + nr_segment_message_destroy_fields(&attrs->message); } nr_free(attrs); diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index ada4538dd..0190349fa 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -146,7 +146,8 @@ void nr_span_event_set_category(nr_span_event_t* event, case NR_SPAN_GENERIC: nro_set_hash_string(event->intrinsics, "category", "generic"); - nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND) break; + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + break; case NR_SPAN_HTTP: nro_set_hash_string(event->intrinsics, "category", "http"); @@ -178,6 +179,7 @@ void nr_span_event_set_spankind(nr_span_event_t* event, nro_set_hash_string(event->intrinsics, "span.kind", "consumer"); break; case NR_SPAN_NO_SPANKIND: + default: if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { nro_set_hash_none(event->intrinsics, "span.kind"); } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 2ce236537..16020b7b0 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -29,7 +29,7 @@ typedef enum { * The spankinds a span may fall into. * This is set according to: * 1) guidelines in agent-specs which state datastore and http spans set - * span.kind to client and further states that generic span.kind is unset + * span.kind to client and further states that generic span.kind is unset * * 2) for message spans follow guidance here: * https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/ @@ -148,8 +148,8 @@ extern void nr_span_event_set_transaction_name(nr_span_event_t* event, const char* transaction_name); extern void nr_span_event_set_category(nr_span_event_t* event, nr_span_category_t category); -extern void nr_span_event_set_category(nr_span_event_t* event, - nr_span_category_t category); +extern void nr_span_event_set_spankind(nr_span_event_t* event, + nr_span_spankind_t category); extern void nr_span_event_set_timestamp(nr_span_event_t* event, nrtime_t time); extern void nr_span_event_set_duration(nr_span_event_t* event, nrtime_t duration); From 9f7e56162efd0be7526f045722e297776210961b Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 06:37:17 -0700 Subject: [PATCH 13/63] feat(axiom): Added message getters to span_event --- axiom/nr_span_event.c | 27 +++++++++++++++++++++++++++ axiom/nr_span_event_private.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 0190349fa..9da8532f4 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -439,6 +439,7 @@ SPAN_EVENT_GETTER_STRING(nr_span_event_get_transaction_name, intrinsics, "transaction.name") SPAN_EVENT_GETTER_STRING(nr_span_event_get_category, intrinsics, "category") +SPAN_EVENT_GETTER_STRING(nr_span_event_get_spankind, intrinsics, "span.kind") SPAN_EVENT_GETTER_TIME(nr_span_event_get_timestamp, intrinsics, "timestamp") SPAN_EVENT_GETTER_DOUBLE(nr_span_event_get_duration, intrinsics, "duration") SPAN_EVENT_GETTER_DOUBLE(nr_span_event_get_priority, intrinsics, "priority") @@ -527,6 +528,32 @@ const char* nr_span_event_get_external(const nr_span_event_t* event, return NULL; } +const char* nr_span_event_get_message(const nr_span_event_t* event, + nr_span_event_message_member_t member) { + if (NULL == event) { + return NULL; + } + + switch (member) { + case NR_SPAN_MESSAGE_DESTINATION_NAME: + return nro_get_hash_string(event->agent_attributes, + "messaging.destination.name", NULL); + case NR_SPAN_MESSAGE_CLOUD_REGION: + return nro_get_hash_string(event->agent_attributes, "cloud.region", NULL); + case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: + return nro_get_hash_string(event->intrinsics, "cloud.account.id", NULL); + case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: + return nro_get_hash_string(event->agent_attributes, "messaging.system", + NULL); + case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: + return nro_get_hash_string(event->agent_attributes, "cloud.resource_id", + NULL); + case NR_SPAN_MESSAGE_SERVER_ADDRESS: + return nro_get_hash_string(event->intrinsics, "server.address", NULL); + } + return NULL; +} + void nr_span_event_set_attribute_user(nr_span_event_t* event, const char* name, const nrobj_t* value) { diff --git a/axiom/nr_span_event_private.h b/axiom/nr_span_event_private.h index 349c50538..4f55c6f2f 100644 --- a/axiom/nr_span_event_private.h +++ b/axiom/nr_span_event_private.h @@ -28,6 +28,7 @@ extern const char* nr_span_event_get_name(const nr_span_event_t* event); extern const char* nr_span_event_get_transaction_name( const nr_span_event_t* event); extern const char* nr_span_event_get_category(const nr_span_event_t* event); +extern const char* nr_span_event_get_spankind(const nr_span_event_t* event); extern nrtime_t nr_span_event_get_timestamp(const nr_span_event_t* event); extern double nr_span_event_get_duration(const nr_span_event_t* event); extern double nr_span_event_get_priority(const nr_span_event_t* event); @@ -44,6 +45,9 @@ extern const char* nr_span_event_get_external( const nr_span_event_t* event, nr_span_event_external_member_t member); extern uint64_t nr_span_event_get_external_status(const nr_span_event_t* event); +extern const char* nr_span_event_get_message( + const nr_span_event_t* event, + nr_span_event_message_member_t member); extern const char* nr_span_event_get_error_message( const nr_span_event_t* event); extern const char* nr_span_event_get_error_class(const nr_span_event_t* event); From 95077b19fcb3cba721145b8845f611cc56d65401 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 06:39:21 -0700 Subject: [PATCH 14/63] feat(axiom): Add span message related span get/set functionality * test get/set spankind * test get/set message span members --- axiom/tests/test_span_event.c | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index 85ca788b9..3d741e355 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -256,6 +256,47 @@ static void test_span_event_category(void) { tlib_pass_if_str_equal("Category should be the one we set - http", "http", nr_span_event_get_category(event)); + nr_span_event_set_category(event, NR_SPAN_MESSAGE); + tlib_pass_if_str_equal("Category should be the one we set - message", + "message", nr_span_event_get_category(event)); + + nr_span_event_destroy(&event); +} + +static void test_span_event_spankind(void) { + nr_span_event_t* event = nr_span_event_create(); + + // Test : the default is NULL (spankind must be explicitly set) + tlib_pass_if_str_equal("The default category", NULL, + nr_span_event_get_spankind(event)); + + // Test : A null event returns NULL + tlib_pass_if_null("The default category", nr_span_event_get_spankind(NULL)); + + // Test : passing a NULL event should not blow up + nr_span_event_set_spankind(NULL, NR_SPAN_PRODUCER); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + tlib_pass_if_str_equal( + "Spankind should be the one we set - no spankind (NULL)", NULL, + nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_PRODUCER); + tlib_pass_if_str_equal("Spankind should be the one we set - producer", + "producer", nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + tlib_pass_if_str_equal("Spankind should be the one we set - client", "client", + nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_CONSUMER); + tlib_pass_if_str_equal("Spankind should be the one we set - consumer", + "consumer", nr_span_event_get_spankind(event)); + nr_span_event_destroy(&event); } @@ -434,6 +475,89 @@ static void test_span_events_extern_get_and_set(void) { nr_span_event_destroy(&span); } +static void test_span_event_message_string_get_and_set(void) { + nr_span_event_t* event = nr_span_event_create(); + + // Test : that is does not blow up when we give the setter a NULL pointer + nr_span_event_set_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME, "wallaby"); + tlib_pass_if_null( + "the destination name should still be NULL", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, NULL); + tlib_pass_if_null( + "given a NULL value we should get a NULL", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : the getter should not blow up when we send it an event with a NULL + // component + tlib_pass_if_null( + "NULL event -> NULL component", + nr_span_event_get_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : setting the cloud region back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); + + // Test : setting the destination name back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : setting the cloud account id back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); + + // Test : setting the messaging system back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); + + // Test : setting the cloud resource id back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); + + // Test : setting the server address back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + + nr_span_event_destroy(&event); +} + static void test_span_event_error(void) { nr_span_event_t* event = nr_span_event_create(); @@ -614,10 +738,12 @@ void test_main(void* p NRUNUSED) { test_span_event_name(); test_span_event_transaction_name(); test_span_event_category(); + test_span_event_spankind(); test_span_event_timestamp(); test_span_event_duration(); test_span_event_datastore_string_get_and_set(); test_span_events_extern_get_and_set(); + test_span_event_message_string_get_and_set(); test_span_event_error(); test_span_event_set_attribute_user(); test_span_event_txn_parent_attributes(); From 5554ee240c2a9c229588d244ea518e48e267bdcc Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 09:27:01 -0700 Subject: [PATCH 15/63] feat(axiom): Add message segment tests Sorry clang-format added some unrelated formatting. --- axiom/tests/test_segment_traces.c | 183 +++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 27 deletions(-) diff --git a/axiom/tests/test_segment_traces.c b/axiom/tests/test_segment_traces.c index 450ea8af6..4ca0074a8 100644 --- a/axiom/tests/test_segment_traces.c +++ b/axiom/tests/test_segment_traces.c @@ -51,6 +51,10 @@ tlib_pass_if_str_equal("category", "http", \ nr_span_event_get_category(evt)); \ break; \ + case NR_SPAN_MESSAGE: \ + tlib_pass_if_str_equal("category", "message", \ + nr_span_event_get_category(evt)); \ + break; \ default: \ tlib_pass_if_true("invalid category", false, "category=%s", \ nr_span_event_get_category(evt)); \ @@ -86,6 +90,29 @@ tlib_pass_if_int_equal("status", expected_status, \ nr_span_event_get_external_status(span_event)); +#define SPAN_EVENT_COMPARE_MESSAGE( \ + span_event, expected_destination_name, expected_cloud_region, \ + expected_cloud_account_id, expected_messaging_system, \ + expected_cloud_resource_id, expected_server_address) \ + tlib_pass_if_str_equal("destination.name", expected_destination_name, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ + tlib_pass_if_str_equal( \ + "cloud.region", expected_cloud_region, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION)); \ + tlib_pass_if_str_equal("cloud.account.id", expected_cloud_account_id, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); \ + tlib_pass_if_str_equal("messaging.system", expected_messaging_system, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); \ + tlib_pass_if_str_equal("cloud.resource_id", expected_cloud_resource_id, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); \ + tlib_pass_if_str_equal( \ + "server.address", expected_server_address, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + static void nr_vector_span_event_dtor(void* element, void* userdata NRUNUSED) { nr_span_event_destroy((nr_span_event_t**)&element); } @@ -652,13 +679,15 @@ static void test_json_print_segments_invalid_typed_attributes(void) { nr_span_event_t* evt_root; nr_span_event_t* evt_a; nr_span_event_t* evt_b; + nr_span_event_t* evt_c; nrtxn_t txn = {0}; // clang-format off - nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 9000}; + nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 11000}; nr_segment_t A = {.txn = &txn, .start_time = 1000, .stop_time = 6000}; nr_segment_t B = {.txn = &txn, .start_time = 6000, .stop_time = 8000}; + nr_segment_t C = {.txn = &txn, .start_time = 9000, .stop_time = 10000}; // clang-format on buf = nr_buffer_create(4096, 4096); @@ -668,20 +697,23 @@ static void test_json_print_segments_invalid_typed_attributes(void) { /* Mock up the transaction */ mock_txn(&txn, &root); txn.abs_start_time = 1000; - txn.segment_count = 2; + txn.segment_count = 3; /* Create a collection of mock segments */ nr_segment_children_init(&root.children); nr_segment_add_child(&root, &A); nr_segment_add_child(&root, &B); + nr_segment_add_child(&root, &C); root.name = nr_string_add(txn.trace_strings, "WebTransaction/*"); A.name = nr_string_add(txn.trace_strings, "A"); B.name = nr_string_add(txn.trace_strings, "B"); + C.name = nr_string_add(txn.trace_strings, "C"); A.type = NR_SEGMENT_EXTERNAL; B.type = NR_SEGMENT_DATASTORE; + C.type = NR_SEGMENT_MESSAGE; /* * Test : Normal operation @@ -689,23 +721,27 @@ static void test_json_print_segments_invalid_typed_attributes(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, NULL, NULL, &txn, &root, segment_names); tlib_pass_if_bool_equal("success", true, rv); - test_buffer_contents("datastore params", buf, - "[0,9,\"`0\",{},[[1,6," - "\"`1\",{},[]],[6,8," - "\"`2\",{},[]]]]"); + test_buffer_contents("segment attributes", buf, + "[0,11,\"`0\",{}," + "[[1,6,\"`1\",{},[]]," + "[6,8,\"`2\",{},[]]," + "[9,10,\"`3\",{},[]]]]"); - tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 3); + tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 4); evt_root = (nr_span_event_t*)nr_vector_get(span_events, 0); evt_a = (nr_span_event_t*)nr_vector_get(span_events, 1); evt_b = (nr_span_event_t*)nr_vector_get(span_events, 2); + evt_c = (nr_span_event_t*)nr_vector_get(span_events, 3); SPAN_EVENT_COMPARE(evt_root, "WebTransaction/*", NR_SPAN_GENERIC, NULL, 1000, - 9000); + 11000); SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_HTTP, evt_root, 2000, 5000); SPAN_EVENT_COMPARE_EXTERNAL(evt_a, NULL, NULL, NULL, 0); SPAN_EVENT_COMPARE(evt_b, "B", NR_SPAN_DATASTORE, evt_root, 7000, 2000); SPAN_EVENT_COMPARE_DATASTORE(evt_b, NULL, NULL, NULL, NULL); + SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_MESSAGE, evt_root, 10000, 1000); + SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL, NULL, NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -713,6 +749,7 @@ static void test_json_print_segments_invalid_typed_attributes(void) { nr_segment_destroy_fields(&A); nr_segment_destroy_fields(&B); + nr_segment_destroy_fields(&C); cleanup_mock_txn(&txn); nr_string_pool_destroy(&segment_names); @@ -904,7 +941,95 @@ static void test_json_print_segments_external_async_user_attrs(void) { nr_vector_destroy(&span_events); } -static void test_json_print_segments_datastore_external(void) { +static void test_json_print_segments_message_attributes(void) { + bool rv; + nrbuf_t* buf; + nr_vector_t* span_events; + nrpool_t* segment_names; + + nrtxn_t txn = {0}; + + nr_span_event_t* evt_root; + nr_span_event_t* evt_a; + + // clang-format off + nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 9000}; + nr_segment_t A = {.txn = &txn, .start_time = 1000, .stop_time = 6000}; + // clang-format on + + buf = nr_buffer_create(4096, 4096); + span_events = nr_vector_create(9, nr_vector_span_event_dtor, NULL); + segment_names = nr_string_pool_create(); + + /* Mock up the transaction */ + mock_txn(&txn, &root); + txn.abs_start_time = 1000; + txn.segment_count = 2; + + /* Create a collection of mock segments */ + + /* ------root------- + * ------A------ + */ + + nr_segment_children_init(&root.children); + + nr_segment_add_child(&root, &A); + + root.name = nr_string_add(txn.trace_strings, "WebTransaction/*"); + A.name = nr_string_add(txn.trace_strings, "A"); + + A.type = NR_SEGMENT_MESSAGE; + A.attributes = NULL; + A.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + A.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); + A.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); + A.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); + A.typed_attributes->message.destination_name = nr_strdup("queue_name"); + A.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + A.typed_attributes->message.server_address = nr_strdup("localhost"); + + /* + * Test : Normal operation + */ + rv = nr_segment_traces_json_print_segments(buf, span_events, NULL, NULL, &txn, + &root, segment_names); + tlib_pass_if_bool_equal("success", true, rv); + test_buffer_contents("message attributes", buf, + "[0,9,\"`0\",{},[[1,6,\"`1\",{" + "\"destination_name\":\"queue_name\"," + "\"messaging_system\":\"aws_sqs\"," + "\"cloud_region\":\"us-west-1\"," + "\"cloud_account_id\":\"12345678\"," + "\"cloud_resource_id\":\"resource_id_info\"," + "\"server_address\":\"localhost\"" + "},[]]]]"); + + tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 2); + + evt_root = (nr_span_event_t*)nr_vector_get(span_events, 0); + evt_a = (nr_span_event_t*)nr_vector_get(span_events, 1); + + SPAN_EVENT_COMPARE(evt_root, "WebTransaction/*", NR_SPAN_GENERIC, NULL, 1000, + 9000); + SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_MESSAGE, evt_root, 2000, 5000); + SPAN_EVENT_COMPARE_MESSAGE(evt_a, "queue_name", "us-west-1", "12345678", + "aws_sqs", "resource_id_info", "localhost"); + + /* Clean up */ + nr_segment_children_deinit(&root.children); + nr_segment_destroy_fields(&root); + + nr_segment_destroy_fields(&A); + + cleanup_mock_txn(&txn); + nr_string_pool_destroy(&segment_names); + + nr_buffer_destroy(&buf); + nr_vector_destroy(&span_events); +} + +static void test_json_print_segments_datastore_external_message(void) { bool rv; nrbuf_t* buf; nr_vector_t* span_events; @@ -972,12 +1097,12 @@ static void test_json_print_segments_datastore_external(void) { C.typed_attributes->external.transaction_guid = nr_strdup("guid"); C.typed_attributes->external.status = 200; - D.type = NR_SEGMENT_DATASTORE; + D.type = NR_SEGMENT_MESSAGE; D.attributes = NULL; D.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); - D.typed_attributes->datastore.sql = nr_strdup("SELECT pass"); - D.typed_attributes->datastore.instance.host = nr_strdup("localhost"); - D.typed_attributes->datastore.instance.database_name = nr_strdup("db"); + D.typed_attributes->message.destination_name = nr_strdup("queue_name"); + D.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + D.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); /* * Test : Normal operation @@ -999,9 +1124,9 @@ static void test_json_print_segments_datastore_external(void) { "\"transaction_guid\":\"guid\"," "\"status\":200},[]]," "[5,6,\"`4\"," - "{\"host\":\"localhost\"," - "\"database_name\":\"db\"," - "\"sql\":\"SELECT pass\"},[]]]]]]"); + "{\"destination_name\":\"queue_name\"," + "\"messaging_system\":\"aws_sqs\"," + "\"cloud_region\":\"us-west-1\"},[]]]]]]"); tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 5); @@ -1019,9 +1144,9 @@ static void test_json_print_segments_datastore_external(void) { "localhost:3308"); SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_HTTP, evt_a, 5000, 1000); SPAN_EVENT_COMPARE_EXTERNAL(evt_c, "example.com", "GET", "curl", 200); - SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_DATASTORE, evt_a, 6000, 1000); - SPAN_EVENT_COMPARE_DATASTORE(evt_d, "localhost", "db", "SELECT pass", - "localhost:unknown"); + SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_MESSAGE, evt_a, 6000, 1000); + SPAN_EVENT_COMPARE_MESSAGE(evt_d, "queue_name", "us-west-1", NULL, "aws_sqs", + NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -1146,8 +1271,8 @@ static void test_json_print_segments_async_basic(void) { * * These diagrams all follow the same pattern: time is shown in seconds on * the first row, followed by the ROOT node, and then individual contexts - * with their nodes. The "main" context indicates that no async_context will - * be attached to nodes in that context. + * with their nodes. The "main" context indicates that no async_context + * will be attached to nodes in that context. * * time (s) 0 1 2 3 4 5 6 7 8 9 10 * |------------------- ROOT -------------------| @@ -1245,8 +1370,8 @@ static void test_json_print_segments_async_multi_child(void) { /* * Multiple children test: main context lasts the same timespan as ROOT, and - * spawns one child context with three nodes for part of its run time, one of - * which has a duplicated name. + * spawns one child context with three nodes for part of its run time, one + * of which has a duplicated name. * * time (s) 0 1 2 3 4 5 6 7 8 9 10 * |------------------- ROOT -------------------| @@ -1955,7 +2080,8 @@ static void test_json_print_segments_with_sampling_cousin_parent(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, set, set, &txn, &root, segment_names); tlib_pass_if_bool_equal( - "Printing JSON for a sampled cousin parent tree of segments must succeed", + "Printing JSON for a sampled cousin parent tree of segments must " + "succeed", true, rv); test_buffer_contents("Cousin Parent", buf, "[0,14,\"`0\",{},[[1,5,\"`1\",{},[[1,3,\"`2\",{},[]]]],[" @@ -2269,7 +2395,8 @@ static void test_json_print_segments_with_sampling_genghis_khan(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, set, set, &txn, &root, segment_names); tlib_pass_if_bool_equal( - "Printing JSON for a genghis khan sampled tree of segments must succeed", + "Printing JSON for a genghis khan sampled tree of segments must " + "succeed", true, rv); test_buffer_contents("genghis khan", buf, "[0,9,\"`0\",{},[[1,6,\"`1\",{},[]],[3,4,\"`2\",{},[]],[" @@ -2470,7 +2597,8 @@ static void test_trace_create_data_bad_parameters(void) { agent_attributes, user_attributes, intrinsics, true, false); tlib_pass_if_null( - "A transaction with more than NR_MAX_SEGMENTS segments must not succeed " + "A transaction with more than NR_MAX_SEGMENTS segments must not " + "succeed " "in creating " "a trace", metadata.out->trace_json); @@ -2786,9 +2914,10 @@ void test_main(void* p NRUNUSED) { test_json_print_segments_hanoi(); test_json_print_segments_three_siblings(); test_json_print_segments_two_generations(); - test_json_print_segments_datastore_external(); + test_json_print_segments_datastore_external_message(); test_json_print_segments_datastore_params(); test_json_print_segments_external_async_user_attrs(); + test_json_print_segments_message_attributes(); test_json_print_segments_async_basic(); test_json_print_segments_async_multi_child(); From d22cbc9656f633964d46b34dccff120705eac5a0 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 10:10:43 -0700 Subject: [PATCH 16/63] feat(axiom): Add tests to ensure message segment destroy clean up properly --- axiom/tests/test_segment_private.c | 64 +++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index e586f1f4f..e4407aa8f 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -25,6 +25,7 @@ static void test_bad_parameters(void) { nr_segment_destroy_fields(NULL); nr_segment_datastore_destroy_fields(NULL); nr_segment_external_destroy_fields(NULL); + nr_segment_message_destroy_fields(NULL); nr_segment_metric_destroy_fields(NULL); nr_segment_error_destroy_fields(NULL); } @@ -205,7 +206,6 @@ static void test_set_custom(void) { tlib_pass_if_int_equal( "Setting an untyped segment to custom must set the type", (int)NR_SEGMENT_CUSTOM, (int)s.type); - nr_segment_set_datastore(&t, &d); tlib_pass_if_true("Setting a datastore segment to custom must be successful", nr_segment_set_custom(&t), "Expected true"); @@ -316,6 +316,51 @@ static void test_set_destroy_external_fields(void) { &s.typed_attributes); } +static void test_set_destroy_message_fields(void) { + nr_segment_t s = {.type = NR_SEGMENT_MESSAGE}; + + nr_segment_message_t m = {.message_action = NR_SPAN_CLIENT, + .cloud_region = "my_cloud_region", + .cloud_account_id = "12345678", + .messaging_system = "my_messaging_system", + .cloud_resource_id = "my_cloud_resource_id", + .server_address = "localhost"}; + + nr_segment_external_t e = {.transaction_guid = "transaction_guid", + .uri = "uri", + .library = "library", + .procedure = "procedure", + .status = 200}; + /* + * Test : Bad parameters. + */ + tlib_pass_if_false( + "Setting a NULL segment's message attributes must not be successful", + nr_segment_set_message(NULL, &m), "Expected false"); + + tlib_pass_if_false( + "Setting a segment with NULL message attributes must not be successful", + nr_segment_set_message(&s, NULL), "Expected false"); + + /* + * Test : Normal operation. + */ + tlib_pass_if_true("Setting a segment's message attributes must be successful", + nr_segment_set_message(&s, &m), "Expected true"); + + tlib_pass_if_true( + "Setting a segment from message attributes to external attributes must " + "be successful", + nr_segment_set_external(&s, &e), "Expected true"); + + /* Valgrind shall affirm that the attributes for s were cleaned + * up when the segment type was changed from message to external. + */ + + /* Clean up */ + nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); +} + static void test_destroy_typed_attributes(void) { nr_segment_t s = {0}; char* test_string = "0123456789"; @@ -328,6 +373,22 @@ static void test_destroy_typed_attributes(void) { nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, NULL); nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, NULL); + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); + + /* + * Test : Clean up typed attributes for a message segment + */ + s.type = NR_SEGMENT_MESSAGE; + s.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + s.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); + s.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); + s.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); + s.typed_attributes->message.destination_name = nr_strdup("queue_name"); + s.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + s.typed_attributes->message.server_address = nr_strdup("localhost"); + + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); /* * Test : Clean up typed attributes for an external segment @@ -394,6 +455,7 @@ void test_main(void* p NRUNUSED) { test_set_custom(); test_set_destroy_datastore_fields(); test_set_destroy_external_fields(); + test_set_destroy_message_fields(); test_destroy_typed_attributes(); test_destroy_fields(); test_destroy_metric(); From 88abff84322d6984ce1e109d73004c631870ab7a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 13:18:42 -0700 Subject: [PATCH 17/63] feat(axiom): Handle message segment metric rollups Rollups happen in 2 places in nr_txn.c nr_error_to_event And nr_txn_event_intrinsics * fixed externalCallCount was getting set in nr_error_to_event but not in nr_txn_event_intrinsics * Added messageCallCount/messageDuration to both functions --- axiom/nr_txn.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index 774c44671..e6363bcbe 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -60,10 +60,8 @@ struct _nr_txn_attribute_t { #define NR_TXN_ATTRIBUTE_TRACE_ERROR \ (NR_ATTRIBUTE_DESTINATION_TXN_TRACE | NR_ATTRIBUTE_DESTINATION_ERROR) -#define NR_TXN_ATTR(X, NAME, DESTS) \ - const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { \ - (NAME), (DESTS) \ - } +#define NR_TXN_ATTR(X, NAME, DESTS) \ + const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { (NAME), (DESTS) } NR_TXN_ATTR(nr_txn_request_uri, "request.uri", @@ -2492,11 +2490,15 @@ nr_analytics_event_t* nr_error_to_event(const nrtxn_t* txn) { "External/all", "externalDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); + nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseCallCount"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "External/all", "externalCallCount"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageCallCount"); nro_set_hash_string(params, "nr.transactionGuid", nr_txn_get_guid(txn)); @@ -2582,10 +2584,16 @@ nrobj_t* nr_txn_event_intrinsics(const nrtxn_t* txn) { params, txn->unscoped_metrics, "WebFrontend/QueueTime", "queueDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "External/all", "externalDuration"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "External/all", "externalCallCount"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseCallCount"); + nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageDuration"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageCallCount"); if (txn->options.distributed_tracing_enabled) { nr_txn_add_distributed_tracing_intrinsics(txn, params); From 3e78de637456615e51b83159b2e30569702e917f Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 13:22:57 -0700 Subject: [PATCH 18/63] feat(axiom): tests for rollup metrics for message segment --- axiom/tests/test_cmd_txndata.c | 10 ++++++++-- axiom/tests/test_txn.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/axiom/tests/test_cmd_txndata.c b/axiom/tests/test_cmd_txndata.c index fc9272e1c..ffb53a6c9 100644 --- a/axiom/tests/test_cmd_txndata.c +++ b/axiom/tests/test_cmd_txndata.c @@ -134,7 +134,8 @@ static void test_encode_errors(void) { "[887788,\"txnname\",\"msg\",\"cls\",{\"stack_trace\":[" "\"stacktrace " "json\"],\"agentAttributes\":{\"agent_long\":2},\"userAttributes\":{" - "\"user_long\":1},\"intrinsics\":{\"a\":\"b\",\"guid\":\"abcdef\"}},\"abcdef\"]"), + "\"user_long\":1},\"intrinsics\":{\"a\":\"b\",\"guid\":\"abcdef\"}}," + "\"abcdef\"]"), nr_flatbuffers_table_read_bytes(&tbl, ERROR_FIELD_DATA), nr_flatbuffers_table_read_vector_len(&tbl, ERROR_FIELD_DATA), __FILE__, __LINE__); @@ -1042,6 +1043,7 @@ static void test_encode_txn_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 2 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); txn.attributes = nr_attributes_create(0); @@ -1093,9 +1095,13 @@ static void test_encode_txn_event(void) { "\"timestamp\":123.00000," "\"duration\":0.98700,\"totalTime\":0.98700,\"nr.apdexPerfZone\":" "\"F\"," - "\"queueDuration\":3.00000,\"externalDuration\":2.00000," + "\"queueDuration\":3.00000," + "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":2.00000," "\"databaseCallCount\":2," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false}," "{\"user_long\":1},{\"agent_long\":2}]"), nr_flatbuffers_table_read_bytes(&tbl, EVENT_FIELD_DATA), diff --git a/axiom/tests/test_txn.c b/axiom/tests/test_txn.c index 9230a416a..cf7e4a170 100644 --- a/axiom/tests/test_txn.c +++ b/axiom/tests/test_txn.c @@ -2006,7 +2006,7 @@ static nrtxn_t* create_full_txn_and_reset(nrapp_t* app) { nr_segment_t* seg = nr_segment_start(txn, NULL, NULL); seg->start_time = 5 * NR_TIME_DIVISOR; seg->stop_time = 6 * NR_TIME_DIVISOR; - seg->type = NR_SEGMENT_DATASTORE; + seg->type = NR_SEGMENT_MESSAGE; seg->typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); nr_segment_end(&seg); } @@ -2962,6 +2962,7 @@ static void test_create_rollup_metrics(void) { txn.datastore_products = nr_string_pool_create(); nrm_force_add(txn.unscoped_metrics, "Datastore/all", 4 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "External/all", 1 * NR_TIME_DIVISOR); + nrm_force_add(txn.unscoped_metrics, "MessageBroker/all", 1 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "Datastore/MongoDB/all", 2 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "Datastore/SQLite/all", @@ -2977,6 +2978,9 @@ static void test_create_rollup_metrics(void) { "{\"name\":\"External\\/" "all\",\"data\":[1,1.00000,1.00000,1.00000,1.00000,1." "00000],\"forced\":true}," + "{\"name\":\"MessageBroker\\/" + "all\",\"data\":[1,1.00000,1.00000,1.00000,1.00000,1." + "00000],\"forced\":true}," "{\"name\":\"Datastore\\/MongoDB\\/" "all\",\"data\":[1,2.00000,2.00000,2.00000,2.00000,4." "00000],\"forced\":true}," @@ -3910,6 +3914,7 @@ static void test_error_to_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); event = nr_error_to_event(&txn); @@ -3926,8 +3931,10 @@ static void test_error_to_event(void) { "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," "\"databaseDuration\":1.00000," + "\"messageDuration\":1.00000," "\"databaseCallCount\":1," "\"externalCallCount\":1," + "\"messageCallCount\":1," "\"nr.transactionGuid\":\"abcd\"," "\"guid\":\"abcd\"" "}," @@ -3951,8 +3958,10 @@ static void test_error_to_event(void) { "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," "\"databaseDuration\":1.00000," + "\"messageDuration\":1.00000," "\"databaseCallCount\":1," "\"externalCallCount\":1," + "\"messageCallCount\":1," "\"nr.transactionGuid\":\"abcd\"," "\"guid\":\"abcd\"," "\"nr.referringTransactionGuid\":\"foo_guid\"," @@ -4041,6 +4050,7 @@ static void test_create_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 2 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); event = nr_txn_to_event(&txn); @@ -4056,8 +4066,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4078,8 +4091,11 @@ static void test_create_event(void) { "\"totalTime\":0.98700," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4103,8 +4119,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4126,8 +4145,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4148,8 +4170,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -8054,7 +8079,8 @@ static void test_segment_record_error(void) { /* Do not add to current segment */ nr_txn_record_error(txn, 0.5, false /* do not add to current segment*/, - "low priority message", "low priority class", "[\"A\",\"B\"]"); + "low priority message", "low priority class", + "[\"A\",\"B\"]"); tlib_pass_if_not_null("Txn error event created", txn->error); tlib_pass_if_null("Segment error NOT created", segment->error); tlib_pass_if_str_equal("Correct txn error.message", "low priority message", @@ -8063,7 +8089,8 @@ static void test_segment_record_error(void) { nr_error_get_klass(txn->error)); /* Normal operation: txn error prioritized over previous */ - nr_txn_record_error(txn, 1, true, "error message", "error class", "[\"A\",\"B\"]"); + nr_txn_record_error(txn, 1, true, "error message", "error class", + "[\"A\",\"B\"]"); tlib_pass_if_not_null("Txn error event created", txn->error); tlib_pass_if_not_null("Segment error created", segment->error); From 7802981f1fab2d38001d1d04d2ce0b568fd57ba1 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:24:34 -0700 Subject: [PATCH 19/63] feat(axiom): Stronger handling of NULL/empty str for message attributes Handle NULL/empty str and provide the `` string. --- axiom/nr_segment_message.c | 66 +++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 6efcd1072..2fba880ac 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -25,12 +25,22 @@ static void nr_segment_message_set_attrs( message_attributes.message_action = params->message_action; if (options.message_tracer_segment_parameters_enabled) { - message_attributes.destination_name = params->destination_name; - message_attributes.cloud_region = params->cloud_region; - message_attributes.cloud_account_id = params->cloud_account_id; - message_attributes.messaging_system = params->messaging_system; - message_attributes.cloud_resource_id = params->cloud_resource_id; - message_attributes.server_address = params->server_address; + message_attributes.destination_name = nr_strempty(params->destination_name) + ? NULL + : params->destination_name; + message_attributes.cloud_region + = nr_strempty(params->cloud_region) ? NULL : params->cloud_region; + message_attributes.cloud_account_id = nr_strempty(params->cloud_account_id) + ? NULL + : params->cloud_account_id; + message_attributes.messaging_system = nr_strempty(params->messaging_system) + ? NULL + : params->messaging_system; + message_attributes.cloud_resource_id + = nr_strempty(params->cloud_resource_id) ? NULL + : params->cloud_resource_id; + message_attributes.server_address + = nr_strempty(params->server_address) ? NULL : params->server_address; } nr_segment_set_message(segment, &message_attributes); @@ -42,20 +52,20 @@ static void nr_segment_message_set_attrs( * * Metrics created during this call * ---------------------------------------------------------------------------------- - * MessageBroker/all Unscoped - * Always MessageBroker/{library}/all Scoped Always + * MessageBroker/all Unscoped Always + * MessageBroker/{library}/all coped Always * * Metrics created based on MessageBroker/all (in nr_txn_create_rollup_metrics) * ---------------------------------------------------------------------------------- - * MessageBroker/allWeb Unscoped Web - * MessageBroker/allOther Unscoped - * non-Web + * MessageBroker/allWeb Unscoped Web + * MessageBroker/allOther Unscoped non-Web * * Segment name * ----------------------------------------------------------------------------------- * MessageBroker/{library}/all Always * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * non-temp + * MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp * * * These metrics are dictated by the spec located here: @@ -86,6 +96,7 @@ static char* nr_segment_message_create_metrics( nrtime_t duration) { const char* action_string = NULL; const char* destination_type_string = NULL; + const char* library_string = NULL; char* rollup_metric = NULL; char* scoped_metric = NULL; @@ -93,7 +104,7 @@ static char* nr_segment_message_create_metrics( return NULL; } - if (NULL == message_params || NULL == message_params->library) { + if (NULL == message_params) { return NULL; } @@ -106,7 +117,12 @@ static char* nr_segment_message_create_metrics( nrm_force_add(segment->txn->unscoped_metrics, "MessageBroker/all", duration); - rollup_metric = nr_formatf("MessageBroker/%s/all", message_params->library); + if (nr_strempty(message_params->library)) { + library_string = ""; + } else { + library_string = message_params->library; + } + rollup_metric = nr_formatf("MessageBroker/%s/all", library_string); nrm_force_add(segment->txn->unscoped_metrics, rollup_metric, duration); nr_free(rollup_metric); @@ -122,7 +138,7 @@ static char* nr_segment_message_create_metrics( } else if (NR_SPAN_CONSUMER == message_params->message_action) { action_string = "Consume"; } else { - action_string = "Unknown"; + action_string = ""; } switch (message_params->destination_type) { @@ -138,26 +154,26 @@ static char* nr_segment_message_create_metrics( destination_type_string = "Exchange"; break; default: - destination_type_string = "Unknown"; + destination_type_string = ""; break; } /* * Create the scoped metric * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp */ if (NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE == message_params->destination_type || NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC == message_params->destination_type) { - scoped_metric - = nr_formatf("MessageBroker/%s/%s/%s/Temp", message_params->library, - destination_type_string, action_string); + scoped_metric = nr_formatf("MessageBroker/%s/%s/%s/Temp", library_string, + destination_type_string, action_string); } else { - scoped_metric = nr_formatf( - "MessageBroker/%s/%s/%s/Named/%s", message_params->library, - destination_type_string, action_string, - message_params->destination_name ? message_params->destination_name - : "Unknown"); + scoped_metric + = nr_formatf("MessageBroker/%s/%s/%s/Named/%s", library_string, + destination_type_string, action_string, + nr_strempty(message_params->destination_name) + ? "" + : message_params->destination_name); } nr_segment_add_metric(segment, scoped_metric, true); From a12ddebdaac819aff60b05c0897c6b7985e1b448 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:26:35 -0700 Subject: [PATCH 20/63] feat(axiom): message segment rollup metrics --- axiom/nr_txn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index e6363bcbe..8c2a4a75d 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -1219,11 +1219,15 @@ void nr_txn_create_rollup_metrics(nrtxn_t* txn) { "Datastore/allOther"); nrm_duplicate_metric(txn->unscoped_metrics, "External/all", "External/allOther"); + nrm_duplicate_metric(txn->unscoped_metrics, "MessageBroker/all", + "MessageBroker/allOther"); } else { nrm_duplicate_metric(txn->unscoped_metrics, "Datastore/all", "Datastore/allWeb"); nrm_duplicate_metric(txn->unscoped_metrics, "External/all", "External/allWeb"); + nrm_duplicate_metric(txn->unscoped_metrics, "MessageBroker/all", + "MessageBroker/allWeb"); } nr_string_pool_apply( From 882689aeeb416b9264e8190c706f369a36b64636 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:35:51 -0700 Subject: [PATCH 21/63] feat(axiom): add message rollup metric to test case --- axiom/tests/test_txn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/axiom/tests/test_txn.c b/axiom/tests/test_txn.c index cf7e4a170..5dc68deae 100644 --- a/axiom/tests/test_txn.c +++ b/axiom/tests/test_txn.c @@ -2993,6 +2993,9 @@ static void test_create_rollup_metrics(void) { "{\"name\":\"External\\/" "allOther\",\"data\":[1,1.00000,1.00000,1.00000,1." "00000,1.00000],\"forced\":true}," + "{\"name\":\"MessageBroker\\/" + "allOther\",\"data\":[1,1.00000,1.00000,1.00000,1." + "00000,1.00000],\"forced\":true}," "{\"name\":\"Datastore\\/MongoDB\\/" "allOther\",\"data\":[1,2.00000,2.00000,2.00000,2." "00000,4.00000],\"forced\":true}," From 3e448d0b33810c246966c84880037d1c980de5bf Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:41:29 -0700 Subject: [PATCH 22/63] feat(axiom): Add unit tests for nr_segment_message --- axiom/tests/Makefile | 1 + axiom/tests/test_segment_helpers.h | 23 +- axiom/tests/test_segment_message.c | 880 +++++++++++++++++++++++++++++ 3 files changed, 903 insertions(+), 1 deletion(-) create mode 100644 axiom/tests/test_segment_message.c diff --git a/axiom/tests/Makefile b/axiom/tests/Makefile index 0a37821bb..3d67984ca 100644 --- a/axiom/tests/Makefile +++ b/axiom/tests/Makefile @@ -173,6 +173,7 @@ TESTS := \ test_segment_children \ test_segment_datastore \ test_segment_external \ + test_segment_message \ test_segment_private \ test_segment_terms \ test_segment_traces \ diff --git a/axiom/tests/test_segment_helpers.h b/axiom/tests/test_segment_helpers.h index 908432798..9ff7f54f7 100644 --- a/axiom/tests/test_segment_helpers.h +++ b/axiom/tests/test_segment_helpers.h @@ -12,6 +12,7 @@ #include "nr_segment.h" #include "nr_segment_datastore.h" #include "nr_segment_external.h" +#include "nr_segment_message.h" #include "tlib_main.h" #include "util_metrics_private.h" #include "nr_limits.h" @@ -287,7 +288,7 @@ static NRUNUSED bool test_segment_end_and_keep(nr_segment_t** segment_ptr) { } /* - * Purpose : Ends an external segment without nulling out the segment pointer. + * Purpose : Ends an external segment without nulling out the segment pointer. * * WARNING : This can only be used safely when the segment priority queue is * disabled. @@ -326,4 +327,24 @@ static NRUNUSED bool test_segment_datastore_end_and_keep( return nr_segment_datastore_end(&segment, params); } +/* + * Purpose : Ends a message segment without nulling out the segment pointer. + * + * WARNING : This can only be used safely when the segment priority queue is + * disabled. + */ +static NRUNUSED bool test_segment_message_end_and_keep( + nr_segment_t** segment_ptr, + nr_segment_message_params_t* params) { + nr_segment_t* segment; + + if (NULL == segment_ptr) { + return false; + } + + segment = *segment_ptr; + + return nr_segment_message_end(&segment, params); +} + #endif /* TEST_SEGMENT_HELPERS_HDR */ diff --git a/axiom/tests/test_segment_message.c b/axiom/tests/test_segment_message.c new file mode 100644 index 000000000..82cfc46c0 --- /dev/null +++ b/axiom/tests/test_segment_message.c @@ -0,0 +1,880 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nr_axiom.h" +#include "nr_header.h" +#include "nr_segment_message.h" +#include "test_segment_helpers.h" + +typedef struct { + const char* test_name; + const char* name; + const char* txn_rollup_metric; + const char* library_metric; + uint32_t num_metrics; + const char* destination_name; + const char* cloud_region; + const char* cloud_account_id; + const char* messaging_system; + const char* cloud_resource_id; + const char* server_address; + +} segment_message_expecteds_t; + +static nr_segment_t* mock_txn_segment(void) { + nrtxn_t* txn = new_txn(0); + + return nr_segment_start(txn, NULL, NULL); +} + +static void test_message_segment(nr_segment_message_params_t* params, + bool message_attributes_enabled, + segment_message_expecteds_t expecteds) { + nr_segment_t* seg = mock_txn_segment(); + nrtxn_t* txn = seg->txn; + seg->txn->options.message_tracer_segment_parameters_enabled + = message_attributes_enabled; + + test_segment_message_end_and_keep(&seg, params); + + tlib_pass_if_str_equal(expecteds.test_name, expecteds.name, + nr_string_get(seg->txn->trace_strings, seg->name)); + test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, + expecteds.txn_rollup_metric); + test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, + expecteds.library_metric); + test_metric_vector_size(seg->metrics, expecteds.num_metrics); + tlib_pass_if_true(expecteds.test_name, NR_SEGMENT_MESSAGE == seg->type, + "NR_SEGMENT_MESSAGE"); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.destination_name, + expecteds.destination_name); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_region, + expecteds.cloud_region); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_account_id, + expecteds.cloud_account_id); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.messaging_system, + expecteds.messaging_system); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_resource_id, + expecteds.cloud_resource_id); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.server_address, + expecteds.server_address); + + nr_txn_destroy(&txn); +} + +static void test_bad_parameters(void) { + nr_segment_t seg_null = {0}; + nr_segment_t* seg_null_ptr; + nr_segment_t* seg = mock_txn_segment(); + nrtxn_t* txn = seg->txn; + nr_segment_message_params_t params = {0}; + + tlib_pass_if_false("bad parameters", nr_segment_message_end(NULL, ¶ms), + "expected false"); + + seg_null_ptr = NULL; + tlib_pass_if_false("bad parameters", + nr_segment_message_end(&seg_null_ptr, ¶ms), + "expected false"); + + seg_null_ptr = &seg_null; + tlib_pass_if_false("bad parameters", + nr_segment_message_end(&seg_null_ptr, ¶ms), + "expected false"); + + tlib_pass_if_false("bad parameters", nr_segment_message_end(&seg, NULL), + "expected false"); + test_metric_vector_size(seg->metrics, 0); + + nr_txn_destroy(&txn); +} + +static void test_segment_message_destination_type(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC destination type", + .name = "MessageBroker/SQS/Topic/Produce/Temp", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type", + .name = "MessageBroker/SQS/Queue/Produce/Temp", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_EXCHANGE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", + .name = "MessageBroker/SQS/Exchange/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_TOPIC destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_QUEUE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type", + .name = "MessageBroker/SQS/Queue/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_message_action(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + + /* Test NR_SPAN_PRODUCER message action */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_PRODUCER message action", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_SPAN_CONSUMER message action */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_CONSUMER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_CONSUMER message action", + .name = "MessageBroker/SQS/Topic/Consume/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* + * Test NR_SPAN_CLIENT message action; this is not + * allowed for message segments, should show unknown. + */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_CLIENT, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_CLIENT message action", + .name = "MessageBroker/SQS/Topic//Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_library(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test null library */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = NULL, + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null library", + .name + = "MessageBroker//Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker//all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty library */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty library", + .name + = "MessageBroker//Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker//all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid library */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid library", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_destination_name(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test null destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = NULL}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = ""}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_region(void) { + /* + * cloud_region values should NOT impact the creation of + * metrics. + */ + + /* Test null cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = "wild-west-1", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = "wild-west-1", + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_account_id(void) { + /* + * cloud_account_id values should NOT impact the creation + * of metrics. + */ + + /* Test null cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = "12345678", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = "12345678", + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_messaging_system(void) { + /* + * messaging_system values should NOT impact the creation + * of metrics. + */ + + /* Test null messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = "my_messaging_system", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = "my_messaging_system", + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_resource_id(void) { + /* + * cloud_resource_id values should NOT impact the creation + * of metrics. + */ + + /* Test null cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = "my_resource_id", + .server_address = NULL}); +} + +static void test_segment_message_server_address(void) { + /* + * server_address values should NOT impact the creation + * of metrics. + */ + + /* Test null server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = "localhost"}); + + /* Test empty server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = "localhost"}); +} + +static void test_segment_message_parameters_enabled(void) { + /* + * Attributes should be set based on value of parameters_enabled. + */ + + /* Test true message_parameters_enabled */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test true message_parameters_enabled", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .server_address = "localhost"}); + + /* Test false message_parameters_enabled */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + false /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test false message_parameters_enabled", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +tlib_parallel_info_t parallel_info = {.suggested_nthreads = 4, .state_size = 0}; + +void test_main(void* p NRUNUSED) { + test_bad_parameters(); + test_segment_message_destination_type(); + test_segment_message_message_action(); + test_segment_message_library(); + test_segment_message_destination_name(); + test_segment_message_cloud_region(); + test_segment_message_cloud_account_id(); + test_segment_message_messaging_system(); + test_segment_message_cloud_resource_id(); + test_segment_message_server_address(); + test_segment_message_parameters_enabled(); +} From 2dd2a33e834da2611b5a20c7d97b7fd989373255 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 14:24:13 -0700 Subject: [PATCH 23/63] feat(agent): Add nr_message_segment.o to Makefile --- axiom/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axiom/Makefile b/axiom/Makefile index 34b45c229..aef7c069c 100644 --- a/axiom/Makefile +++ b/axiom/Makefile @@ -17,7 +17,6 @@ # Useful variables: # # AR: The archiver used to build a static library (default: ar). -# CC: The C compiler to use (default: gcc). # CFLAGS: Flags to give the C compiler when building object files. # @@ -113,6 +112,7 @@ OBJS := \ nr_segment_children.o \ nr_segment_datastore.o \ nr_segment_external.o \ + nr_segment_message.o \ nr_segment_private.o \ nr_segment_terms.o \ nr_segment_traces.o \ From 3e89fcf8a5527c9dc5fd1d5fd44a77fc9899ac9d Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:23:21 -0700 Subject: [PATCH 24/63] feat(agent): Add message segment to enums, unions, structs Set segment type enum Create nr_segment_message_t struct Add to the nr_segment_typed_attributes_t union --- axiom/nr_segment.h | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 56d972579..b708c5274 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -34,7 +34,8 @@ typedef struct _nrtxn_t nrtxn_t; typedef enum _nr_segment_type_t { NR_SEGMENT_CUSTOM, NR_SEGMENT_DATASTORE, - NR_SEGMENT_EXTERNAL + NR_SEGMENT_EXTERNAL, + NR_SEGMENT_MESSAGE } nr_segment_type_t; /* @@ -109,6 +110,16 @@ typedef struct _nr_segment_external_t { uint64_t status; } nr_segment_external_t; +typedef struct _nr_segment_message_t { + char* transaction_guid; + char* action; /* MUST be one of: produce, consume */ + char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ + char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary + Topic, Exchange */ + uint64_t destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp */ +} nr_segment_message_t; + typedef struct _nr_segment_metric_t { char* name; bool scoped; @@ -132,6 +143,7 @@ typedef struct _nr_segment_error_t { typedef union { nr_segment_datastore_t datastore; nr_segment_external_t external; + nr_segment_message_t message; } nr_segment_typed_attributes_t; typedef struct _nr_segment_t { @@ -179,8 +191,8 @@ typedef struct _nr_segment_t { int priority; /* Used to determine which segments are preferred for span event creation */ nr_segment_typed_attributes_t* typed_attributes; /* Attributes specific to - external or datastore - segments. */ + external, datastore, + or message segments. */ nr_segment_error_t* error; /* segment error attributes */ #if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \ && !defined OVERWRITE_ZEND_EXECUTE_DATA /* PHP 8.0+ and OAPI */ @@ -314,6 +326,17 @@ extern bool nr_segment_set_datastore(nr_segment_t* segment, */ extern bool nr_segment_set_external(nr_segment_t* segment, const nr_segment_external_t* external); + +/* + * Purpose : Mark the segment as being a message segment. + * + * Params : 1. The pointer to the segment. + * 2. The message attributes, which will be copied into the segment. + * + * Returns : true if successful, false otherwise. + */ +extern bool nr_segment_set_message(nr_segment_t* segment, + const nr_segment_message_t* message); /* * Purpose : Add a child to a segment. * From a7ada88ac18b744bafca207ff254911292dd89c0 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:41:05 -0700 Subject: [PATCH 25/63] fix(agent): typo --- axiom/nr_segment.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index b708c5274..780f04a15 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -111,12 +111,11 @@ typedef struct _nr_segment_external_t { } nr_segment_external_t; typedef struct _nr_segment_message_t { - char* transaction_guid; char* action; /* MUST be one of: produce, consume */ char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary Topic, Exchange */ - uint64_t destination_name; /* The name of the Queue, Topic, or Exchange; + char* destination_name; /* The name of the Queue, Topic, or Exchange; otherwise, Temp */ } nr_segment_message_t; From fef9fb233ffd155d6ce4576734c2434e63215216 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 18:57:13 -0700 Subject: [PATCH 26/63] feat(agent): Destroy Message Segment metadata --- axiom/nr_segment_private.c | 13 +++++++++++++ axiom/nr_segment_private.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index a60865afd..4a9629d18 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -39,6 +39,17 @@ void nr_segment_external_destroy_fields(nr_segment_external_t* external) { nr_free(external->procedure); } +void nr_segment_message_destroy_fields(nr_segment_message_t* message) { + if (nrunlikely(NULL == message)) { + return; + } + + nr_free(message->action); + nr_free(message->library); + nr_free(message->destination_type); + nr_free(message->destination_name); +} + void nr_segment_destroy_typed_attributes( nr_segment_type_t type, nr_segment_typed_attributes_t** attributes) { @@ -54,6 +65,8 @@ void nr_segment_destroy_typed_attributes( nr_segment_datastore_destroy_fields(&attrs->datastore); } else if (NR_SEGMENT_EXTERNAL == type) { nr_segment_external_destroy_fields(&attrs->external); + } else if (NR_SEGMENT_MESSAGE == type) { + nr_segment_message_destroy_fields(&attrs->external); } nr_free(attrs); diff --git a/axiom/nr_segment_private.h b/axiom/nr_segment_private.h index 70b499795..b2d6fe2c4 100644 --- a/axiom/nr_segment_private.h +++ b/axiom/nr_segment_private.h @@ -33,6 +33,13 @@ void nr_segment_datastore_destroy_fields(nr_segment_datastore_t* datastore); */ void nr_segment_external_destroy_fields(nr_segment_external_t* external); +/* + * Purpose : Free all data related to a segment's message metadata. + * + * Params : 1. A pointer to a segment's nr_segment_message_t structure. + */ +void nr_segment_message_destroy_fields(nr_segment_message_t* message); + /* * Purpose : Free all data related to a segment metric. * From ede290e8b3ad837d5676cc0069aa5a57741b79cb Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 23 Oct 2024 19:32:17 -0700 Subject: [PATCH 27/63] feat(agent): Add message typed attributes to a hash in the buffer --- axiom/nr_segment_traces.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index 846d89a55..ecde6173e 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -162,6 +162,15 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, ext->transaction_guid, false); add_hash_key_value_to_buffer_int(buf, "status", &ext->status); } break; + case NR_SEGMENT_MESSAGE: { + const nr_segment_message_t* message = &segment->typed_attributes->message; + add_hash_key_value_to_buffer(buf, "action", message->action, false); + add_hash_key_value_to_buffer(buf, "library", message->library, false); + add_hash_key_value_to_buffer(buf, "destination_type", + message->destination_type, false); + add_hash_key_value_to_buffer(buf, "destination_name", + message->destination_name, false); + } break; case NR_SEGMENT_CUSTOM: default: break; From 4d0209145500c803754b02e23b9f90e635cc1e98 Mon Sep 17 00:00:00 2001 From: ZNeumann Date: Wed, 30 Oct 2024 13:23:34 -0600 Subject: [PATCH 28/63] feat(agent): add message parameters ini (#981) --- agent/php_newrelic.h | 6 ++++++ agent/php_nrini.c | 11 +++++++++++ agent/scripts/newrelic.ini.template | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/agent/php_newrelic.h b/agent/php_newrelic.h index 1860b5167..6afaf531a 100644 --- a/agent/php_newrelic.h +++ b/agent/php_newrelic.h @@ -596,6 +596,12 @@ nrinibool_t nrinibool_t vulnerability_management_composer_api_enabled; /* newrelic.vulnerability_management.composer_api.enabled */ +/* + * Configuration options for recording Messaging APIs + */ +nrinibool_t + message_tracer_segment_parameters_enabled; /* newrelic.segment_tracer.segment_parameters.enabled */ + #if ZEND_MODULE_API_NO < ZEND_7_4_X_API_NO /* * pid and user_function_wrappers are used to store user function wrappers. diff --git a/agent/php_nrini.c b/agent/php_nrini.c index 6c21d1bdf..4a2f7c471 100644 --- a/agent/php_nrini.c +++ b/agent/php_nrini.c @@ -3100,6 +3100,17 @@ STD_PHP_INI_ENTRY_EX("newrelic.vulnerability_management.composer_api.enabled", newrelic_globals, nr_enabled_disabled_dh) +/* + * Messaging API + */ +STD_PHP_INI_ENTRY_EX("newrelic.message_tracer.segment_parameters.enabled", + "1", + NR_PHP_REQUEST, + nr_boolean_mh, + message_tracer_segment_parameters_enabled, + zend_newrelic_globals, + newrelic_globals, + nr_enabled_disabled_dh) PHP_INI_END() /* } */ void nr_php_register_ini_entries(int module_number TSRMLS_DC) { diff --git a/agent/scripts/newrelic.ini.template b/agent/scripts/newrelic.ini.template index 4ed06a091..b406628a9 100644 --- a/agent/scripts/newrelic.ini.template +++ b/agent/scripts/newrelic.ini.template @@ -1341,3 +1341,14 @@ newrelic.daemon.logfile = "/var/log/newrelic/newrelic-daemon.log" ; to gather package information for vulnerability management. ; ;newrelic.vulnerability_management.composer_api.enabled = false + +; Setting: newrelic.message_tracer.segment_parameters.enabled +; Type : boolean +; Scope : per-directory +; Default: true +; Info : If this setting is true, then message parameters will be captured and +; stored on their respective segments. While enabled, specific attributes +; can be filtered by using newrelic.attributes.include/exclude and +; newrelic.span_events.attributes.include/exclude +; +;newrelic.message_tracer.segment_parameters.enabled = true From 470d63d6b864e876d179326e774f5bb98a9deab3 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 26 Nov 2024 10:37:41 -0700 Subject: [PATCH 29/63] feat(agent): Add entity relationship building attributes to message segment. --- axiom/nr_segment.h | 27 +++++++++++++++++++++------ axiom/nr_segment_private.c | 8 +++++--- axiom/nr_segment_traces.c | 14 ++++++++++---- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 780f04a15..ab07993e3 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -111,12 +111,27 @@ typedef struct _nr_segment_external_t { } nr_segment_external_t; typedef struct _nr_segment_message_t { - char* action; /* MUST be one of: produce, consume */ - char* library; /* MUST be one of: JMS, RabbitMQ, SNS, SQS */ - char* destination_type; /* MUST be: Queue, Topic, Temporary Queue, Temporary - Topic, Exchange */ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp */ + /* + * Attributes needed for entity relationship building. + * Compare to OTEL attributes: + * https://opentelemetry.io/docs/specs/semconv/attributes-registry/cloud/ + * cloud.account.id, cloud.region, messaging.system and server.address are + * used to create relationships between APM and cloud services. It may not + * make sense to add these attributes unless they are used for creating one of + * the relationships in Entity Relationships. + */ + + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ + char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS + relationship.*/ + char* cloud_account_id; /*The cloud provider account ID. Needed for SQS + relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ + char* server_address; /* the server domain name or IP address. Needed for + MQBROKER relationship.*/ + } nr_segment_message_t; typedef struct _nr_segment_metric_t { diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index 4a9629d18..7b574006f 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -44,10 +44,12 @@ void nr_segment_message_destroy_fields(nr_segment_message_t* message) { return; } - nr_free(message->action); - nr_free(message->library); - nr_free(message->destination_type); nr_free(message->destination_name); + nr_free(message->messaging_system); + nr_free(message->cloud_region); + nr_free(message->cloud_account_id); + nr_free(message->cloud_resource_id); + nr_free(message->server_address); } void nr_segment_destroy_typed_attributes( diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index ecde6173e..b5b370d06 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -164,12 +164,18 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, } break; case NR_SEGMENT_MESSAGE: { const nr_segment_message_t* message = &segment->typed_attributes->message; - add_hash_key_value_to_buffer(buf, "action", message->action, false); - add_hash_key_value_to_buffer(buf, "library", message->library, false); - add_hash_key_value_to_buffer(buf, "destination_type", - message->destination_type, false); add_hash_key_value_to_buffer(buf, "destination_name", message->destination_name, false); + add_hash_key_value_to_buffer(buf, "messaging_system", + message->messaging_system, false); + add_hash_key_value_to_buffer(buf, "cloud_region", message->cloud_region, + false); + add_hash_key_value_to_buffer(buf, "cloud_account_id", + message->cloud_account_id, false); + add_hash_key_value_to_buffer(buf, "cloud_resource_id", + message->cloud_resource_id, false); + add_hash_key_value_to_buffer(buf, "server_address", + message->server_address, false); } break; case NR_SEGMENT_CUSTOM: default: From 5555b577a2871f1a2a69226384fc555f6ecbdf70 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 2 Dec 2024 07:14:12 -0700 Subject: [PATCH 30/63] feat(agent): Add message attribute functionality for message spans * Create enums for message attributes attributes * Add MESSAGE enum to nr_span_category_t span category * create nr_span_event_set_message --- axiom/nr_span_event.c | 29 +++++++++++++++++++++++++++++ axiom/nr_span_event.h | 27 ++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 965b297d9..58d8ab231 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -328,6 +328,35 @@ void nr_span_event_set_external_status(nr_span_event_t* event, nro_set_hash_ulong(event->agent_attributes, "http.statusCode", status); } +void nr_span_event_set_message(nr_span_event_t* event, + nr_span_event_message_member_t member, + const char* new_value) { + if (NULL == event || NULL == new_value) { + return; + } + + switch (member) { + case NR_SPAN_MESSAGE_DESTINATION_NAME: + nro_set_hash_string(event->agent_attributes, "messaging.destination.name", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_REGION: + nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: + nro_set_hash_string(event->intrinsics, "cloud.account.id", new_value); + break; + case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: + nro_set_hash_string(event->agent_attributes, "messaging.system", new_value); + break; + case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: + nro_set_hash_string(event->agent_attributes, "cloud.resource_id", new_value); + break; + case NR_SPAN_MESSAGE_SERVER_ADDRESS: + nro_set_hash_string(event->intrinsics, "server.address", new_value); + break; + } +} + /* * Getters. * diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 74ee2119c..37c9873e4 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -21,7 +21,8 @@ typedef struct _nr_span_event_t nr_span_event_t; typedef enum { NR_SPAN_GENERIC, NR_SPAN_HTTP, - NR_SPAN_DATASTORE + NR_SPAN_DATASTORE, + NR_SPAN_MESSAGE } nr_span_category_t; /* @@ -44,6 +45,18 @@ typedef enum { NR_SPAN_EXTERNAL_METHOD } nr_span_event_external_member_t; +/* + * Fields that can be set on message spans. + */ +typedef enum { + NR_SPAN_MESSAGE_DESTINATION_NAME, + NR_SPAN_MESSAGE_CLOUD_REGION, + NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, + NR_SPAN_MESSAGE_MESSAGING_SYSTEM, + NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + NR_SPAN_MESSAGE_SERVER_ADDRESS +} nr_span_event_message_member_t; + /* * The parent attributes that can be set on service entry spans. * parent.transportDuration is set in @@ -170,6 +183,18 @@ extern void nr_span_event_set_external(nr_span_event_t* event, extern void nr_span_event_set_external_status(nr_span_event_t* event, const uint64_t status); +/* + * Purpose : Set a message attribute. + * + * Params : 1. The target Span Event that should be changed. + * 2. The message attribute to be set. + * 3. The string value that the field will be after the function has + * executed. + */ +extern void nr_span_event_set_message(nr_span_event_t* event, + nr_span_event_message_member_t member, + const char* new_value); + /* * Purpose : Set a user attribute. * From 2c92b63a7d0686b73774a653573f062f09676eff Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 3 Dec 2024 14:41:41 -0700 Subject: [PATCH 31/63] feat(agent): Add nr_span_event_set_spankind create `nr_span_event_set_spankind` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for generic,http,datastore the logic of nr_span_event_set_category is overloaded because according agent-specs/Span-Events.md, span.kind could only ever be “client” for datastore and http spans and empty for generic spans. I debated extracting all the logic and making nr_span_event_set_spankind calls for those categories in nr_segment.c; however, since the span.kind values are always the same for those span categories, I left it in for now. Message spans however, will call nr_span_event_set_spankind separately and nr_span_event_set_category will only be used to set the category. --- axiom/nr_span_event.c | 50 +++++++++++++++++++++++++++++++++---------- axiom/nr_span_event.h | 22 +++++++++++++++++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 58d8ab231..df9cdc494 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -141,20 +141,45 @@ void nr_span_event_set_category(nr_span_event_t* event, switch (category) { case NR_SPAN_DATASTORE: nro_set_hash_string(event->intrinsics, "category", "datastore"); - nro_set_hash_string(event->intrinsics, "span.kind", "client"); + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); break; case NR_SPAN_GENERIC: nro_set_hash_string(event->intrinsics, "category", "generic"); - if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { - nro_set_hash_none(event->intrinsics, "span.kind"); - } - break; + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND) break; case NR_SPAN_HTTP: nro_set_hash_string(event->intrinsics, "category", "http"); + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + break; + + case NR_SPAN_MESSAGE: + nro_set_hash_string(event->intrinsics, "category", "message"); + break; + } +} + +void nr_span_event_set_spankind(nr_span_event_t* event, + nr_span_spankind_t spankind) { + if (NULL == event) { + return; + } + + switch (spankind) { + case NR_SPAN_PRODUCER: + nro_set_hash_string(event->intrinsics, "span.kind", "producer"); + break; + case NR_SPAN_CLIENT: nro_set_hash_string(event->intrinsics, "span.kind", "client"); break; + case NR_SPAN_CONSUMER: + nro_set_hash_string(event->intrinsics, "span.kind", "consumer"); + break; + case NR_SPAN_NO_SPANKIND: + if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { + nro_set_hash_none(event->intrinsics, "span.kind"); + } + break; } } @@ -329,15 +354,16 @@ void nr_span_event_set_external_status(nr_span_event_t* event, } void nr_span_event_set_message(nr_span_event_t* event, - nr_span_event_message_member_t member, - const char* new_value) { + nr_span_event_message_member_t member, + const char* new_value) { if (NULL == event || NULL == new_value) { return; } switch (member) { case NR_SPAN_MESSAGE_DESTINATION_NAME: - nro_set_hash_string(event->agent_attributes, "messaging.destination.name", new_value); + nro_set_hash_string(event->agent_attributes, "messaging.destination.name", + new_value); break; case NR_SPAN_MESSAGE_CLOUD_REGION: nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); @@ -346,12 +372,14 @@ void nr_span_event_set_message(nr_span_event_t* event, nro_set_hash_string(event->intrinsics, "cloud.account.id", new_value); break; case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: - nro_set_hash_string(event->agent_attributes, "messaging.system", new_value); + nro_set_hash_string(event->agent_attributes, "messaging.system", + new_value); break; case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: - nro_set_hash_string(event->agent_attributes, "cloud.resource_id", new_value); + nro_set_hash_string(event->agent_attributes, "cloud.resource_id", + new_value); break; - case NR_SPAN_MESSAGE_SERVER_ADDRESS: + case NR_SPAN_MESSAGE_SERVER_ADDRESS: nro_set_hash_string(event->intrinsics, "server.address", new_value); break; } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 37c9873e4..2ce236537 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -25,6 +25,26 @@ typedef enum { NR_SPAN_MESSAGE } nr_span_category_t; +/* + * The spankinds a span may fall into. + * This is set according to: + * 1) guidelines in agent-specs which state datastore and http spans set + * span.kind to client and further states that generic span.kind is unset + * + * 2) for message spans follow guidance here: + * https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/ + * which states that span.kind is + * a) producer when the operation type is create or send(if the context is + * create) b) client when the operation type is create or send(if the context is + * NOT create) c) consumer when the operation type is process + */ +typedef enum { + NR_SPAN_PRODUCER, + NR_SPAN_CLIENT, + NR_SPAN_CONSUMER, + NR_SPAN_NO_SPANKIND +} nr_span_spankind_t; + /* * Fields that can be set on datastore spans. */ @@ -128,6 +148,8 @@ extern void nr_span_event_set_transaction_name(nr_span_event_t* event, const char* transaction_name); extern void nr_span_event_set_category(nr_span_event_t* event, nr_span_category_t category); +extern void nr_span_event_set_category(nr_span_event_t* event, + nr_span_category_t category); extern void nr_span_event_set_timestamp(nr_span_event_t* event, nrtime_t time); extern void nr_span_event_set_duration(nr_span_event_t* event, nrtime_t duration); From 33f7ef2cc95907fd7f1ce7eb54ebad094a50414d Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 3 Dec 2024 15:53:39 -0700 Subject: [PATCH 32/63] feat(agent): Add span handling for message segments add message_type to nr_segment_message_t to inform the spankind since message_type is on nr_segment_message_t, give a default in case the message span is created but the nr_segment_message_t is not accessible added function nr_populate_message_spans added function nr_segment_set_message added message segment handling to nr_segment_to_span_event --- axiom/nr_segment.c | 64 +++++++++++++++++++++++++++++++++++++++++-- axiom/nr_segment.h | 5 ++-- axiom/nr_span_event.c | 2 ++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index fa91cf1b7..294839343 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -313,6 +313,35 @@ static void nr_populate_http_spans(nr_span_event_t* span_event, segment->typed_attributes->external.status); } +static void nr_populate_message_spans(nr_span_event_t* span_event, + const nr_segment_t* segment) { + nr_span_event_set_category(span_event, NR_SPAN_MESSAGE); + + if (nrunlikely(NULL == segment || NULL == segment->typed_attributes)) { + return; + } + + nr_span_event_set_spankind(span_event, + segment->typed_attributes->message_type); + + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_DESTINATION_NAME, + segment->typed_attributes->message.destination_name); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, + segment->typed_attributes->message.messaging_system); + nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION, + segment->typed_attributes->message.cloud_region); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, + segment->typed_attributes->message.cloud_account_id); + nr_span_event_set_message( + span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + segment->typed_attributes->message.cloud_resource_id); + nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS, + segment->typed_attributes->message.server_address); +} + static nr_status_t add_user_attribute_to_span_event(const char* key, const nrobj_t* val, void* ptr) { @@ -431,8 +460,8 @@ nr_span_event_t* nr_segment_to_span_event(nr_segment_t* segment) { nr_span_event_set_trusted_parent_id( event, nr_distributed_trace_inbound_get_trusted_parent_id( segment->txn->distributed_trace)); - nr_span_event_set_parent_id(event, - nr_distributed_trace_inbound_get_guid(segment->txn->distributed_trace)); + nr_span_event_set_parent_id(event, nr_distributed_trace_inbound_get_guid( + segment->txn->distributed_trace)); nr_span_event_set_transaction_name(event, segment->txn->name); @@ -482,6 +511,10 @@ nr_span_event_t* nr_segment_to_span_event(nr_segment_t* segment) { nr_populate_http_spans(event, segment); break; + case NR_SEGMENT_MESSAGE: + nr_populate_message_spans(event, segment); + break; + case NR_SEGMENT_CUSTOM: nr_span_event_set_category(event, NR_SPAN_GENERIC); break; @@ -599,6 +632,33 @@ bool nr_segment_set_external(nr_segment_t* segment, return true; } +bool nr_segment_set_message(nr_segment_t* segment, + const nr_segment_external_t* message) { + if (nrunlikely((NULL == segment) || (NULL == message))) { + return false; + } + + nr_segment_destroy_typed_attributes(segment->type, + &segment->typed_attributes); + segment->type = NR_SEGMENT_MESSAGE; + segment->typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + + // clang-format off + // Initialize the fields of the message attributes, one field per line. + segment->typed_attributes->message = (nr_segment_message_t){ + .message_type = message->message_type, + .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, + .destination_name = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, + .destination_name = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, + .destination_name = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, + .destination_name = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, + .destination_name = message->server_address ? nr_strdup(message->server_address) : NULL, + }; + // clang-format on + + return true; +} + bool nr_segment_add_child(nr_segment_t* parent, nr_segment_t* child) { if (nrunlikely((NULL == parent) || (NULL == child))) { return false; diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index ab07993e3..19b078d97 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -121,8 +121,9 @@ typedef struct _nr_segment_message_t { * the relationships in Entity Relationships. */ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + nr_span_spankind_t message_type; /*The type of message, producer/consumer.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index df9cdc494..ada4538dd 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -155,6 +155,8 @@ void nr_span_event_set_category(nr_span_event_t* event, case NR_SPAN_MESSAGE: nro_set_hash_string(event->intrinsics, "category", "message"); + /* give it a default value in case we exit before spankind is set*/ + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); break; } } From 7305105b7b45cf9fc466a26aaba82b180b3372f5 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 5 Dec 2024 15:56:50 -0700 Subject: [PATCH 33/63] feat(agent): Add new ini value to opts so axiom can see it Add the message_tracer_segment_parameters_enabled value to opts for use in axiom. --- agent/php_txn.c | 4 +++- axiom/nr_txn.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/agent/php_txn.c b/agent/php_txn.c index b5b57975c..bc0ea6b7e 100644 --- a/agent/php_txn.c +++ b/agent/php_txn.c @@ -854,6 +854,8 @@ nr_status_t nr_php_txn_begin(const char* appnames, opts.log_forwarding_log_level = NRINI(log_forwarding_log_level); opts.log_events_max_samples_stored = NRINI(log_events_max_samples_stored); opts.log_metrics_enabled = NRINI(log_metrics_enabled); + opts.message_tracer_segment_parameters_enabled + = NRINI(message_tracer_segment_parameters_enabled); /* * Enable the behaviour whereby asynchronous time is discounted from the total @@ -1165,7 +1167,7 @@ nr_status_t nr_php_txn_end(int ignoretxn, int in_post_deactivate TSRMLS_DC) { #if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \ && !defined OVERWRITE_ZEND_EXECUTE_DATA nr_segment_t* segment = nr_txn_get_current_segment(NRPRG(txn), NULL); - while(NULL != segment && segment != NRTXN(segment_root)) { + while (NULL != segment && segment != NRTXN(segment_root)) { nr_segment_end(&segment); segment = nr_txn_get_current_segment(NRPRG(txn), NULL); } diff --git a/axiom/nr_txn.h b/axiom/nr_txn.h index 8874260ec..55871f1b1 100644 --- a/axiom/nr_txn.h +++ b/axiom/nr_txn.h @@ -132,6 +132,8 @@ typedef struct _nrtxnopt_t { size_t log_events_max_samples_stored; /* The maximum number of log events per transaction */ bool log_metrics_enabled; /* Whether log metrics are enabled */ + bool message_tracer_segment_parameters_enabled; /* Determines whether to add + message attr */ } nrtxnopt_t; typedef enum _nrtxnstatus_cross_process_t { From b296507292e58b9fa4188ca41de64919bcfcbfdf Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 5 Dec 2024 19:00:18 -0700 Subject: [PATCH 34/63] feat(axiom): Add nr_segment_message functionality Includes creating metrics and ending the message segment. --- axiom/nr_segment.c | 17 ++- axiom/nr_segment.h | 7 +- axiom/nr_segment_message.c | 223 +++++++++++++++++++++++++++++++++++++ axiom/nr_segment_message.h | 59 ++++++++++ axiom/nr_segment_private.c | 2 +- axiom/nr_span_event.c | 4 +- axiom/nr_span_event.h | 6 +- 7 files changed, 301 insertions(+), 17 deletions(-) create mode 100644 axiom/nr_segment_message.c create mode 100644 axiom/nr_segment_message.h diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index 294839343..9a7dba1c9 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -322,8 +322,7 @@ static void nr_populate_message_spans(nr_span_event_t* span_event, } nr_span_event_set_spankind(span_event, - segment->typed_attributes->message_type); - + segment->typed_attributes->message.message_action); nr_span_event_set_message( span_event, NR_SPAN_MESSAGE_DESTINATION_NAME, segment->typed_attributes->message.destination_name); @@ -633,7 +632,7 @@ bool nr_segment_set_external(nr_segment_t* segment, } bool nr_segment_set_message(nr_segment_t* segment, - const nr_segment_external_t* message) { + const nr_segment_message_t* message) { if (nrunlikely((NULL == segment) || (NULL == message))) { return false; } @@ -646,13 +645,13 @@ bool nr_segment_set_message(nr_segment_t* segment, // clang-format off // Initialize the fields of the message attributes, one field per line. segment->typed_attributes->message = (nr_segment_message_t){ - .message_type = message->message_type, + .message_action = message->message_action, .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, - .destination_name = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, - .destination_name = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, - .destination_name = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, - .destination_name = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, - .destination_name = message->server_address ? nr_strdup(message->server_address) : NULL, + .cloud_region = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, + .cloud_account_id = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, + .messaging_system = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, + .cloud_resource_id = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, + .server_address = message->server_address ? nr_strdup(message->server_address) : NULL, }; // clang-format on diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 19b078d97..66b53ce5e 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -121,9 +121,10 @@ typedef struct _nr_segment_message_t { * the relationships in Entity Relationships. */ - nr_span_spankind_t message_type; /*The type of message, producer/consumer.*/ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + nr_span_spankind_t + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c new file mode 100644 index 000000000..6efcd1072 --- /dev/null +++ b/axiom/nr_segment_message.c @@ -0,0 +1,223 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nr_axiom.h" + +#include + +#include "nr_header.h" +#include "nr_segment_message.h" +#include "nr_segment_private.h" +#include "util_strings.h" +#include "util_url.h" + +/* + * Purpose : Set all the typed message attributes on the segment. + */ +static void nr_segment_message_set_attrs( + nr_segment_t* segment, + const nr_segment_message_params_t* params, + nrtxnopt_t options) { + nr_segment_message_t message_attributes = {0}; + + message_attributes.message_action = params->message_action; + + if (options.message_tracer_segment_parameters_enabled) { + message_attributes.destination_name = params->destination_name; + message_attributes.cloud_region = params->cloud_region; + message_attributes.cloud_account_id = params->cloud_account_id; + message_attributes.messaging_system = params->messaging_system; + message_attributes.cloud_resource_id = params->cloud_resource_id; + message_attributes.server_address = params->server_address; + } + + nr_segment_set_message(segment, &message_attributes); +} + +/* + * Purpose : Create metrics for a completed message call and set the segment + * name. + * + * Metrics created during this call + * ---------------------------------------------------------------------------------- + * MessageBroker/all Unscoped + * Always MessageBroker/{library}/all Scoped Always + * + * Metrics created based on MessageBroker/all (in nr_txn_create_rollup_metrics) + * ---------------------------------------------------------------------------------- + * MessageBroker/allWeb Unscoped Web + * MessageBroker/allOther Unscoped + * non-Web + * + * Segment name + * ----------------------------------------------------------------------------------- + * MessageBroker/{library}/all Always + * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * + * + * These metrics are dictated by the spec located here: + * https://source.datanerd.us/agents/agent-specs/blob/master/APIs/messaging.md#metrics + * When the destination is temporary (such as a temporary queue, or a temporary + * topic), the destination name MUST be omitted. The metric segment 'Named' MUST + * be replaced with 'Temp'. The DestinationType segment SHOULD NOT contain + * "Temporary". Thus, "Temporary " should be removed from the destination type + * enum before metric use. Examples: MessageBroker/JMS/Queue/Produce/Temp, + * MessageBroker/JMS/Topic/Produce/Temp + * + * Further note that for pull-style messaging, the transaction segment name MUST + * be equal to the scoped metric name (e.g., + * MessageBroker/JMS/Queue/Produce/Named/SortQueue) + * + * + * Params : 1. The message segment. + * 2. Message parameters + * 3. Duration of the segment + * + * Returns : the scoped metric that was created. Caller is responsible for + * freeing this value. + */ + +static char* nr_segment_message_create_metrics( + nr_segment_t* segment, + const nr_segment_message_params_t* message_params, + nrtime_t duration) { + const char* action_string = NULL; + const char* destination_type_string = NULL; + char* rollup_metric = NULL; + char* scoped_metric = NULL; + + if (NULL == segment) { + return NULL; + } + + if (NULL == message_params || NULL == message_params->library) { + return NULL; + } + + /* Rollup metric. + * + * This has to be created on the transaction in order to create + * MessageBroker/allWeb and MessageBroker/allOther and to calculate + * messageDuration later on. + */ + + nrm_force_add(segment->txn->unscoped_metrics, "MessageBroker/all", duration); + + rollup_metric = nr_formatf("MessageBroker/%s/all", message_params->library); + nrm_force_add(segment->txn->unscoped_metrics, rollup_metric, duration); + nr_free(rollup_metric); + + /* + * Note: although the concept of Temporary queues/topics is detailed in the + * spec, in practice, we are unlikely to encounter it as it is currently only + * meaningful with JMS (Java Message Service). It is added here for adherence + * with spec. + */ + + if (NR_SPAN_PRODUCER == message_params->message_action) { + action_string = "Produce"; + } else if (NR_SPAN_CONSUMER == message_params->message_action) { + action_string = "Consume"; + } else { + action_string = "Unknown"; + } + + switch (message_params->destination_type) { + case NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE: + case NR_MESSAGE_DESTINATION_TYPE_QUEUE: + destination_type_string = "Queue"; + break; + case NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC: + case NR_MESSAGE_DESTINATION_TYPE_TOPIC: + destination_type_string = "Topic"; + break; + case NR_MESSAGE_DESTINATION_TYPE_EXCHANGE: + destination_type_string = "Exchange"; + break; + default: + destination_type_string = "Unknown"; + break; + } + /* + * Create the scoped metric + * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + */ + if (NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE == message_params->destination_type + || NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC + == message_params->destination_type) { + scoped_metric + = nr_formatf("MessageBroker/%s/%s/%s/Temp", message_params->library, + destination_type_string, action_string); + } else { + scoped_metric = nr_formatf( + "MessageBroker/%s/%s/%s/Named/%s", message_params->library, + destination_type_string, action_string, + message_params->destination_name ? message_params->destination_name + : "Unknown"); + } + + nr_segment_add_metric(segment, scoped_metric, true); + + /* + * The scoped metric will be used as the segment name. + */ + return scoped_metric; +} + +bool nr_segment_message_end(nr_segment_t** segment_ptr, + const nr_segment_message_params_t* message_params) { + bool rv = false; + nr_segment_t* segment; + nrtime_t duration = 0; + char* scoped_metric = NULL; + + if (NULL == segment_ptr) { + return false; + } + + segment = *segment_ptr; + + if (NULL == segment || NULL == message_params || NULL == segment->txn) { + return false; + } + + /* + * We don't want message segments to have any children, as + * this would scramble the exclusive time calculation. + * Additionally, because it makes http calls under the hood, + * we don't want additional external calls created for this same txn. + * Therefore, we delete all children of the message segment. + */ + if (segment) { + for (size_t i = 0; i < nr_segment_children_size(&segment->children); i++) { + nr_segment_t* child = nr_segment_children_get(&segment->children, i); + nr_segment_discard(&child); + } + } + + nr_segment_message_set_attrs(segment, message_params, segment->txn->options); + + /* + * We set the end time here because we need the duration, (nr_segment_end will + * not overwrite this value if it's already set). + */ + if (!segment->stop_time) { + segment->stop_time + = nr_time_duration(nr_txn_start_time(segment->txn), nr_get_time()); + } + duration = nr_time_duration(segment->start_time, segment->stop_time); + + scoped_metric + = nr_segment_message_create_metrics(segment, message_params, duration); + nr_segment_set_name(segment, scoped_metric); + + rv = nr_segment_end(&segment); + + nr_free(scoped_metric); + + return rv; +} diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h new file mode 100644 index 000000000..d6b38b8ee --- /dev/null +++ b/axiom/nr_segment_message.h @@ -0,0 +1,59 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NR_SEGMENT_MESSAGE_HDR +#define NR_SEGMENT_MESSAGE_HDR + +#include "nr_segment.h" + +/* + * Note: + * CAT is EOLed and this feature is not compatible with CAT. + */ + +typedef enum _nr_segment_message_destination_type_t { + NR_MESSAGE_DESTINATION_TYPE_QUEUE, + NR_MESSAGE_DESTINATION_TYPE_TOPIC, + NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, + NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, + NR_MESSAGE_DESTINATION_TYPE_EXCHANGE +} nr_segment_message_destination_type_t; + +typedef struct { + /* All strings are null-terminated. When unset, the strings are ingored. */ + + /* Only used for creating metrics. */ + + char* library; /* Library; Possible values are SQS, SNS, RabbitMQ, JMS */ + nr_segment_message_destination_type_t + destination_type; /* Named/temp queue/topic/exchange */ + + /* Used for creating message attributes. */ + nr_span_spankind_t + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /* The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship. */ + char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS + relationship.*/ + char* cloud_account_id; /*The cloud provider account ID. Needed for SQS + relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ + char* server_address; /* the server domain name or IP address. Needed for + MQBROKER relationship.*/ + +} nr_segment_message_params_t; + +/* + * Purpose : End a message segment and record metrics. + * + * Params : 1. nr_segment_message_params_t + * + * Returns: true on success. + */ +extern bool nr_segment_message_end(nr_segment_t** segment, + const nr_segment_message_params_t* params); + +#endif diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index 7b574006f..283ec0067 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -68,7 +68,7 @@ void nr_segment_destroy_typed_attributes( } else if (NR_SEGMENT_EXTERNAL == type) { nr_segment_external_destroy_fields(&attrs->external); } else if (NR_SEGMENT_MESSAGE == type) { - nr_segment_message_destroy_fields(&attrs->external); + nr_segment_message_destroy_fields(&attrs->message); } nr_free(attrs); diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index ada4538dd..0190349fa 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -146,7 +146,8 @@ void nr_span_event_set_category(nr_span_event_t* event, case NR_SPAN_GENERIC: nro_set_hash_string(event->intrinsics, "category", "generic"); - nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND) break; + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + break; case NR_SPAN_HTTP: nro_set_hash_string(event->intrinsics, "category", "http"); @@ -178,6 +179,7 @@ void nr_span_event_set_spankind(nr_span_event_t* event, nro_set_hash_string(event->intrinsics, "span.kind", "consumer"); break; case NR_SPAN_NO_SPANKIND: + default: if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { nro_set_hash_none(event->intrinsics, "span.kind"); } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 2ce236537..16020b7b0 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -29,7 +29,7 @@ typedef enum { * The spankinds a span may fall into. * This is set according to: * 1) guidelines in agent-specs which state datastore and http spans set - * span.kind to client and further states that generic span.kind is unset + * span.kind to client and further states that generic span.kind is unset * * 2) for message spans follow guidance here: * https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/ @@ -148,8 +148,8 @@ extern void nr_span_event_set_transaction_name(nr_span_event_t* event, const char* transaction_name); extern void nr_span_event_set_category(nr_span_event_t* event, nr_span_category_t category); -extern void nr_span_event_set_category(nr_span_event_t* event, - nr_span_category_t category); +extern void nr_span_event_set_spankind(nr_span_event_t* event, + nr_span_spankind_t category); extern void nr_span_event_set_timestamp(nr_span_event_t* event, nrtime_t time); extern void nr_span_event_set_duration(nr_span_event_t* event, nrtime_t duration); From d511086561989610ae9a31251ac55cf1e0260ff4 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 06:37:17 -0700 Subject: [PATCH 35/63] feat(axiom): Added message getters to span_event --- axiom/nr_span_event.c | 27 +++++++++++++++++++++++++++ axiom/nr_span_event_private.h | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 0190349fa..9da8532f4 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -439,6 +439,7 @@ SPAN_EVENT_GETTER_STRING(nr_span_event_get_transaction_name, intrinsics, "transaction.name") SPAN_EVENT_GETTER_STRING(nr_span_event_get_category, intrinsics, "category") +SPAN_EVENT_GETTER_STRING(nr_span_event_get_spankind, intrinsics, "span.kind") SPAN_EVENT_GETTER_TIME(nr_span_event_get_timestamp, intrinsics, "timestamp") SPAN_EVENT_GETTER_DOUBLE(nr_span_event_get_duration, intrinsics, "duration") SPAN_EVENT_GETTER_DOUBLE(nr_span_event_get_priority, intrinsics, "priority") @@ -527,6 +528,32 @@ const char* nr_span_event_get_external(const nr_span_event_t* event, return NULL; } +const char* nr_span_event_get_message(const nr_span_event_t* event, + nr_span_event_message_member_t member) { + if (NULL == event) { + return NULL; + } + + switch (member) { + case NR_SPAN_MESSAGE_DESTINATION_NAME: + return nro_get_hash_string(event->agent_attributes, + "messaging.destination.name", NULL); + case NR_SPAN_MESSAGE_CLOUD_REGION: + return nro_get_hash_string(event->agent_attributes, "cloud.region", NULL); + case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: + return nro_get_hash_string(event->intrinsics, "cloud.account.id", NULL); + case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: + return nro_get_hash_string(event->agent_attributes, "messaging.system", + NULL); + case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: + return nro_get_hash_string(event->agent_attributes, "cloud.resource_id", + NULL); + case NR_SPAN_MESSAGE_SERVER_ADDRESS: + return nro_get_hash_string(event->intrinsics, "server.address", NULL); + } + return NULL; +} + void nr_span_event_set_attribute_user(nr_span_event_t* event, const char* name, const nrobj_t* value) { diff --git a/axiom/nr_span_event_private.h b/axiom/nr_span_event_private.h index 349c50538..4f55c6f2f 100644 --- a/axiom/nr_span_event_private.h +++ b/axiom/nr_span_event_private.h @@ -28,6 +28,7 @@ extern const char* nr_span_event_get_name(const nr_span_event_t* event); extern const char* nr_span_event_get_transaction_name( const nr_span_event_t* event); extern const char* nr_span_event_get_category(const nr_span_event_t* event); +extern const char* nr_span_event_get_spankind(const nr_span_event_t* event); extern nrtime_t nr_span_event_get_timestamp(const nr_span_event_t* event); extern double nr_span_event_get_duration(const nr_span_event_t* event); extern double nr_span_event_get_priority(const nr_span_event_t* event); @@ -44,6 +45,9 @@ extern const char* nr_span_event_get_external( const nr_span_event_t* event, nr_span_event_external_member_t member); extern uint64_t nr_span_event_get_external_status(const nr_span_event_t* event); +extern const char* nr_span_event_get_message( + const nr_span_event_t* event, + nr_span_event_message_member_t member); extern const char* nr_span_event_get_error_message( const nr_span_event_t* event); extern const char* nr_span_event_get_error_class(const nr_span_event_t* event); From fc43234094d7b8ef1c8b5cb8a41889eff9610ac3 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 06:39:21 -0700 Subject: [PATCH 36/63] feat(axiom): Add span message related span get/set functionality * test get/set spankind * test get/set message span members --- axiom/tests/test_span_event.c | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index 85ca788b9..3d741e355 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -256,6 +256,47 @@ static void test_span_event_category(void) { tlib_pass_if_str_equal("Category should be the one we set - http", "http", nr_span_event_get_category(event)); + nr_span_event_set_category(event, NR_SPAN_MESSAGE); + tlib_pass_if_str_equal("Category should be the one we set - message", + "message", nr_span_event_get_category(event)); + + nr_span_event_destroy(&event); +} + +static void test_span_event_spankind(void) { + nr_span_event_t* event = nr_span_event_create(); + + // Test : the default is NULL (spankind must be explicitly set) + tlib_pass_if_str_equal("The default category", NULL, + nr_span_event_get_spankind(event)); + + // Test : A null event returns NULL + tlib_pass_if_null("The default category", nr_span_event_get_spankind(NULL)); + + // Test : passing a NULL event should not blow up + nr_span_event_set_spankind(NULL, NR_SPAN_PRODUCER); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + tlib_pass_if_str_equal( + "Spankind should be the one we set - no spankind (NULL)", NULL, + nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_PRODUCER); + tlib_pass_if_str_equal("Spankind should be the one we set - producer", + "producer", nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + tlib_pass_if_str_equal("Spankind should be the one we set - client", "client", + nr_span_event_get_spankind(event)); + + // Test : setting the spankind back and forth + nr_span_event_set_spankind(event, NR_SPAN_CONSUMER); + tlib_pass_if_str_equal("Spankind should be the one we set - consumer", + "consumer", nr_span_event_get_spankind(event)); + nr_span_event_destroy(&event); } @@ -434,6 +475,89 @@ static void test_span_events_extern_get_and_set(void) { nr_span_event_destroy(&span); } +static void test_span_event_message_string_get_and_set(void) { + nr_span_event_t* event = nr_span_event_create(); + + // Test : that is does not blow up when we give the setter a NULL pointer + nr_span_event_set_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME, "wallaby"); + tlib_pass_if_null( + "the destination name should still be NULL", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, NULL); + tlib_pass_if_null( + "given a NULL value we should get a NULL", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : the getter should not blow up when we send it an event with a NULL + // component + tlib_pass_if_null( + "NULL event -> NULL component", + nr_span_event_get_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : setting the cloud region back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); + + // Test : setting the destination name back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); + + // Test : setting the cloud account id back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); + + // Test : setting the messaging system back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); + + // Test : setting the cloud resource id back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, + "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); + + // Test : setting the server address back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + + nr_span_event_destroy(&event); +} + static void test_span_event_error(void) { nr_span_event_t* event = nr_span_event_create(); @@ -614,10 +738,12 @@ void test_main(void* p NRUNUSED) { test_span_event_name(); test_span_event_transaction_name(); test_span_event_category(); + test_span_event_spankind(); test_span_event_timestamp(); test_span_event_duration(); test_span_event_datastore_string_get_and_set(); test_span_events_extern_get_and_set(); + test_span_event_message_string_get_and_set(); test_span_event_error(); test_span_event_set_attribute_user(); test_span_event_txn_parent_attributes(); From d8522f7eecfc185f0af5c36c5597e843785a081a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 09:27:01 -0700 Subject: [PATCH 37/63] feat(axiom): Add message segment tests Sorry clang-format added some unrelated formatting. --- axiom/tests/test_segment_traces.c | 183 +++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 27 deletions(-) diff --git a/axiom/tests/test_segment_traces.c b/axiom/tests/test_segment_traces.c index 450ea8af6..4ca0074a8 100644 --- a/axiom/tests/test_segment_traces.c +++ b/axiom/tests/test_segment_traces.c @@ -51,6 +51,10 @@ tlib_pass_if_str_equal("category", "http", \ nr_span_event_get_category(evt)); \ break; \ + case NR_SPAN_MESSAGE: \ + tlib_pass_if_str_equal("category", "message", \ + nr_span_event_get_category(evt)); \ + break; \ default: \ tlib_pass_if_true("invalid category", false, "category=%s", \ nr_span_event_get_category(evt)); \ @@ -86,6 +90,29 @@ tlib_pass_if_int_equal("status", expected_status, \ nr_span_event_get_external_status(span_event)); +#define SPAN_EVENT_COMPARE_MESSAGE( \ + span_event, expected_destination_name, expected_cloud_region, \ + expected_cloud_account_id, expected_messaging_system, \ + expected_cloud_resource_id, expected_server_address) \ + tlib_pass_if_str_equal("destination.name", expected_destination_name, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ + tlib_pass_if_str_equal( \ + "cloud.region", expected_cloud_region, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION)); \ + tlib_pass_if_str_equal("cloud.account.id", expected_cloud_account_id, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); \ + tlib_pass_if_str_equal("messaging.system", expected_messaging_system, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); \ + tlib_pass_if_str_equal("cloud.resource_id", expected_cloud_resource_id, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); \ + tlib_pass_if_str_equal( \ + "server.address", expected_server_address, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + static void nr_vector_span_event_dtor(void* element, void* userdata NRUNUSED) { nr_span_event_destroy((nr_span_event_t**)&element); } @@ -652,13 +679,15 @@ static void test_json_print_segments_invalid_typed_attributes(void) { nr_span_event_t* evt_root; nr_span_event_t* evt_a; nr_span_event_t* evt_b; + nr_span_event_t* evt_c; nrtxn_t txn = {0}; // clang-format off - nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 9000}; + nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 11000}; nr_segment_t A = {.txn = &txn, .start_time = 1000, .stop_time = 6000}; nr_segment_t B = {.txn = &txn, .start_time = 6000, .stop_time = 8000}; + nr_segment_t C = {.txn = &txn, .start_time = 9000, .stop_time = 10000}; // clang-format on buf = nr_buffer_create(4096, 4096); @@ -668,20 +697,23 @@ static void test_json_print_segments_invalid_typed_attributes(void) { /* Mock up the transaction */ mock_txn(&txn, &root); txn.abs_start_time = 1000; - txn.segment_count = 2; + txn.segment_count = 3; /* Create a collection of mock segments */ nr_segment_children_init(&root.children); nr_segment_add_child(&root, &A); nr_segment_add_child(&root, &B); + nr_segment_add_child(&root, &C); root.name = nr_string_add(txn.trace_strings, "WebTransaction/*"); A.name = nr_string_add(txn.trace_strings, "A"); B.name = nr_string_add(txn.trace_strings, "B"); + C.name = nr_string_add(txn.trace_strings, "C"); A.type = NR_SEGMENT_EXTERNAL; B.type = NR_SEGMENT_DATASTORE; + C.type = NR_SEGMENT_MESSAGE; /* * Test : Normal operation @@ -689,23 +721,27 @@ static void test_json_print_segments_invalid_typed_attributes(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, NULL, NULL, &txn, &root, segment_names); tlib_pass_if_bool_equal("success", true, rv); - test_buffer_contents("datastore params", buf, - "[0,9,\"`0\",{},[[1,6," - "\"`1\",{},[]],[6,8," - "\"`2\",{},[]]]]"); + test_buffer_contents("segment attributes", buf, + "[0,11,\"`0\",{}," + "[[1,6,\"`1\",{},[]]," + "[6,8,\"`2\",{},[]]," + "[9,10,\"`3\",{},[]]]]"); - tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 3); + tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 4); evt_root = (nr_span_event_t*)nr_vector_get(span_events, 0); evt_a = (nr_span_event_t*)nr_vector_get(span_events, 1); evt_b = (nr_span_event_t*)nr_vector_get(span_events, 2); + evt_c = (nr_span_event_t*)nr_vector_get(span_events, 3); SPAN_EVENT_COMPARE(evt_root, "WebTransaction/*", NR_SPAN_GENERIC, NULL, 1000, - 9000); + 11000); SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_HTTP, evt_root, 2000, 5000); SPAN_EVENT_COMPARE_EXTERNAL(evt_a, NULL, NULL, NULL, 0); SPAN_EVENT_COMPARE(evt_b, "B", NR_SPAN_DATASTORE, evt_root, 7000, 2000); SPAN_EVENT_COMPARE_DATASTORE(evt_b, NULL, NULL, NULL, NULL); + SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_MESSAGE, evt_root, 10000, 1000); + SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL, NULL, NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -713,6 +749,7 @@ static void test_json_print_segments_invalid_typed_attributes(void) { nr_segment_destroy_fields(&A); nr_segment_destroy_fields(&B); + nr_segment_destroy_fields(&C); cleanup_mock_txn(&txn); nr_string_pool_destroy(&segment_names); @@ -904,7 +941,95 @@ static void test_json_print_segments_external_async_user_attrs(void) { nr_vector_destroy(&span_events); } -static void test_json_print_segments_datastore_external(void) { +static void test_json_print_segments_message_attributes(void) { + bool rv; + nrbuf_t* buf; + nr_vector_t* span_events; + nrpool_t* segment_names; + + nrtxn_t txn = {0}; + + nr_span_event_t* evt_root; + nr_span_event_t* evt_a; + + // clang-format off + nr_segment_t root = {.txn = &txn, .start_time = 0, .stop_time = 9000}; + nr_segment_t A = {.txn = &txn, .start_time = 1000, .stop_time = 6000}; + // clang-format on + + buf = nr_buffer_create(4096, 4096); + span_events = nr_vector_create(9, nr_vector_span_event_dtor, NULL); + segment_names = nr_string_pool_create(); + + /* Mock up the transaction */ + mock_txn(&txn, &root); + txn.abs_start_time = 1000; + txn.segment_count = 2; + + /* Create a collection of mock segments */ + + /* ------root------- + * ------A------ + */ + + nr_segment_children_init(&root.children); + + nr_segment_add_child(&root, &A); + + root.name = nr_string_add(txn.trace_strings, "WebTransaction/*"); + A.name = nr_string_add(txn.trace_strings, "A"); + + A.type = NR_SEGMENT_MESSAGE; + A.attributes = NULL; + A.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + A.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); + A.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); + A.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); + A.typed_attributes->message.destination_name = nr_strdup("queue_name"); + A.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + A.typed_attributes->message.server_address = nr_strdup("localhost"); + + /* + * Test : Normal operation + */ + rv = nr_segment_traces_json_print_segments(buf, span_events, NULL, NULL, &txn, + &root, segment_names); + tlib_pass_if_bool_equal("success", true, rv); + test_buffer_contents("message attributes", buf, + "[0,9,\"`0\",{},[[1,6,\"`1\",{" + "\"destination_name\":\"queue_name\"," + "\"messaging_system\":\"aws_sqs\"," + "\"cloud_region\":\"us-west-1\"," + "\"cloud_account_id\":\"12345678\"," + "\"cloud_resource_id\":\"resource_id_info\"," + "\"server_address\":\"localhost\"" + "},[]]]]"); + + tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 2); + + evt_root = (nr_span_event_t*)nr_vector_get(span_events, 0); + evt_a = (nr_span_event_t*)nr_vector_get(span_events, 1); + + SPAN_EVENT_COMPARE(evt_root, "WebTransaction/*", NR_SPAN_GENERIC, NULL, 1000, + 9000); + SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_MESSAGE, evt_root, 2000, 5000); + SPAN_EVENT_COMPARE_MESSAGE(evt_a, "queue_name", "us-west-1", "12345678", + "aws_sqs", "resource_id_info", "localhost"); + + /* Clean up */ + nr_segment_children_deinit(&root.children); + nr_segment_destroy_fields(&root); + + nr_segment_destroy_fields(&A); + + cleanup_mock_txn(&txn); + nr_string_pool_destroy(&segment_names); + + nr_buffer_destroy(&buf); + nr_vector_destroy(&span_events); +} + +static void test_json_print_segments_datastore_external_message(void) { bool rv; nrbuf_t* buf; nr_vector_t* span_events; @@ -972,12 +1097,12 @@ static void test_json_print_segments_datastore_external(void) { C.typed_attributes->external.transaction_guid = nr_strdup("guid"); C.typed_attributes->external.status = 200; - D.type = NR_SEGMENT_DATASTORE; + D.type = NR_SEGMENT_MESSAGE; D.attributes = NULL; D.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); - D.typed_attributes->datastore.sql = nr_strdup("SELECT pass"); - D.typed_attributes->datastore.instance.host = nr_strdup("localhost"); - D.typed_attributes->datastore.instance.database_name = nr_strdup("db"); + D.typed_attributes->message.destination_name = nr_strdup("queue_name"); + D.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + D.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); /* * Test : Normal operation @@ -999,9 +1124,9 @@ static void test_json_print_segments_datastore_external(void) { "\"transaction_guid\":\"guid\"," "\"status\":200},[]]," "[5,6,\"`4\"," - "{\"host\":\"localhost\"," - "\"database_name\":\"db\"," - "\"sql\":\"SELECT pass\"},[]]]]]]"); + "{\"destination_name\":\"queue_name\"," + "\"messaging_system\":\"aws_sqs\"," + "\"cloud_region\":\"us-west-1\"},[]]]]]]"); tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 5); @@ -1019,9 +1144,9 @@ static void test_json_print_segments_datastore_external(void) { "localhost:3308"); SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_HTTP, evt_a, 5000, 1000); SPAN_EVENT_COMPARE_EXTERNAL(evt_c, "example.com", "GET", "curl", 200); - SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_DATASTORE, evt_a, 6000, 1000); - SPAN_EVENT_COMPARE_DATASTORE(evt_d, "localhost", "db", "SELECT pass", - "localhost:unknown"); + SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_MESSAGE, evt_a, 6000, 1000); + SPAN_EVENT_COMPARE_MESSAGE(evt_d, "queue_name", "us-west-1", NULL, "aws_sqs", + NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -1146,8 +1271,8 @@ static void test_json_print_segments_async_basic(void) { * * These diagrams all follow the same pattern: time is shown in seconds on * the first row, followed by the ROOT node, and then individual contexts - * with their nodes. The "main" context indicates that no async_context will - * be attached to nodes in that context. + * with their nodes. The "main" context indicates that no async_context + * will be attached to nodes in that context. * * time (s) 0 1 2 3 4 5 6 7 8 9 10 * |------------------- ROOT -------------------| @@ -1245,8 +1370,8 @@ static void test_json_print_segments_async_multi_child(void) { /* * Multiple children test: main context lasts the same timespan as ROOT, and - * spawns one child context with three nodes for part of its run time, one of - * which has a duplicated name. + * spawns one child context with three nodes for part of its run time, one + * of which has a duplicated name. * * time (s) 0 1 2 3 4 5 6 7 8 9 10 * |------------------- ROOT -------------------| @@ -1955,7 +2080,8 @@ static void test_json_print_segments_with_sampling_cousin_parent(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, set, set, &txn, &root, segment_names); tlib_pass_if_bool_equal( - "Printing JSON for a sampled cousin parent tree of segments must succeed", + "Printing JSON for a sampled cousin parent tree of segments must " + "succeed", true, rv); test_buffer_contents("Cousin Parent", buf, "[0,14,\"`0\",{},[[1,5,\"`1\",{},[[1,3,\"`2\",{},[]]]],[" @@ -2269,7 +2395,8 @@ static void test_json_print_segments_with_sampling_genghis_khan(void) { rv = nr_segment_traces_json_print_segments(buf, span_events, set, set, &txn, &root, segment_names); tlib_pass_if_bool_equal( - "Printing JSON for a genghis khan sampled tree of segments must succeed", + "Printing JSON for a genghis khan sampled tree of segments must " + "succeed", true, rv); test_buffer_contents("genghis khan", buf, "[0,9,\"`0\",{},[[1,6,\"`1\",{},[]],[3,4,\"`2\",{},[]],[" @@ -2470,7 +2597,8 @@ static void test_trace_create_data_bad_parameters(void) { agent_attributes, user_attributes, intrinsics, true, false); tlib_pass_if_null( - "A transaction with more than NR_MAX_SEGMENTS segments must not succeed " + "A transaction with more than NR_MAX_SEGMENTS segments must not " + "succeed " "in creating " "a trace", metadata.out->trace_json); @@ -2786,9 +2914,10 @@ void test_main(void* p NRUNUSED) { test_json_print_segments_hanoi(); test_json_print_segments_three_siblings(); test_json_print_segments_two_generations(); - test_json_print_segments_datastore_external(); + test_json_print_segments_datastore_external_message(); test_json_print_segments_datastore_params(); test_json_print_segments_external_async_user_attrs(); + test_json_print_segments_message_attributes(); test_json_print_segments_async_basic(); test_json_print_segments_async_multi_child(); From 9ab2928dda5b282350631c6ded6e7b6415eb0cda Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 10:10:43 -0700 Subject: [PATCH 38/63] feat(axiom): Add tests to ensure message segment destroy clean up properly --- axiom/tests/test_segment_private.c | 64 +++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index e586f1f4f..e4407aa8f 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -25,6 +25,7 @@ static void test_bad_parameters(void) { nr_segment_destroy_fields(NULL); nr_segment_datastore_destroy_fields(NULL); nr_segment_external_destroy_fields(NULL); + nr_segment_message_destroy_fields(NULL); nr_segment_metric_destroy_fields(NULL); nr_segment_error_destroy_fields(NULL); } @@ -205,7 +206,6 @@ static void test_set_custom(void) { tlib_pass_if_int_equal( "Setting an untyped segment to custom must set the type", (int)NR_SEGMENT_CUSTOM, (int)s.type); - nr_segment_set_datastore(&t, &d); tlib_pass_if_true("Setting a datastore segment to custom must be successful", nr_segment_set_custom(&t), "Expected true"); @@ -316,6 +316,51 @@ static void test_set_destroy_external_fields(void) { &s.typed_attributes); } +static void test_set_destroy_message_fields(void) { + nr_segment_t s = {.type = NR_SEGMENT_MESSAGE}; + + nr_segment_message_t m = {.message_action = NR_SPAN_CLIENT, + .cloud_region = "my_cloud_region", + .cloud_account_id = "12345678", + .messaging_system = "my_messaging_system", + .cloud_resource_id = "my_cloud_resource_id", + .server_address = "localhost"}; + + nr_segment_external_t e = {.transaction_guid = "transaction_guid", + .uri = "uri", + .library = "library", + .procedure = "procedure", + .status = 200}; + /* + * Test : Bad parameters. + */ + tlib_pass_if_false( + "Setting a NULL segment's message attributes must not be successful", + nr_segment_set_message(NULL, &m), "Expected false"); + + tlib_pass_if_false( + "Setting a segment with NULL message attributes must not be successful", + nr_segment_set_message(&s, NULL), "Expected false"); + + /* + * Test : Normal operation. + */ + tlib_pass_if_true("Setting a segment's message attributes must be successful", + nr_segment_set_message(&s, &m), "Expected true"); + + tlib_pass_if_true( + "Setting a segment from message attributes to external attributes must " + "be successful", + nr_segment_set_external(&s, &e), "Expected true"); + + /* Valgrind shall affirm that the attributes for s were cleaned + * up when the segment type was changed from message to external. + */ + + /* Clean up */ + nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); +} + static void test_destroy_typed_attributes(void) { nr_segment_t s = {0}; char* test_string = "0123456789"; @@ -328,6 +373,22 @@ static void test_destroy_typed_attributes(void) { nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, NULL); nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, NULL); + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); + + /* + * Test : Clean up typed attributes for a message segment + */ + s.type = NR_SEGMENT_MESSAGE; + s.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); + s.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); + s.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); + s.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); + s.typed_attributes->message.destination_name = nr_strdup("queue_name"); + s.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); + s.typed_attributes->message.server_address = nr_strdup("localhost"); + + nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); /* * Test : Clean up typed attributes for an external segment @@ -394,6 +455,7 @@ void test_main(void* p NRUNUSED) { test_set_custom(); test_set_destroy_datastore_fields(); test_set_destroy_external_fields(); + test_set_destroy_message_fields(); test_destroy_typed_attributes(); test_destroy_fields(); test_destroy_metric(); From 6932595b740cf04e4c277e103b6f4748ef932de9 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 13:18:42 -0700 Subject: [PATCH 39/63] feat(axiom): Handle message segment metric rollups Rollups happen in 2 places in nr_txn.c nr_error_to_event And nr_txn_event_intrinsics * fixed externalCallCount was getting set in nr_error_to_event but not in nr_txn_event_intrinsics * Added messageCallCount/messageDuration to both functions --- axiom/nr_txn.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index 774c44671..e6363bcbe 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -60,10 +60,8 @@ struct _nr_txn_attribute_t { #define NR_TXN_ATTRIBUTE_TRACE_ERROR \ (NR_ATTRIBUTE_DESTINATION_TXN_TRACE | NR_ATTRIBUTE_DESTINATION_ERROR) -#define NR_TXN_ATTR(X, NAME, DESTS) \ - const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { \ - (NAME), (DESTS) \ - } +#define NR_TXN_ATTR(X, NAME, DESTS) \ + const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { (NAME), (DESTS) } NR_TXN_ATTR(nr_txn_request_uri, "request.uri", @@ -2492,11 +2490,15 @@ nr_analytics_event_t* nr_error_to_event(const nrtxn_t* txn) { "External/all", "externalDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); + nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseCallCount"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "External/all", "externalCallCount"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageCallCount"); nro_set_hash_string(params, "nr.transactionGuid", nr_txn_get_guid(txn)); @@ -2582,10 +2584,16 @@ nrobj_t* nr_txn_event_intrinsics(const nrtxn_t* txn) { params, txn->unscoped_metrics, "WebFrontend/QueueTime", "queueDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "External/all", "externalDuration"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "External/all", "externalCallCount"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseCallCount"); + nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageDuration"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "MessageBroker/all", "messageCallCount"); if (txn->options.distributed_tracing_enabled) { nr_txn_add_distributed_tracing_intrinsics(txn, params); From 9168e47a9ebf266005b5e1e6cc3e23603c021007 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 13:22:57 -0700 Subject: [PATCH 40/63] feat(axiom): tests for rollup metrics for message segment --- axiom/tests/test_cmd_txndata.c | 10 ++++++++-- axiom/tests/test_txn.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/axiom/tests/test_cmd_txndata.c b/axiom/tests/test_cmd_txndata.c index fc9272e1c..ffb53a6c9 100644 --- a/axiom/tests/test_cmd_txndata.c +++ b/axiom/tests/test_cmd_txndata.c @@ -134,7 +134,8 @@ static void test_encode_errors(void) { "[887788,\"txnname\",\"msg\",\"cls\",{\"stack_trace\":[" "\"stacktrace " "json\"],\"agentAttributes\":{\"agent_long\":2},\"userAttributes\":{" - "\"user_long\":1},\"intrinsics\":{\"a\":\"b\",\"guid\":\"abcdef\"}},\"abcdef\"]"), + "\"user_long\":1},\"intrinsics\":{\"a\":\"b\",\"guid\":\"abcdef\"}}," + "\"abcdef\"]"), nr_flatbuffers_table_read_bytes(&tbl, ERROR_FIELD_DATA), nr_flatbuffers_table_read_vector_len(&tbl, ERROR_FIELD_DATA), __FILE__, __LINE__); @@ -1042,6 +1043,7 @@ static void test_encode_txn_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 2 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); txn.attributes = nr_attributes_create(0); @@ -1093,9 +1095,13 @@ static void test_encode_txn_event(void) { "\"timestamp\":123.00000," "\"duration\":0.98700,\"totalTime\":0.98700,\"nr.apdexPerfZone\":" "\"F\"," - "\"queueDuration\":3.00000,\"externalDuration\":2.00000," + "\"queueDuration\":3.00000," + "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":2.00000," "\"databaseCallCount\":2," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false}," "{\"user_long\":1},{\"agent_long\":2}]"), nr_flatbuffers_table_read_bytes(&tbl, EVENT_FIELD_DATA), diff --git a/axiom/tests/test_txn.c b/axiom/tests/test_txn.c index 9230a416a..cf7e4a170 100644 --- a/axiom/tests/test_txn.c +++ b/axiom/tests/test_txn.c @@ -2006,7 +2006,7 @@ static nrtxn_t* create_full_txn_and_reset(nrapp_t* app) { nr_segment_t* seg = nr_segment_start(txn, NULL, NULL); seg->start_time = 5 * NR_TIME_DIVISOR; seg->stop_time = 6 * NR_TIME_DIVISOR; - seg->type = NR_SEGMENT_DATASTORE; + seg->type = NR_SEGMENT_MESSAGE; seg->typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); nr_segment_end(&seg); } @@ -2962,6 +2962,7 @@ static void test_create_rollup_metrics(void) { txn.datastore_products = nr_string_pool_create(); nrm_force_add(txn.unscoped_metrics, "Datastore/all", 4 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "External/all", 1 * NR_TIME_DIVISOR); + nrm_force_add(txn.unscoped_metrics, "MessageBroker/all", 1 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "Datastore/MongoDB/all", 2 * NR_TIME_DIVISOR); nrm_force_add(txn.unscoped_metrics, "Datastore/SQLite/all", @@ -2977,6 +2978,9 @@ static void test_create_rollup_metrics(void) { "{\"name\":\"External\\/" "all\",\"data\":[1,1.00000,1.00000,1.00000,1.00000,1." "00000],\"forced\":true}," + "{\"name\":\"MessageBroker\\/" + "all\",\"data\":[1,1.00000,1.00000,1.00000,1.00000,1." + "00000],\"forced\":true}," "{\"name\":\"Datastore\\/MongoDB\\/" "all\",\"data\":[1,2.00000,2.00000,2.00000,2.00000,4." "00000],\"forced\":true}," @@ -3910,6 +3914,7 @@ static void test_error_to_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); event = nr_error_to_event(&txn); @@ -3926,8 +3931,10 @@ static void test_error_to_event(void) { "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," "\"databaseDuration\":1.00000," + "\"messageDuration\":1.00000," "\"databaseCallCount\":1," "\"externalCallCount\":1," + "\"messageCallCount\":1," "\"nr.transactionGuid\":\"abcd\"," "\"guid\":\"abcd\"" "}," @@ -3951,8 +3958,10 @@ static void test_error_to_event(void) { "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," "\"databaseDuration\":1.00000," + "\"messageDuration\":1.00000," "\"databaseCallCount\":1," "\"externalCallCount\":1," + "\"messageCallCount\":1," "\"nr.transactionGuid\":\"abcd\"," "\"guid\":\"abcd\"," "\"nr.referringTransactionGuid\":\"foo_guid\"," @@ -4041,6 +4050,7 @@ static void test_create_event(void) { nrm_add(txn.unscoped_metrics, "Datastore/all", 1 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "External/all", 2 * NR_TIME_DIVISOR); + nrm_add(txn.unscoped_metrics, "MessageBroker/all", 2 * NR_TIME_DIVISOR); nrm_add(txn.unscoped_metrics, "WebFrontend/QueueTime", 3 * NR_TIME_DIVISOR); event = nr_txn_to_event(&txn); @@ -4056,8 +4066,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4078,8 +4091,11 @@ static void test_create_event(void) { "\"totalTime\":0.98700," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4103,8 +4119,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4126,8 +4145,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -4148,8 +4170,11 @@ static void test_create_event(void) { "\"nr.apdexPerfZone\":\"F\"," "\"queueDuration\":3.00000," "\"externalDuration\":2.00000," + "\"externalCallCount\":1," "\"databaseDuration\":1.00000," "\"databaseCallCount\":1," + "\"messageDuration\":2.00000," + "\"messageCallCount\":1," "\"error\":false" "}," "{\"user_long\":1}," @@ -8054,7 +8079,8 @@ static void test_segment_record_error(void) { /* Do not add to current segment */ nr_txn_record_error(txn, 0.5, false /* do not add to current segment*/, - "low priority message", "low priority class", "[\"A\",\"B\"]"); + "low priority message", "low priority class", + "[\"A\",\"B\"]"); tlib_pass_if_not_null("Txn error event created", txn->error); tlib_pass_if_null("Segment error NOT created", segment->error); tlib_pass_if_str_equal("Correct txn error.message", "low priority message", @@ -8063,7 +8089,8 @@ static void test_segment_record_error(void) { nr_error_get_klass(txn->error)); /* Normal operation: txn error prioritized over previous */ - nr_txn_record_error(txn, 1, true, "error message", "error class", "[\"A\",\"B\"]"); + nr_txn_record_error(txn, 1, true, "error message", "error class", + "[\"A\",\"B\"]"); tlib_pass_if_not_null("Txn error event created", txn->error); tlib_pass_if_not_null("Segment error created", segment->error); From ba40124caf6ce3fadd6a16380a87033fefdc4b4c Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:24:34 -0700 Subject: [PATCH 41/63] feat(axiom): Stronger handling of NULL/empty str for message attributes Handle NULL/empty str and provide the `` string. --- axiom/nr_segment_message.c | 66 +++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 6efcd1072..2fba880ac 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -25,12 +25,22 @@ static void nr_segment_message_set_attrs( message_attributes.message_action = params->message_action; if (options.message_tracer_segment_parameters_enabled) { - message_attributes.destination_name = params->destination_name; - message_attributes.cloud_region = params->cloud_region; - message_attributes.cloud_account_id = params->cloud_account_id; - message_attributes.messaging_system = params->messaging_system; - message_attributes.cloud_resource_id = params->cloud_resource_id; - message_attributes.server_address = params->server_address; + message_attributes.destination_name = nr_strempty(params->destination_name) + ? NULL + : params->destination_name; + message_attributes.cloud_region + = nr_strempty(params->cloud_region) ? NULL : params->cloud_region; + message_attributes.cloud_account_id = nr_strempty(params->cloud_account_id) + ? NULL + : params->cloud_account_id; + message_attributes.messaging_system = nr_strempty(params->messaging_system) + ? NULL + : params->messaging_system; + message_attributes.cloud_resource_id + = nr_strempty(params->cloud_resource_id) ? NULL + : params->cloud_resource_id; + message_attributes.server_address + = nr_strempty(params->server_address) ? NULL : params->server_address; } nr_segment_set_message(segment, &message_attributes); @@ -42,20 +52,20 @@ static void nr_segment_message_set_attrs( * * Metrics created during this call * ---------------------------------------------------------------------------------- - * MessageBroker/all Unscoped - * Always MessageBroker/{library}/all Scoped Always + * MessageBroker/all Unscoped Always + * MessageBroker/{library}/all coped Always * * Metrics created based on MessageBroker/all (in nr_txn_create_rollup_metrics) * ---------------------------------------------------------------------------------- - * MessageBroker/allWeb Unscoped Web - * MessageBroker/allOther Unscoped - * non-Web + * MessageBroker/allWeb Unscoped Web + * MessageBroker/allOther Unscoped non-Web * * Segment name * ----------------------------------------------------------------------------------- * MessageBroker/{library}/all Always * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * non-temp + * MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp * * * These metrics are dictated by the spec located here: @@ -86,6 +96,7 @@ static char* nr_segment_message_create_metrics( nrtime_t duration) { const char* action_string = NULL; const char* destination_type_string = NULL; + const char* library_string = NULL; char* rollup_metric = NULL; char* scoped_metric = NULL; @@ -93,7 +104,7 @@ static char* nr_segment_message_create_metrics( return NULL; } - if (NULL == message_params || NULL == message_params->library) { + if (NULL == message_params) { return NULL; } @@ -106,7 +117,12 @@ static char* nr_segment_message_create_metrics( nrm_force_add(segment->txn->unscoped_metrics, "MessageBroker/all", duration); - rollup_metric = nr_formatf("MessageBroker/%s/all", message_params->library); + if (nr_strempty(message_params->library)) { + library_string = ""; + } else { + library_string = message_params->library; + } + rollup_metric = nr_formatf("MessageBroker/%s/all", library_string); nrm_force_add(segment->txn->unscoped_metrics, rollup_metric, duration); nr_free(rollup_metric); @@ -122,7 +138,7 @@ static char* nr_segment_message_create_metrics( } else if (NR_SPAN_CONSUMER == message_params->message_action) { action_string = "Consume"; } else { - action_string = "Unknown"; + action_string = ""; } switch (message_params->destination_type) { @@ -138,26 +154,26 @@ static char* nr_segment_message_create_metrics( destination_type_string = "Exchange"; break; default: - destination_type_string = "Unknown"; + destination_type_string = ""; break; } /* * Create the scoped metric * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp dest + * non-temp MessageBroker/{Library}/{DestinationType}/{Action}/Temp */ if (NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE == message_params->destination_type || NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC == message_params->destination_type) { - scoped_metric - = nr_formatf("MessageBroker/%s/%s/%s/Temp", message_params->library, - destination_type_string, action_string); + scoped_metric = nr_formatf("MessageBroker/%s/%s/%s/Temp", library_string, + destination_type_string, action_string); } else { - scoped_metric = nr_formatf( - "MessageBroker/%s/%s/%s/Named/%s", message_params->library, - destination_type_string, action_string, - message_params->destination_name ? message_params->destination_name - : "Unknown"); + scoped_metric + = nr_formatf("MessageBroker/%s/%s/%s/Named/%s", library_string, + destination_type_string, action_string, + nr_strempty(message_params->destination_name) + ? "" + : message_params->destination_name); } nr_segment_add_metric(segment, scoped_metric, true); From d0b2a554c875dd7a5f3e0500ce3462f6c6e2b04a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:26:35 -0700 Subject: [PATCH 42/63] feat(axiom): message segment rollup metrics --- axiom/nr_txn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index e6363bcbe..8c2a4a75d 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -1219,11 +1219,15 @@ void nr_txn_create_rollup_metrics(nrtxn_t* txn) { "Datastore/allOther"); nrm_duplicate_metric(txn->unscoped_metrics, "External/all", "External/allOther"); + nrm_duplicate_metric(txn->unscoped_metrics, "MessageBroker/all", + "MessageBroker/allOther"); } else { nrm_duplicate_metric(txn->unscoped_metrics, "Datastore/all", "Datastore/allWeb"); nrm_duplicate_metric(txn->unscoped_metrics, "External/all", "External/allWeb"); + nrm_duplicate_metric(txn->unscoped_metrics, "MessageBroker/all", + "MessageBroker/allWeb"); } nr_string_pool_apply( From 4fc9bcea5f64bae2b5a14924d4c28da090438906 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:35:51 -0700 Subject: [PATCH 43/63] feat(axiom): add message rollup metric to test case --- axiom/tests/test_txn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/axiom/tests/test_txn.c b/axiom/tests/test_txn.c index cf7e4a170..5dc68deae 100644 --- a/axiom/tests/test_txn.c +++ b/axiom/tests/test_txn.c @@ -2993,6 +2993,9 @@ static void test_create_rollup_metrics(void) { "{\"name\":\"External\\/" "allOther\",\"data\":[1,1.00000,1.00000,1.00000,1." "00000,1.00000],\"forced\":true}," + "{\"name\":\"MessageBroker\\/" + "allOther\",\"data\":[1,1.00000,1.00000,1.00000,1." + "00000,1.00000],\"forced\":true}," "{\"name\":\"Datastore\\/MongoDB\\/" "allOther\",\"data\":[1,2.00000,2.00000,2.00000,2." "00000,4.00000],\"forced\":true}," From c8d2db149e723664fc34f6677057930b17462e4a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 9 Dec 2024 20:41:29 -0700 Subject: [PATCH 44/63] feat(axiom): Add unit tests for nr_segment_message --- axiom/tests/Makefile | 1 + axiom/tests/test_segment_helpers.h | 23 +- axiom/tests/test_segment_message.c | 880 +++++++++++++++++++++++++++++ 3 files changed, 903 insertions(+), 1 deletion(-) create mode 100644 axiom/tests/test_segment_message.c diff --git a/axiom/tests/Makefile b/axiom/tests/Makefile index 0a37821bb..3d67984ca 100644 --- a/axiom/tests/Makefile +++ b/axiom/tests/Makefile @@ -173,6 +173,7 @@ TESTS := \ test_segment_children \ test_segment_datastore \ test_segment_external \ + test_segment_message \ test_segment_private \ test_segment_terms \ test_segment_traces \ diff --git a/axiom/tests/test_segment_helpers.h b/axiom/tests/test_segment_helpers.h index 908432798..9ff7f54f7 100644 --- a/axiom/tests/test_segment_helpers.h +++ b/axiom/tests/test_segment_helpers.h @@ -12,6 +12,7 @@ #include "nr_segment.h" #include "nr_segment_datastore.h" #include "nr_segment_external.h" +#include "nr_segment_message.h" #include "tlib_main.h" #include "util_metrics_private.h" #include "nr_limits.h" @@ -287,7 +288,7 @@ static NRUNUSED bool test_segment_end_and_keep(nr_segment_t** segment_ptr) { } /* - * Purpose : Ends an external segment without nulling out the segment pointer. + * Purpose : Ends an external segment without nulling out the segment pointer. * * WARNING : This can only be used safely when the segment priority queue is * disabled. @@ -326,4 +327,24 @@ static NRUNUSED bool test_segment_datastore_end_and_keep( return nr_segment_datastore_end(&segment, params); } +/* + * Purpose : Ends a message segment without nulling out the segment pointer. + * + * WARNING : This can only be used safely when the segment priority queue is + * disabled. + */ +static NRUNUSED bool test_segment_message_end_and_keep( + nr_segment_t** segment_ptr, + nr_segment_message_params_t* params) { + nr_segment_t* segment; + + if (NULL == segment_ptr) { + return false; + } + + segment = *segment_ptr; + + return nr_segment_message_end(&segment, params); +} + #endif /* TEST_SEGMENT_HELPERS_HDR */ diff --git a/axiom/tests/test_segment_message.c b/axiom/tests/test_segment_message.c new file mode 100644 index 000000000..82cfc46c0 --- /dev/null +++ b/axiom/tests/test_segment_message.c @@ -0,0 +1,880 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nr_axiom.h" +#include "nr_header.h" +#include "nr_segment_message.h" +#include "test_segment_helpers.h" + +typedef struct { + const char* test_name; + const char* name; + const char* txn_rollup_metric; + const char* library_metric; + uint32_t num_metrics; + const char* destination_name; + const char* cloud_region; + const char* cloud_account_id; + const char* messaging_system; + const char* cloud_resource_id; + const char* server_address; + +} segment_message_expecteds_t; + +static nr_segment_t* mock_txn_segment(void) { + nrtxn_t* txn = new_txn(0); + + return nr_segment_start(txn, NULL, NULL); +} + +static void test_message_segment(nr_segment_message_params_t* params, + bool message_attributes_enabled, + segment_message_expecteds_t expecteds) { + nr_segment_t* seg = mock_txn_segment(); + nrtxn_t* txn = seg->txn; + seg->txn->options.message_tracer_segment_parameters_enabled + = message_attributes_enabled; + + test_segment_message_end_and_keep(&seg, params); + + tlib_pass_if_str_equal(expecteds.test_name, expecteds.name, + nr_string_get(seg->txn->trace_strings, seg->name)); + test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, + expecteds.txn_rollup_metric); + test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, + expecteds.library_metric); + test_metric_vector_size(seg->metrics, expecteds.num_metrics); + tlib_pass_if_true(expecteds.test_name, NR_SEGMENT_MESSAGE == seg->type, + "NR_SEGMENT_MESSAGE"); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.destination_name, + expecteds.destination_name); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_region, + expecteds.cloud_region); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_account_id, + expecteds.cloud_account_id); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.messaging_system, + expecteds.messaging_system); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.cloud_resource_id, + expecteds.cloud_resource_id); + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.server_address, + expecteds.server_address); + + nr_txn_destroy(&txn); +} + +static void test_bad_parameters(void) { + nr_segment_t seg_null = {0}; + nr_segment_t* seg_null_ptr; + nr_segment_t* seg = mock_txn_segment(); + nrtxn_t* txn = seg->txn; + nr_segment_message_params_t params = {0}; + + tlib_pass_if_false("bad parameters", nr_segment_message_end(NULL, ¶ms), + "expected false"); + + seg_null_ptr = NULL; + tlib_pass_if_false("bad parameters", + nr_segment_message_end(&seg_null_ptr, ¶ms), + "expected false"); + + seg_null_ptr = &seg_null; + tlib_pass_if_false("bad parameters", + nr_segment_message_end(&seg_null_ptr, ¶ms), + "expected false"); + + tlib_pass_if_false("bad parameters", nr_segment_message_end(&seg, NULL), + "expected false"); + test_metric_vector_size(seg->metrics, 0); + + nr_txn_destroy(&txn); +} + +static void test_segment_message_destination_type(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC destination type", + .name = "MessageBroker/SQS/Topic/Produce/Temp", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type", + .name = "MessageBroker/SQS/Queue/Produce/Temp", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_EXCHANGE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", + .name = "MessageBroker/SQS/Exchange/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_TOPIC destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_QUEUE, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name + = "Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type", + .name = "MessageBroker/SQS/Queue/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_message_action(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + + /* Test NR_SPAN_PRODUCER message action */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_PRODUCER message action", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test NR_SPAN_CONSUMER message action */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_CONSUMER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_CONSUMER message action", + .name = "MessageBroker/SQS/Topic/Consume/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* + * Test NR_SPAN_CLIENT message action; this is not + * allowed for message segments, should show unknown. + */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_CLIENT, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test NR_SPAN_CLIENT message action", + .name = "MessageBroker/SQS/Topic//Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_library(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test null library */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = NULL, + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null library", + .name + = "MessageBroker//Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker//all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty library */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty library", + .name + = "MessageBroker//Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker//all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid library */ + + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_queue_or_topic"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid library", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_queue_or_topic", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_destination_name(void) { + /* + * The following values are used to create metrics: + * library + * destination_type + * message_action + * destination_name + */ + /* Test null destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = NULL}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = ""}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid destination_name */ + test_message_segment( + &(nr_segment_message_params_t){ + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid destination_name", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_region(void) { + /* + * cloud_region values should NOT impact the creation of + * metrics. + */ + + /* Test null cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_region */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_region = "wild-west-1", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_region", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = "wild-west-1", + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_account_id(void) { + /* + * cloud_account_id values should NOT impact the creation + * of metrics. + */ + + /* Test null cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_account_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_account_id = "12345678", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_account_id", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = "12345678", + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_messaging_system(void) { + /* + * messaging_system values should NOT impact the creation + * of metrics. + */ + + /* Test null messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid messaging_system */ + test_message_segment( + &(nr_segment_message_params_t){ + .messaging_system = "my_messaging_system", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid messaging_system", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = "my_messaging_system", + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +static void test_segment_message_cloud_resource_id(void) { + /* + * cloud_resource_id values should NOT impact the creation + * of metrics. + */ + + /* Test null cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test empty cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid cloud_resource_id */ + test_message_segment( + &(nr_segment_message_params_t){ + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid cloud_resource_id ", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = "my_resource_id", + .server_address = NULL}); +} + +static void test_segment_message_server_address(void) { + /* + * server_address values should NOT impact the creation + * of metrics. + */ + + /* Test null server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = "localhost"}); + + /* Test empty server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); + + /* Test valid server_address */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid server_address", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = "localhost"}); +} + +static void test_segment_message_parameters_enabled(void) { + /* + * Attributes should be set based on value of parameters_enabled. + */ + + /* Test true message_parameters_enabled */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test true message_parameters_enabled", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .server_address = "localhost"}); + + /* Test false message_parameters_enabled */ + test_message_segment( + &(nr_segment_message_params_t){ + .server_address = "localhost", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .messaging_system = "my_system", + .cloud_resource_id = "my_resource_id", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + false /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test false message_parameters_enabled", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL}); +} + +tlib_parallel_info_t parallel_info = {.suggested_nthreads = 4, .state_size = 0}; + +void test_main(void* p NRUNUSED) { + test_bad_parameters(); + test_segment_message_destination_type(); + test_segment_message_message_action(); + test_segment_message_library(); + test_segment_message_destination_name(); + test_segment_message_cloud_region(); + test_segment_message_cloud_account_id(); + test_segment_message_messaging_system(); + test_segment_message_cloud_resource_id(); + test_segment_message_server_address(); + test_segment_message_parameters_enabled(); +} From a0a61a2ead8ba0eae246b8aa0d78a1317137e8dd Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 10 Dec 2024 08:21:36 -0700 Subject: [PATCH 45/63] feat(axiom): Update integration test for externalCallCount --- tests/integration/synthetics/test_happy_path_with_dt.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/synthetics/test_happy_path_with_dt.php b/tests/integration/synthetics/test_happy_path_with_dt.php index 855a35e2a..3b7696f79 100644 --- a/tests/integration/synthetics/test_happy_path_with_dt.php +++ b/tests/integration/synthetics/test_happy_path_with_dt.php @@ -62,6 +62,7 @@ "nr.syntheticsJobId": "jjjjjjj-jjjj-1234-jjjj-jjjjjjjjjjjj", "nr.syntheticsMonitorId": "mmmmmmm-mmmm-1234-mmmm-mmmmmmmmmmmm", "externalDuration": "??", + "externalCallCount": "1", "guid": "??", "sampled": true, "priority": "??", From 1135d39001d208b37131b2faf3a5001580c2d1fc Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 10 Dec 2024 08:52:59 -0700 Subject: [PATCH 46/63] fix(test): NOT a string... --- tests/integration/synthetics/test_happy_path_with_dt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/synthetics/test_happy_path_with_dt.php b/tests/integration/synthetics/test_happy_path_with_dt.php index 3b7696f79..14c3b3b88 100644 --- a/tests/integration/synthetics/test_happy_path_with_dt.php +++ b/tests/integration/synthetics/test_happy_path_with_dt.php @@ -62,7 +62,7 @@ "nr.syntheticsJobId": "jjjjjjj-jjjj-1234-jjjj-jjjjjjjjjjjj", "nr.syntheticsMonitorId": "mmmmmmm-mmmm-1234-mmmm-mmmmmmmmmmmm", "externalDuration": "??", - "externalCallCount": "1", + "externalCallCount": 1, "guid": "??", "sampled": true, "priority": "??", From b7ffa6cf718a537fe12cbaf4e74ab37124c20580 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Fri, 13 Dec 2024 14:27:19 -0700 Subject: [PATCH 47/63] chore(axiom): Comment update --- axiom/nr_segment_external.c | 4 ++-- axiom/nr_segment_message.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/axiom/nr_segment_external.c b/axiom/nr_segment_external.c index dbaf4c78a..738cec6f5 100644 --- a/axiom/nr_segment_external.c +++ b/axiom/nr_segment_external.c @@ -57,8 +57,8 @@ static void nr_segment_external_set_attrs( * External/{host}/all non-CAT * ExternalTransaction/{host}/{external_id}/{external_txnname} CAT * - * These metrics are dictated by the spec located here: - * https://source.datanerd.us/agents/agent-specs/blob/master/Cross-Application-Tracing-PORTED.md + * These metrics are dictated by the agent-spec in this file: + * Cross-Application-Tracing-PORTED.md */ static void nr_segment_external_create_metrics(nr_segment_t* segment, const char* uri, diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 2fba880ac..219c1f520 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -68,8 +68,8 @@ static void nr_segment_message_set_attrs( * MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp * * - * These metrics are dictated by the spec located here: - * https://source.datanerd.us/agents/agent-specs/blob/master/APIs/messaging.md#metrics + * These metrics are dictated by the agent-spec file here: + * APIs/messaging.md#metrics * When the destination is temporary (such as a temporary queue, or a temporary * topic), the destination name MUST be omitted. The metric segment 'Named' MUST * be replaced with 'Temp'. The DestinationType segment SHOULD NOT contain From d7c4d79fe7a6a6dc2ff51a24fe4a7d3d7c66975c Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 23 Dec 2024 21:35:57 -0700 Subject: [PATCH 48/63] fix(axiom): Correct the attribute bucket. --- axiom/nr_span_event.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 9da8532f4..60c4f4695 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -373,7 +373,8 @@ void nr_span_event_set_message(nr_span_event_t* event, nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); break; case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: - nro_set_hash_string(event->intrinsics, "cloud.account.id", new_value); + nro_set_hash_string(event->agent_attributes, "cloud.account.id", + new_value); break; case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: nro_set_hash_string(event->agent_attributes, "messaging.system", @@ -384,7 +385,7 @@ void nr_span_event_set_message(nr_span_event_t* event, new_value); break; case NR_SPAN_MESSAGE_SERVER_ADDRESS: - nro_set_hash_string(event->intrinsics, "server.address", new_value); + nro_set_hash_string(event->agent_attributes, "server.address", new_value); break; } } @@ -541,7 +542,8 @@ const char* nr_span_event_get_message(const nr_span_event_t* event, case NR_SPAN_MESSAGE_CLOUD_REGION: return nro_get_hash_string(event->agent_attributes, "cloud.region", NULL); case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: - return nro_get_hash_string(event->intrinsics, "cloud.account.id", NULL); + return nro_get_hash_string(event->agent_attributes, "cloud.account.id", + NULL); case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: return nro_get_hash_string(event->agent_attributes, "messaging.system", NULL); @@ -549,7 +551,8 @@ const char* nr_span_event_get_message(const nr_span_event_t* event, return nro_get_hash_string(event->agent_attributes, "cloud.resource_id", NULL); case NR_SPAN_MESSAGE_SERVER_ADDRESS: - return nro_get_hash_string(event->intrinsics, "server.address", NULL); + return nro_get_hash_string(event->agent_attributes, "server.address", + NULL); } return NULL; } From 1ffa5d739b020cb3ae5bf4d5640ee986160e63cf Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 24 Dec 2024 10:58:09 -0700 Subject: [PATCH 49/63] feat(axiom): Add aws_operation to message segment attributes. --- axiom/nr_segment.c | 3 + axiom/nr_segment.h | 10 +- axiom/nr_segment_message.c | 2 + axiom/nr_segment_message.h | 25 +++- axiom/nr_segment_private.c | 1 + axiom/nr_segment_traces.c | 2 + axiom/nr_span_event.c | 6 + axiom/nr_span_event.h | 4 +- axiom/tests/test_segment_message.c | 182 +++++++++++++++++++++++------ axiom/tests/test_segment_traces.c | 19 ++- axiom/tests/test_span_event.c | 10 ++ 11 files changed, 213 insertions(+), 51 deletions(-) diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index 9a7dba1c9..52ff20ce4 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -339,6 +339,8 @@ static void nr_populate_message_spans(nr_span_event_t* span_event, segment->typed_attributes->message.cloud_resource_id); nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS, segment->typed_attributes->message.server_address); + nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_AWS_OPERATION, + segment->typed_attributes->message.aws_operation); } static nr_status_t add_user_attribute_to_span_event(const char* key, @@ -652,6 +654,7 @@ bool nr_segment_set_message(nr_segment_t* segment, .messaging_system = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, .cloud_resource_id = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, .server_address = message->server_address ? nr_strdup(message->server_address) : NULL, + .aws_operation = message->aws_operation ? nr_strdup(message->aws_operation) : NULL, }; // clang-format on diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 66b53ce5e..59822d07c 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -123,16 +123,18 @@ typedef struct _nr_segment_message_t { nr_span_spankind_t message_action; /*The action of the message, e.g.,Produce/Consume.*/ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + char* destination_name; /*The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship.*/ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS relationship.*/ char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ - char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ - char* server_address; /* the server domain name or IP address. Needed for + char* cloud_resource_id; /*Unique cloud provider identifier. For AWS, this is + the ARN of the AWS resource being accessed.*/ + char* server_address; /*The server domain name or IP address. Needed for MQBROKER relationship.*/ + char* aws_operation; /*AWS specific operation name.*/ } nr_segment_message_t; diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 219c1f520..f98abcb09 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -41,6 +41,8 @@ static void nr_segment_message_set_attrs( : params->cloud_resource_id; message_attributes.server_address = nr_strempty(params->server_address) ? NULL : params->server_address; + message_attributes.aws_operation + = nr_strempty(params->server_address) ? NULL : params->aws_operation; } nr_segment_set_message(segment, &message_attributes); diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h index d6b38b8ee..0d1e46c09 100644 --- a/axiom/nr_segment_message.h +++ b/axiom/nr_segment_message.h @@ -8,7 +8,7 @@ #include "nr_segment.h" -/* +/* * Note: * CAT is EOLed and this feature is not compatible with CAT. */ @@ -33,19 +33,34 @@ typedef struct { /* Used for creating message attributes. */ nr_span_spankind_t message_action; /*The action of the message, e.g.,Produce/Consume.*/ - char* destination_name; /* The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship. */ + char* destination_name; /*The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship.*/ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS relationship.*/ char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ - char* cloud_resource_id; /*The ARN of the AWS resource being accessed.*/ - char* server_address; /* the server domain name or IP address. Needed for + char* cloud_resource_id; /*A unique identifier given by the cloud resource. + For AWS, this is the ARN of the AWS resource being + accessed.*/ + char* server_address; /*The server domain name or IP address. Needed for MQBROKER relationship.*/ + char* aws_operation; /*The AWS operation being called.*/ } nr_segment_message_params_t; +static inline void nr_segment_message_destroy_message_params( + nr_segment_message_params_t* message_params) { + nr_free(message_params->library); + nr_free(message_params->destination_name); + nr_free(message_params->cloud_region); + nr_free(message_params->cloud_account_id); + nr_free(message_params->messaging_system); + nr_free(message_params->cloud_resource_id); + nr_free(message_params->server_address); + nr_free(message_params->aws_operation); +} + /* * Purpose : End a message segment and record metrics. * diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index 283ec0067..e112306b6 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -50,6 +50,7 @@ void nr_segment_message_destroy_fields(nr_segment_message_t* message) { nr_free(message->cloud_account_id); nr_free(message->cloud_resource_id); nr_free(message->server_address); + nr_free(message->aws_operation); } void nr_segment_destroy_typed_attributes( diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index b5b370d06..4d2a52f23 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -176,6 +176,8 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, message->cloud_resource_id, false); add_hash_key_value_to_buffer(buf, "server_address", message->server_address, false); + add_hash_key_value_to_buffer(buf, "aws_operation", message->aws_operation, + false); } break; case NR_SEGMENT_CUSTOM: default: diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 60c4f4695..9099d1dfb 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -387,6 +387,9 @@ void nr_span_event_set_message(nr_span_event_t* event, case NR_SPAN_MESSAGE_SERVER_ADDRESS: nro_set_hash_string(event->agent_attributes, "server.address", new_value); break; + case NR_SPAN_MESSAGE_AWS_OPERATION: + nro_set_hash_string(event->agent_attributes, "aws.operation", new_value); + break; } } @@ -553,6 +556,9 @@ const char* nr_span_event_get_message(const nr_span_event_t* event, case NR_SPAN_MESSAGE_SERVER_ADDRESS: return nro_get_hash_string(event->agent_attributes, "server.address", NULL); + case NR_SPAN_MESSAGE_AWS_OPERATION: + return nro_get_hash_string(event->agent_attributes, "aws.operation", + NULL); } return NULL; } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 16020b7b0..535ae545a 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -74,7 +74,9 @@ typedef enum { NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, - NR_SPAN_MESSAGE_SERVER_ADDRESS + NR_SPAN_MESSAGE_SERVER_ADDRESS, + NR_SPAN_MESSAGE_AWS_OPERATION + } nr_span_event_message_member_t; /* diff --git a/axiom/tests/test_segment_message.c b/axiom/tests/test_segment_message.c index 82cfc46c0..ded26437e 100644 --- a/axiom/tests/test_segment_message.c +++ b/axiom/tests/test_segment_message.c @@ -20,7 +20,7 @@ typedef struct { const char* messaging_system; const char* cloud_resource_id; const char* server_address; - + const char* aws_operation; } segment_message_expecteds_t; static nr_segment_t* mock_txn_segment(void) { @@ -66,7 +66,9 @@ static void test_message_segment(nr_segment_message_params_t* params, tlib_pass_if_str_equal(expecteds.test_name, seg->typed_attributes->message.server_address, expecteds.server_address); - + tlib_pass_if_str_equal(expecteds.test_name, + seg->typed_attributes->message.aws_operation, + expecteds.aws_operation); nr_txn_destroy(&txn); } @@ -125,7 +127,8 @@ static void test_segment_message_destination_type(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type */ test_message_segment( @@ -147,7 +150,8 @@ static void test_segment_message_destination_type(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type */ test_message_segment( @@ -169,7 +173,8 @@ static void test_segment_message_destination_type(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test NR_MESSAGE_DESTINATION_TYPE_TOPIC destination type */ test_message_segment( @@ -191,7 +196,8 @@ static void test_segment_message_destination_type(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type */ test_message_segment( @@ -213,7 +219,8 @@ static void test_segment_message_destination_type(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_message_action(void) { @@ -244,7 +251,8 @@ static void test_segment_message_message_action(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test NR_SPAN_CONSUMER message action */ @@ -266,7 +274,8 @@ static void test_segment_message_message_action(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* * Test NR_SPAN_CLIENT message action; this is not @@ -290,7 +299,8 @@ static void test_segment_message_message_action(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_library(void) { @@ -321,7 +331,8 @@ static void test_segment_message_library(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty library */ @@ -344,7 +355,8 @@ static void test_segment_message_library(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid library */ @@ -366,7 +378,8 @@ static void test_segment_message_library(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_destination_name(void) { @@ -396,7 +409,8 @@ static void test_segment_message_destination_name(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty destination_name */ test_message_segment( @@ -417,7 +431,8 @@ static void test_segment_message_destination_name(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid destination_name */ test_message_segment( @@ -438,7 +453,8 @@ static void test_segment_message_destination_name(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_cloud_region(void) { @@ -467,7 +483,8 @@ static void test_segment_message_cloud_region(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty cloud_region */ test_message_segment( @@ -489,7 +506,8 @@ static void test_segment_message_cloud_region(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid cloud_region */ test_message_segment( @@ -511,7 +529,8 @@ static void test_segment_message_cloud_region(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_cloud_account_id(void) { @@ -540,7 +559,8 @@ static void test_segment_message_cloud_account_id(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty cloud_account_id */ test_message_segment( @@ -562,7 +582,8 @@ static void test_segment_message_cloud_account_id(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid cloud_account_id */ test_message_segment( @@ -584,7 +605,8 @@ static void test_segment_message_cloud_account_id(void) { .cloud_account_id = "12345678", .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_messaging_system(void) { @@ -613,7 +635,8 @@ static void test_segment_message_messaging_system(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty messaging_system */ test_message_segment( @@ -635,7 +658,8 @@ static void test_segment_message_messaging_system(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid messaging_system */ test_message_segment( @@ -657,7 +681,8 @@ static void test_segment_message_messaging_system(void) { .cloud_account_id = NULL, .messaging_system = "my_messaging_system", .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_cloud_resource_id(void) { @@ -686,7 +711,8 @@ static void test_segment_message_cloud_resource_id(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test empty cloud_resource_id */ test_message_segment( @@ -708,7 +734,8 @@ static void test_segment_message_cloud_resource_id(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid cloud_resource_id */ test_message_segment( @@ -730,7 +757,8 @@ static void test_segment_message_cloud_resource_id(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = "my_resource_id", - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_server_address(void) { @@ -759,7 +787,8 @@ static void test_segment_message_server_address(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = "localhost"}); + .server_address = "localhost", + .aws_operation = NULL}); /* Test empty server_address */ test_message_segment( @@ -781,7 +810,8 @@ static void test_segment_message_server_address(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); /* Test valid server_address */ test_message_segment( @@ -803,7 +833,84 @@ static void test_segment_message_server_address(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = "localhost"}); + .server_address = "localhost", + .aws_operation = NULL}); +} + +static void test_segment_message_aws_operation(void) { + /* + * aws_operation values should NOT impact the creation + * of metrics. + */ + + /* Test null aws_operation */ + test_message_segment( + &(nr_segment_message_params_t){ + .aws_operation = NULL, + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test null aws_operation", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL, + .aws_operation = NULL}); + + /* Test empty aws_operation */ + test_message_segment( + &(nr_segment_message_params_t){ + .aws_operation = "sendMessage", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test empty aws_operation", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL, + .aws_operation = NULL}); + + /* Test valid aws_operation */ + test_message_segment( + &(nr_segment_message_params_t){ + .aws_operation = "sendMessage", + .library = "SQS", + .message_action = NR_SPAN_PRODUCER, + .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, + .destination_name = "my_destination"}, + true /* enable attributes */, + (segment_message_expecteds_t){ + .test_name = "Test valid aws_operation", + .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", + .txn_rollup_metric = "MessageBroker/all", + .library_metric = "MessageBroker/SQS/all", + .num_metrics = 1, + .destination_name = "my_destination", + .cloud_region = NULL, + .cloud_account_id = NULL, + .messaging_system = NULL, + .cloud_resource_id = NULL, + .server_address = NULL, + .aws_operation = NULL}); } static void test_segment_message_parameters_enabled(void) { @@ -822,7 +929,8 @@ static void test_segment_message_parameters_enabled(void) { .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, - .destination_name = "my_destination"}, + .destination_name = "my_destination", + .aws_operation = "sendMessage"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test true message_parameters_enabled", @@ -835,7 +943,8 @@ static void test_segment_message_parameters_enabled(void) { .cloud_account_id = "12345678", .messaging_system = "my_system", .cloud_resource_id = "my_resource_id", - .server_address = "localhost"}); + .server_address = "localhost", + .aws_operation = "sendMessage"}); /* Test false message_parameters_enabled */ test_message_segment( @@ -848,7 +957,8 @@ static void test_segment_message_parameters_enabled(void) { .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, - .destination_name = "my_destination"}, + .destination_name = "my_destination", + .aws_operation = "sendMessage"}, false /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test false message_parameters_enabled", @@ -860,7 +970,8 @@ static void test_segment_message_parameters_enabled(void) { .cloud_account_id = NULL, .messaging_system = NULL, .cloud_resource_id = NULL, - .server_address = NULL}); + .server_address = NULL, + .aws_operation = NULL}); } tlib_parallel_info_t parallel_info = {.suggested_nthreads = 4, .state_size = 0}; @@ -876,5 +987,6 @@ void test_main(void* p NRUNUSED) { test_segment_message_messaging_system(); test_segment_message_cloud_resource_id(); test_segment_message_server_address(); + test_segment_message_aws_operation(); test_segment_message_parameters_enabled(); } diff --git a/axiom/tests/test_segment_traces.c b/axiom/tests/test_segment_traces.c index 4ca0074a8..5c224a6ec 100644 --- a/axiom/tests/test_segment_traces.c +++ b/axiom/tests/test_segment_traces.c @@ -93,7 +93,8 @@ #define SPAN_EVENT_COMPARE_MESSAGE( \ span_event, expected_destination_name, expected_cloud_region, \ expected_cloud_account_id, expected_messaging_system, \ - expected_cloud_resource_id, expected_server_address) \ + expected_cloud_resource_id, expected_server_address, \ + expected_aws_operation) \ tlib_pass_if_str_equal("destination.name", expected_destination_name, \ nr_span_event_get_message( \ span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ @@ -111,7 +112,10 @@ span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); \ tlib_pass_if_str_equal( \ "server.address", expected_server_address, \ - nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); \ + tlib_pass_if_str_equal( \ + "aws.operation", expected_aws_operation, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_AWS_OPERATION)); static void nr_vector_span_event_dtor(void* element, void* userdata NRUNUSED) { nr_span_event_destroy((nr_span_event_t**)&element); @@ -741,7 +745,7 @@ static void test_json_print_segments_invalid_typed_attributes(void) { SPAN_EVENT_COMPARE(evt_b, "B", NR_SPAN_DATASTORE, evt_root, 7000, 2000); SPAN_EVENT_COMPARE_DATASTORE(evt_b, NULL, NULL, NULL, NULL); SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_MESSAGE, evt_root, 10000, 1000); - SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL, NULL, NULL, NULL); + SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL, NULL, NULL, NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -988,6 +992,7 @@ static void test_json_print_segments_message_attributes(void) { A.typed_attributes->message.destination_name = nr_strdup("queue_name"); A.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); A.typed_attributes->message.server_address = nr_strdup("localhost"); + A.typed_attributes->message.aws_operation = nr_strdup("sendMessage"); /* * Test : Normal operation @@ -1002,7 +1007,8 @@ static void test_json_print_segments_message_attributes(void) { "\"cloud_region\":\"us-west-1\"," "\"cloud_account_id\":\"12345678\"," "\"cloud_resource_id\":\"resource_id_info\"," - "\"server_address\":\"localhost\"" + "\"server_address\":\"localhost\"," + "\"aws_operation\":\"sendMessage\"" "},[]]]]"); tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 2); @@ -1014,7 +1020,8 @@ static void test_json_print_segments_message_attributes(void) { 9000); SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_MESSAGE, evt_root, 2000, 5000); SPAN_EVENT_COMPARE_MESSAGE(evt_a, "queue_name", "us-west-1", "12345678", - "aws_sqs", "resource_id_info", "localhost"); + "aws_sqs", "resource_id_info", "localhost", + "sendMessage"); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -1146,7 +1153,7 @@ static void test_json_print_segments_datastore_external_message(void) { SPAN_EVENT_COMPARE_EXTERNAL(evt_c, "example.com", "GET", "curl", 200); SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_MESSAGE, evt_a, 6000, 1000); SPAN_EVENT_COMPARE_MESSAGE(evt_d, "queue_name", "us-west-1", NULL, "aws_sqs", - NULL, NULL); + NULL, NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index 3d741e355..ea0bbdece 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -555,6 +555,16 @@ static void test_span_event_message_string_get_and_set(void) { "should be the component we set 2", "oracle", nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); + // Test : setting the server address back and forth behaves as expected + nr_span_event_set_message(event, NR_SPAN_MESSAGE_AWS_OPERATION, "chicken"); + tlib_pass_if_str_equal( + "should be the component we set 1", "chicken", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_AWS_OPERATION)); + nr_span_event_set_message(event, NR_SPAN_MESSAGE_AWS_OPERATION, "oracle"); + tlib_pass_if_str_equal( + "should be the component we set 2", "oracle", + nr_span_event_get_message(event, NR_SPAN_MESSAGE_AWS_OPERATION)); + nr_span_event_destroy(&event); } From c972a3534c497507472be3d6d42f27b5346f373e Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 24 Dec 2024 13:29:25 -0700 Subject: [PATCH 50/63] fix(axiom): Fixes --- axiom/nr_segment_message.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h index 0d1e46c09..ad6ff719d 100644 --- a/axiom/nr_segment_message.h +++ b/axiom/nr_segment_message.h @@ -49,18 +49,6 @@ typedef struct { } nr_segment_message_params_t; -static inline void nr_segment_message_destroy_message_params( - nr_segment_message_params_t* message_params) { - nr_free(message_params->library); - nr_free(message_params->destination_name); - nr_free(message_params->cloud_region); - nr_free(message_params->cloud_account_id); - nr_free(message_params->messaging_system); - nr_free(message_params->cloud_resource_id); - nr_free(message_params->server_address); - nr_free(message_params->aws_operation); -} - /* * Purpose : End a message segment and record metrics. * From 11480f425b64d82f007f2ba21b341da50bbcc0dd Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Tue, 24 Dec 2024 20:12:22 -0700 Subject: [PATCH 51/63] fix(axiom): copypaste error --- axiom/nr_segment_message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index f98abcb09..304f466b1 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -42,7 +42,7 @@ static void nr_segment_message_set_attrs( message_attributes.server_address = nr_strempty(params->server_address) ? NULL : params->server_address; message_attributes.aws_operation - = nr_strempty(params->server_address) ? NULL : params->aws_operation; + = nr_strempty(params->aws_operation) ? NULL : params->aws_operation; } nr_segment_set_message(segment, &message_attributes); From a91b7080206531226eac488160852305408408d4 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Mon, 30 Dec 2024 06:50:52 -0700 Subject: [PATCH 52/63] refactor(axiom): decoupled cloud attributes from message segment Separated cloud attributes from message segment. They can be applied to multiple segment types and don't belong in typed attributes. It will make it easier to add to other segments in the future. Added a function to add the cloud attributes. Reworked unit tests with new functionality. --- axiom/nr_segment.c | 14 --- axiom/nr_segment.h | 28 ++++-- axiom/nr_segment_message.c | 10 -- axiom/nr_segment_message.h | 23 ++--- axiom/nr_segment_private.c | 4 - axiom/nr_segment_traces.c | 70 ++++++++++++-- axiom/nr_segment_traces.h | 4 + axiom/nr_span_event.c | 25 ----- axiom/nr_span_event.h | 5 - axiom/tests/test_segment_message.c | 144 ++++++++++++++++------------- axiom/tests/test_segment_private.c | 6 -- axiom/tests/test_segment_traces.c | 61 ++++-------- axiom/tests/test_span_event.c | 41 -------- 13 files changed, 191 insertions(+), 244 deletions(-) diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index 52ff20ce4..1573cf548 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -329,18 +329,8 @@ static void nr_populate_message_spans(nr_span_event_t* span_event, nr_span_event_set_message( span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, segment->typed_attributes->message.messaging_system); - nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION, - segment->typed_attributes->message.cloud_region); - nr_span_event_set_message( - span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, - segment->typed_attributes->message.cloud_account_id); - nr_span_event_set_message( - span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, - segment->typed_attributes->message.cloud_resource_id); nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS, segment->typed_attributes->message.server_address); - nr_span_event_set_message(span_event, NR_SPAN_MESSAGE_AWS_OPERATION, - segment->typed_attributes->message.aws_operation); } static nr_status_t add_user_attribute_to_span_event(const char* key, @@ -649,12 +639,8 @@ bool nr_segment_set_message(nr_segment_t* segment, segment->typed_attributes->message = (nr_segment_message_t){ .message_action = message->message_action, .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, - .cloud_region = message->cloud_region ? nr_strdup(message->cloud_region) : NULL, - .cloud_account_id = message->cloud_account_id ? nr_strdup(message->cloud_account_id) : NULL, .messaging_system = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, - .cloud_resource_id = message->cloud_resource_id ? nr_strdup(message->cloud_resource_id) : NULL, .server_address = message->server_address ? nr_strdup(message->server_address) : NULL, - .aws_operation = message->aws_operation ? nr_strdup(message->aws_operation) : NULL, }; // clang-format on diff --git a/axiom/nr_segment.h b/axiom/nr_segment.h index 59822d07c..f35ab6224 100644 --- a/axiom/nr_segment.h +++ b/axiom/nr_segment.h @@ -122,21 +122,35 @@ typedef struct _nr_segment_message_t { */ nr_span_spankind_t - message_action; /*The action of the message, e.g.,Produce/Consume.*/ - char* destination_name; /*The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship.*/ + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /*The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* server_address; /*The server domain name or IP address. Needed for + MQBROKER relationship.*/ +} nr_segment_message_t; + +typedef struct _nr_segment_cloud_attrs_t { + /* + * Attributes needed for entity relationship building. + * Compare to OTEL attributes: + * https://opentelemetry.io/docs/specs/semconv/attributes-registry/cloud/ + * cloud.account.id, cloud.region, messaging.system and server.address are + * used to create relationships between APM and cloud services. It may not + * make sense to add these attributes unless they are used for creating one of + * the relationships in Entity Relationships. + * These attributes aren't specific to a segment category so don't belong as + * typed attributes and can be added whenever they are available. + */ char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS relationship.*/ char* cloud_account_id; /*The cloud provider account ID. Needed for SQS relationship.*/ - char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ char* cloud_resource_id; /*Unique cloud provider identifier. For AWS, this is the ARN of the AWS resource being accessed.*/ - char* server_address; /*The server domain name or IP address. Needed for - MQBROKER relationship.*/ char* aws_operation; /*AWS specific operation name.*/ -} nr_segment_message_t; +} nr_segment_cloud_attrs_t; typedef struct _nr_segment_metric_t { char* name; diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 304f466b1..b212ccf5c 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -28,21 +28,11 @@ static void nr_segment_message_set_attrs( message_attributes.destination_name = nr_strempty(params->destination_name) ? NULL : params->destination_name; - message_attributes.cloud_region - = nr_strempty(params->cloud_region) ? NULL : params->cloud_region; - message_attributes.cloud_account_id = nr_strempty(params->cloud_account_id) - ? NULL - : params->cloud_account_id; message_attributes.messaging_system = nr_strempty(params->messaging_system) ? NULL : params->messaging_system; - message_attributes.cloud_resource_id - = nr_strempty(params->cloud_resource_id) ? NULL - : params->cloud_resource_id; message_attributes.server_address = nr_strempty(params->server_address) ? NULL : params->server_address; - message_attributes.aws_operation - = nr_strempty(params->aws_operation) ? NULL : params->aws_operation; } nr_segment_set_message(segment, &message_attributes); diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h index ad6ff719d..b9f0d7ac0 100644 --- a/axiom/nr_segment_message.h +++ b/axiom/nr_segment_message.h @@ -7,6 +7,7 @@ #define NR_SEGMENT_MESSAGE_HDR #include "nr_segment.h" +#include "nr_segment_traces.h" /* * Note: @@ -25,28 +26,18 @@ typedef struct { /* All strings are null-terminated. When unset, the strings are ingored. */ /* Only used for creating metrics. */ - char* library; /* Library; Possible values are SQS, SNS, RabbitMQ, JMS */ nr_segment_message_destination_type_t destination_type; /* Named/temp queue/topic/exchange */ /* Used for creating message attributes. */ nr_span_spankind_t - message_action; /*The action of the message, e.g.,Produce/Consume.*/ - char* destination_name; /*The name of the Queue, Topic, or Exchange; - otherwise, Temp. Needed for SQS relationship.*/ - char* cloud_region; /*Targeted region; ex:us-east-1*. Needed for SQS - relationship.*/ - char* cloud_account_id; /*The cloud provider account ID. Needed for SQS - relationship.*/ - char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ - char* cloud_resource_id; /*A unique identifier given by the cloud resource. - For AWS, this is the ARN of the AWS resource being - accessed.*/ - char* server_address; /*The server domain name or IP address. Needed for - MQBROKER relationship.*/ - char* aws_operation; /*The AWS operation being called.*/ - + message_action; /*The action of the message, e.g.,Produce/Consume.*/ + char* destination_name; /*The name of the Queue, Topic, or Exchange; + otherwise, Temp. Needed for SQS relationship.*/ + char* messaging_system; /* for ex: aws_sqs. Needed for SQS relationship.*/ + char* server_address; /*The server domain name or IP address. Needed for + MQBROKER relationship.*/ } nr_segment_message_params_t; /* diff --git a/axiom/nr_segment_private.c b/axiom/nr_segment_private.c index e112306b6..f063862b7 100644 --- a/axiom/nr_segment_private.c +++ b/axiom/nr_segment_private.c @@ -46,11 +46,7 @@ void nr_segment_message_destroy_fields(nr_segment_message_t* message) { nr_free(message->destination_name); nr_free(message->messaging_system); - nr_free(message->cloud_region); - nr_free(message->cloud_account_id); - nr_free(message->cloud_resource_id); nr_free(message->server_address); - nr_free(message->aws_operation); } void nr_segment_destroy_typed_attributes( diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index 4d2a52f23..7bcc34e99 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -168,16 +168,8 @@ static void add_typed_attributes_to_buffer(nrbuf_t* buf, message->destination_name, false); add_hash_key_value_to_buffer(buf, "messaging_system", message->messaging_system, false); - add_hash_key_value_to_buffer(buf, "cloud_region", message->cloud_region, - false); - add_hash_key_value_to_buffer(buf, "cloud_account_id", - message->cloud_account_id, false); - add_hash_key_value_to_buffer(buf, "cloud_resource_id", - message->cloud_resource_id, false); add_hash_key_value_to_buffer(buf, "server_address", message->server_address, false); - add_hash_key_value_to_buffer(buf, "aws_operation", message->aws_operation, - false); } break; case NR_SEGMENT_CUSTOM: default: @@ -595,3 +587,65 @@ void nr_segment_traces_create_data( return; } + +/* + * Purpose : If available, add cloud attributes to segment. + * + * Params : 1. segment to create and add agent attributes to + * 2. nr_segment_cloud_attrs_t* that contains the attributes + * + * Returns : void + * + */ +extern void nr_segment_traces_add_cloud_attributes( + nr_segment_t* segment, + const nr_segment_cloud_attrs_t* cloud_attrs) { + if (NULL == cloud_attrs) { + return; + } + + if (NULL == segment) { + return; + } + + /* + * Ensure a spot for the attributes. + */ + + if (NULL == segment->attributes) { + segment->attributes = nr_attributes_create(segment->txn->attribute_config); + } + + if (nrunlikely(NULL == segment->attributes)) { + return; + } + +#define NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION \ + (NR_ATTRIBUTE_DESTINATION_TXN_TRACE | NR_ATTRIBUTE_DESTINATION_ERROR \ + | NR_ATTRIBUTE_DESTINATION_TXN_EVENT | NR_ATTRIBUTE_DESTINATION_SPAN) + + /* + * If the value is empty or null, ignore it. + */ + + if (!nr_strempty(cloud_attrs->cloud_region)) { + nr_attributes_agent_add_string(segment->attributes, + NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + "cloud.region", cloud_attrs->cloud_region); + } + if (!nr_strempty(cloud_attrs->cloud_account_id)) { + nr_attributes_agent_add_string( + segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + "cloud.account.id", cloud_attrs->cloud_account_id); + } + if (!nr_strempty(cloud_attrs->cloud_resource_id)) { + nr_attributes_agent_add_string( + segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + "cloud.resource_id", cloud_attrs->cloud_resource_id); + } + if (!nr_strempty(cloud_attrs->aws_operation)) { + nr_attributes_agent_add_string(segment->attributes, + NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + "aws.operation", cloud_attrs->aws_operation); + } +} diff --git a/axiom/nr_segment_traces.h b/axiom/nr_segment_traces.h index a8ccbb10f..aa9ad4610 100644 --- a/axiom/nr_segment_traces.h +++ b/axiom/nr_segment_traces.h @@ -124,4 +124,8 @@ bool nr_segment_traces_json_print_segments(nrbuf_t* buf, extern nr_segment_iter_return_t nr_segment_traces_stot_iterator_callback( nr_segment_t* segment, void* userdata); + +extern void nr_segment_traces_add_cloud_attributes( + nr_segment_t* segment, + const nr_segment_cloud_attrs_t* cloud_attrs); #endif diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index 9099d1dfb..a9cea1a40 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -369,27 +369,13 @@ void nr_span_event_set_message(nr_span_event_t* event, nro_set_hash_string(event->agent_attributes, "messaging.destination.name", new_value); break; - case NR_SPAN_MESSAGE_CLOUD_REGION: - nro_set_hash_string(event->agent_attributes, "cloud.region", new_value); - break; - case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: - nro_set_hash_string(event->agent_attributes, "cloud.account.id", - new_value); - break; case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: nro_set_hash_string(event->agent_attributes, "messaging.system", new_value); break; - case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: - nro_set_hash_string(event->agent_attributes, "cloud.resource_id", - new_value); - break; case NR_SPAN_MESSAGE_SERVER_ADDRESS: nro_set_hash_string(event->agent_attributes, "server.address", new_value); break; - case NR_SPAN_MESSAGE_AWS_OPERATION: - nro_set_hash_string(event->agent_attributes, "aws.operation", new_value); - break; } } @@ -542,23 +528,12 @@ const char* nr_span_event_get_message(const nr_span_event_t* event, case NR_SPAN_MESSAGE_DESTINATION_NAME: return nro_get_hash_string(event->agent_attributes, "messaging.destination.name", NULL); - case NR_SPAN_MESSAGE_CLOUD_REGION: - return nro_get_hash_string(event->agent_attributes, "cloud.region", NULL); - case NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID: - return nro_get_hash_string(event->agent_attributes, "cloud.account.id", - NULL); case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: return nro_get_hash_string(event->agent_attributes, "messaging.system", NULL); - case NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID: - return nro_get_hash_string(event->agent_attributes, "cloud.resource_id", - NULL); case NR_SPAN_MESSAGE_SERVER_ADDRESS: return nro_get_hash_string(event->agent_attributes, "server.address", NULL); - case NR_SPAN_MESSAGE_AWS_OPERATION: - return nro_get_hash_string(event->agent_attributes, "aws.operation", - NULL); } return NULL; } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 535ae545a..15a4ee880 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -70,13 +70,8 @@ typedef enum { */ typedef enum { NR_SPAN_MESSAGE_DESTINATION_NAME, - NR_SPAN_MESSAGE_CLOUD_REGION, - NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, - NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, NR_SPAN_MESSAGE_SERVER_ADDRESS, - NR_SPAN_MESSAGE_AWS_OPERATION - } nr_span_event_message_member_t; /* diff --git a/axiom/tests/test_segment_message.c b/axiom/tests/test_segment_message.c index ded26437e..75439210d 100644 --- a/axiom/tests/test_segment_message.c +++ b/axiom/tests/test_segment_message.c @@ -7,6 +7,16 @@ #include "nr_header.h" #include "nr_segment_message.h" #include "test_segment_helpers.h" +#include "nr_attributes.h" +#include "nr_attributes_private.h" +#include "util_hash.h" +#include "util_memory.h" +#include "util_object.h" +#include "util_reply.h" +#include "util_strings.h" +#include "util_text.h" + +#include "tlib_main.h" typedef struct { const char* test_name; @@ -30,15 +40,31 @@ static nr_segment_t* mock_txn_segment(void) { } static void test_message_segment(nr_segment_message_params_t* params, + nr_segment_cloud_attrs_t* cloud_attrs, bool message_attributes_enabled, segment_message_expecteds_t expecteds) { + uint32_t all = NR_ATTRIBUTE_DESTINATION_ALL; + nrobj_t* obj = NULL; nr_segment_t* seg = mock_txn_segment(); nrtxn_t* txn = seg->txn; seg->txn->options.message_tracer_segment_parameters_enabled = message_attributes_enabled; - test_segment_message_end_and_keep(&seg, params); + nr_segment_traces_add_cloud_attributes(seg, cloud_attrs); + /* Check the agent cloud attributes. */ + obj = nr_attributes_agent_to_obj(seg->attributes, all); + tlib_pass_if_str_equal(expecteds.test_name, expecteds.aws_operation, + nro_get_hash_string(obj, "aws.operation", 0)); + tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_resource_id, + nro_get_hash_string(obj, "cloud.resource_id", 0)); + tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_account_id, + nro_get_hash_string(obj, "cloud.account.id", 0)); + tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_region, + nro_get_hash_string(obj, "cloud.region", 0)); + nro_delete(obj); + test_segment_message_end_and_keep(&seg, params); + /* Check the metrics and txn naming. */ tlib_pass_if_str_equal(expecteds.test_name, expecteds.name, nr_string_get(seg->txn->trace_strings, seg->name)); test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, @@ -46,29 +72,19 @@ static void test_message_segment(nr_segment_message_params_t* params, test_txn_metric_created(expecteds.test_name, txn->unscoped_metrics, expecteds.library_metric); test_metric_vector_size(seg->metrics, expecteds.num_metrics); + + /* Check the segment settings and typed attributes. */ tlib_pass_if_true(expecteds.test_name, NR_SEGMENT_MESSAGE == seg->type, "NR_SEGMENT_MESSAGE"); tlib_pass_if_str_equal(expecteds.test_name, seg->typed_attributes->message.destination_name, expecteds.destination_name); - tlib_pass_if_str_equal(expecteds.test_name, - seg->typed_attributes->message.cloud_region, - expecteds.cloud_region); - tlib_pass_if_str_equal(expecteds.test_name, - seg->typed_attributes->message.cloud_account_id, - expecteds.cloud_account_id); tlib_pass_if_str_equal(expecteds.test_name, seg->typed_attributes->message.messaging_system, expecteds.messaging_system); - tlib_pass_if_str_equal(expecteds.test_name, - seg->typed_attributes->message.cloud_resource_id, - expecteds.cloud_resource_id); tlib_pass_if_str_equal(expecteds.test_name, seg->typed_attributes->message.server_address, expecteds.server_address); - tlib_pass_if_str_equal(expecteds.test_name, - seg->typed_attributes->message.aws_operation, - expecteds.aws_operation); nr_txn_destroy(&txn); } @@ -114,7 +130,7 @@ static void test_segment_message_destination_type(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC destination type", @@ -137,7 +153,7 @@ static void test_segment_message_destination_type(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE destination type", @@ -160,7 +176,7 @@ static void test_segment_message_destination_type(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_EXCHANGE, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", @@ -183,7 +199,7 @@ static void test_segment_message_destination_type(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_MESSAGE_DESTINATION_TYPE_EXCHANGE destination type", @@ -206,7 +222,7 @@ static void test_segment_message_destination_type(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_QUEUE, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_MESSAGE_DESTINATION_TYPE_QUEUE destination type", @@ -239,7 +255,7 @@ static void test_segment_message_message_action(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_SPAN_PRODUCER message action", .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", @@ -262,7 +278,7 @@ static void test_segment_message_message_action(void) { .message_action = NR_SPAN_CONSUMER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_SPAN_CONSUMER message action", .name = "MessageBroker/SQS/Topic/Consume/Named/my_queue_or_topic", @@ -287,7 +303,7 @@ static void test_segment_message_message_action(void) { .message_action = NR_SPAN_CLIENT, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test NR_SPAN_CLIENT message action", .name = "MessageBroker/SQS/Topic//Named/my_queue_or_topic", @@ -318,7 +334,7 @@ static void test_segment_message_library(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null library", .name @@ -342,7 +358,7 @@ static void test_segment_message_library(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty library", .name @@ -366,7 +382,7 @@ static void test_segment_message_library(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid library", .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", @@ -397,7 +413,7 @@ static void test_segment_message_destination_name(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = NULL}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null destination_name", .name = "MessageBroker/SQS/Topic/Produce/Named/", @@ -419,7 +435,7 @@ static void test_segment_message_destination_name(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = ""}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty destination_name", .name = "MessageBroker/SQS/Topic/Produce/Named/", @@ -441,7 +457,7 @@ static void test_segment_message_destination_name(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid destination_name", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -466,12 +482,11 @@ static void test_segment_message_cloud_region(void) { /* Test null cloud_region */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_region = NULL, .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null cloud_region", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -489,11 +504,11 @@ static void test_segment_message_cloud_region(void) { /* Test empty cloud_region */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_region = "", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_region = ""}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty cloud_region", @@ -512,11 +527,11 @@ static void test_segment_message_cloud_region(void) { /* Test valid cloud_region */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_region = "wild-west-1", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_region = "wild-west-1"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid cloud_region", @@ -542,12 +557,11 @@ static void test_segment_message_cloud_account_id(void) { /* Test null cloud_account_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_account_id = NULL, .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null cloud_account_id", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -565,11 +579,11 @@ static void test_segment_message_cloud_account_id(void) { /* Test empty cloud_account_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_account_id = "", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_account_id = ""}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty cloud_account_id", @@ -588,11 +602,11 @@ static void test_segment_message_cloud_account_id(void) { /* Test valid cloud_account_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_account_id = "12345678", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_account_id = "12345678"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid cloud_account_id", @@ -623,7 +637,7 @@ static void test_segment_message_messaging_system(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null messaging_system", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -646,7 +660,7 @@ static void test_segment_message_messaging_system(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty messaging_system", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -669,7 +683,7 @@ static void test_segment_message_messaging_system(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid messaging_system", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -694,12 +708,11 @@ static void test_segment_message_cloud_resource_id(void) { /* Test null cloud_resource_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_resource_id = NULL, .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null cloud_resource_id ", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -717,11 +730,11 @@ static void test_segment_message_cloud_resource_id(void) { /* Test empty cloud_resource_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_resource_id = "", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_resource_id = ""}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty cloud_resource_id ", @@ -740,11 +753,11 @@ static void test_segment_message_cloud_resource_id(void) { /* Test valid cloud_resource_id */ test_message_segment( &(nr_segment_message_params_t){ - .cloud_resource_id = "my_resource_id", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.cloud_resource_id = "my_resource_id"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid cloud_resource_id ", @@ -775,7 +788,7 @@ static void test_segment_message_server_address(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null server_address", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -798,7 +811,7 @@ static void test_segment_message_server_address(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty server_address", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -821,7 +834,7 @@ static void test_segment_message_server_address(void) { .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid server_address", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -846,12 +859,11 @@ static void test_segment_message_aws_operation(void) { /* Test null aws_operation */ test_message_segment( &(nr_segment_message_params_t){ - .aws_operation = NULL, .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, - true /* enable attributes */, + &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test null aws_operation", .name = "MessageBroker/SQS/Topic/Produce/Named/my_destination", @@ -869,11 +881,11 @@ static void test_segment_message_aws_operation(void) { /* Test empty aws_operation */ test_message_segment( &(nr_segment_message_params_t){ - .aws_operation = "sendMessage", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.aws_operation = ""}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test empty aws_operation", @@ -892,11 +904,11 @@ static void test_segment_message_aws_operation(void) { /* Test valid aws_operation */ test_message_segment( &(nr_segment_message_params_t){ - .aws_operation = "sendMessage", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test valid aws_operation", @@ -910,7 +922,7 @@ static void test_segment_message_aws_operation(void) { .messaging_system = NULL, .cloud_resource_id = NULL, .server_address = NULL, - .aws_operation = NULL}); + .aws_operation = "sendMessage"}); } static void test_segment_message_parameters_enabled(void) { @@ -922,15 +934,15 @@ static void test_segment_message_parameters_enabled(void) { test_message_segment( &(nr_segment_message_params_t){ .server_address = "localhost", - .cloud_region = "wild-west-1", - .cloud_account_id = "12345678", .messaging_system = "my_system", - .cloud_resource_id = "my_resource_id", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, - .destination_name = "my_destination", - .aws_operation = "sendMessage"}, + .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .cloud_resource_id = "my_resource_id"}, true /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test true message_parameters_enabled", @@ -946,19 +958,22 @@ static void test_segment_message_parameters_enabled(void) { .server_address = "localhost", .aws_operation = "sendMessage"}); - /* Test false message_parameters_enabled */ + /* + * Test false message_parameters_enabled. Message attributes should not show, + * but cloud attributes should be unaffected. + */ test_message_segment( &(nr_segment_message_params_t){ .server_address = "localhost", - .cloud_region = "wild-west-1", - .cloud_account_id = "12345678", .messaging_system = "my_system", - .cloud_resource_id = "my_resource_id", .library = "SQS", .message_action = NR_SPAN_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, - .destination_name = "my_destination", - .aws_operation = "sendMessage"}, + .destination_name = "my_destination"}, + &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage", + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", + .cloud_resource_id = "my_resource_id"}, false /* enable attributes */, (segment_message_expecteds_t){ .test_name = "Test false message_parameters_enabled", @@ -967,11 +982,12 @@ static void test_segment_message_parameters_enabled(void) { .library_metric = "MessageBroker/SQS/all", .num_metrics = 1, .destination_name = NULL, - .cloud_account_id = NULL, + .cloud_region = "wild-west-1", + .cloud_account_id = "12345678", .messaging_system = NULL, - .cloud_resource_id = NULL, + .cloud_resource_id = "my_resource_id", .server_address = NULL, - .aws_operation = NULL}); + .aws_operation = "sendMessage"}); } tlib_parallel_info_t parallel_info = {.suggested_nthreads = 4, .state_size = 0}; diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index e4407aa8f..d21e4dd1e 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -320,10 +320,7 @@ static void test_set_destroy_message_fields(void) { nr_segment_t s = {.type = NR_SEGMENT_MESSAGE}; nr_segment_message_t m = {.message_action = NR_SPAN_CLIENT, - .cloud_region = "my_cloud_region", - .cloud_account_id = "12345678", .messaging_system = "my_messaging_system", - .cloud_resource_id = "my_cloud_resource_id", .server_address = "localhost"}; nr_segment_external_t e = {.transaction_guid = "transaction_guid", @@ -381,9 +378,6 @@ static void test_destroy_typed_attributes(void) { */ s.type = NR_SEGMENT_MESSAGE; s.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); - s.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); - s.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); - s.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); s.typed_attributes->message.destination_name = nr_strdup("queue_name"); s.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); s.typed_attributes->message.server_address = nr_strdup("localhost"); diff --git a/axiom/tests/test_segment_traces.c b/axiom/tests/test_segment_traces.c index 5c224a6ec..ac5db9642 100644 --- a/axiom/tests/test_segment_traces.c +++ b/axiom/tests/test_segment_traces.c @@ -90,32 +90,18 @@ tlib_pass_if_int_equal("status", expected_status, \ nr_span_event_get_external_status(span_event)); -#define SPAN_EVENT_COMPARE_MESSAGE( \ - span_event, expected_destination_name, expected_cloud_region, \ - expected_cloud_account_id, expected_messaging_system, \ - expected_cloud_resource_id, expected_server_address, \ - expected_aws_operation) \ - tlib_pass_if_str_equal("destination.name", expected_destination_name, \ - nr_span_event_get_message( \ - span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ - tlib_pass_if_str_equal( \ - "cloud.region", expected_cloud_region, \ - nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_CLOUD_REGION)); \ - tlib_pass_if_str_equal("cloud.account.id", expected_cloud_account_id, \ - nr_span_event_get_message( \ - span_event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); \ - tlib_pass_if_str_equal("messaging.system", expected_messaging_system, \ - nr_span_event_get_message( \ - span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); \ - tlib_pass_if_str_equal("cloud.resource_id", expected_cloud_resource_id, \ - nr_span_event_get_message( \ - span_event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); \ - tlib_pass_if_str_equal( \ - "server.address", expected_server_address, \ - nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); \ - tlib_pass_if_str_equal( \ - "aws.operation", expected_aws_operation, \ - nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_AWS_OPERATION)); +#define SPAN_EVENT_COMPARE_MESSAGE(span_event, expected_destination_name, \ + expected_messaging_system, \ + expected_server_address) \ + tlib_pass_if_str_equal("destination.name", expected_destination_name, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ + tlib_pass_if_str_equal("messaging.system", expected_messaging_system, \ + nr_span_event_get_message( \ + span_event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); \ + tlib_pass_if_str_equal( \ + "server.address", expected_server_address, \ + nr_span_event_get_message(span_event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); static void nr_vector_span_event_dtor(void* element, void* userdata NRUNUSED) { nr_span_event_destroy((nr_span_event_t**)&element); @@ -745,7 +731,7 @@ static void test_json_print_segments_invalid_typed_attributes(void) { SPAN_EVENT_COMPARE(evt_b, "B", NR_SPAN_DATASTORE, evt_root, 7000, 2000); SPAN_EVENT_COMPARE_DATASTORE(evt_b, NULL, NULL, NULL, NULL); SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_MESSAGE, evt_root, 10000, 1000); - SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + SPAN_EVENT_COMPARE_MESSAGE(evt_c, NULL, NULL, NULL); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -986,13 +972,9 @@ static void test_json_print_segments_message_attributes(void) { A.type = NR_SEGMENT_MESSAGE; A.attributes = NULL; A.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); - A.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); - A.typed_attributes->message.cloud_account_id = nr_strdup("12345678"); - A.typed_attributes->message.cloud_resource_id = nr_strdup("resource_id_info"); A.typed_attributes->message.destination_name = nr_strdup("queue_name"); A.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); A.typed_attributes->message.server_address = nr_strdup("localhost"); - A.typed_attributes->message.aws_operation = nr_strdup("sendMessage"); /* * Test : Normal operation @@ -1004,11 +986,7 @@ static void test_json_print_segments_message_attributes(void) { "[0,9,\"`0\",{},[[1,6,\"`1\",{" "\"destination_name\":\"queue_name\"," "\"messaging_system\":\"aws_sqs\"," - "\"cloud_region\":\"us-west-1\"," - "\"cloud_account_id\":\"12345678\"," - "\"cloud_resource_id\":\"resource_id_info\"," - "\"server_address\":\"localhost\"," - "\"aws_operation\":\"sendMessage\"" + "\"server_address\":\"localhost\"" "},[]]]]"); tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 2); @@ -1019,9 +997,7 @@ static void test_json_print_segments_message_attributes(void) { SPAN_EVENT_COMPARE(evt_root, "WebTransaction/*", NR_SPAN_GENERIC, NULL, 1000, 9000); SPAN_EVENT_COMPARE(evt_a, "A", NR_SPAN_MESSAGE, evt_root, 2000, 5000); - SPAN_EVENT_COMPARE_MESSAGE(evt_a, "queue_name", "us-west-1", "12345678", - "aws_sqs", "resource_id_info", "localhost", - "sendMessage"); + SPAN_EVENT_COMPARE_MESSAGE(evt_a, "queue_name", "aws_sqs", "localhost"); /* Clean up */ nr_segment_children_deinit(&root.children); @@ -1109,7 +1085,6 @@ static void test_json_print_segments_datastore_external_message(void) { D.typed_attributes = nr_zalloc(sizeof(nr_segment_typed_attributes_t)); D.typed_attributes->message.destination_name = nr_strdup("queue_name"); D.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); - D.typed_attributes->message.cloud_region = nr_strdup("us-west-1"); /* * Test : Normal operation @@ -1132,8 +1107,7 @@ static void test_json_print_segments_datastore_external_message(void) { "\"status\":200},[]]," "[5,6,\"`4\"," "{\"destination_name\":\"queue_name\"," - "\"messaging_system\":\"aws_sqs\"," - "\"cloud_region\":\"us-west-1\"},[]]]]]]"); + "\"messaging_system\":\"aws_sqs\"},[]]]]]]"); tlib_pass_if_uint_equal("span event size", nr_vector_size(span_events), 5); @@ -1152,8 +1126,7 @@ static void test_json_print_segments_datastore_external_message(void) { SPAN_EVENT_COMPARE(evt_c, "C", NR_SPAN_HTTP, evt_a, 5000, 1000); SPAN_EVENT_COMPARE_EXTERNAL(evt_c, "example.com", "GET", "curl", 200); SPAN_EVENT_COMPARE(evt_d, "D", NR_SPAN_MESSAGE, evt_a, 6000, 1000); - SPAN_EVENT_COMPARE_MESSAGE(evt_d, "queue_name", "us-west-1", NULL, "aws_sqs", - NULL, NULL, NULL); + SPAN_EVENT_COMPARE_MESSAGE(evt_d, "queue_name", "aws_sqs", NULL); /* Clean up */ nr_segment_children_deinit(&root.children); diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index ea0bbdece..f3be09b0e 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -494,16 +494,6 @@ static void test_span_event_message_string_get_and_set(void) { "NULL event -> NULL component", nr_span_event_get_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME)); - // Test : setting the cloud region back and forth behaves as expected - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "chicken"); - tlib_pass_if_str_equal( - "should be the component we set 1", "chicken", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_REGION, "oracle"); - tlib_pass_if_str_equal( - "should be the component we set 2", "oracle", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_REGION)); - // Test : setting the destination name back and forth behaves as expected nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "chicken"); tlib_pass_if_str_equal( @@ -514,16 +504,6 @@ static void test_span_event_message_string_get_and_set(void) { "should be the component we set 2", "oracle", nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); - // Test : setting the cloud account id back and forth behaves as expected - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "chicken"); - tlib_pass_if_str_equal( - "should be the component we set 1", "chicken", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID, "oracle"); - tlib_pass_if_str_equal( - "should be the component we set 2", "oracle", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_ACCOUNT_ID)); - // Test : setting the messaging system back and forth behaves as expected nr_span_event_set_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM, "chicken"); tlib_pass_if_str_equal( @@ -534,17 +514,6 @@ static void test_span_event_message_string_get_and_set(void) { "should be the component we set 2", "oracle", nr_span_event_get_message(event, NR_SPAN_MESSAGE_MESSAGING_SYSTEM)); - // Test : setting the cloud resource id back and forth behaves as expected - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, - "chicken"); - tlib_pass_if_str_equal( - "should be the component we set 1", "chicken", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); - nr_span_event_set_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID, "oracle"); - tlib_pass_if_str_equal( - "should be the component we set 2", "oracle", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_CLOUD_RESOURCE_ID)); - // Test : setting the server address back and forth behaves as expected nr_span_event_set_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS, "chicken"); tlib_pass_if_str_equal( @@ -555,16 +524,6 @@ static void test_span_event_message_string_get_and_set(void) { "should be the component we set 2", "oracle", nr_span_event_get_message(event, NR_SPAN_MESSAGE_SERVER_ADDRESS)); - // Test : setting the server address back and forth behaves as expected - nr_span_event_set_message(event, NR_SPAN_MESSAGE_AWS_OPERATION, "chicken"); - tlib_pass_if_str_equal( - "should be the component we set 1", "chicken", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_AWS_OPERATION)); - nr_span_event_set_message(event, NR_SPAN_MESSAGE_AWS_OPERATION, "oracle"); - tlib_pass_if_str_equal( - "should be the component we set 2", "oracle", - nr_span_event_get_message(event, NR_SPAN_MESSAGE_AWS_OPERATION)); - nr_span_event_destroy(&event); } From 2568161c07e6087289e2c8fb434ec0eb09e1173c Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 12:05:50 -0700 Subject: [PATCH 53/63] revert(axiom): externalCallCount fix in lieu of another PR --- axiom/nr_txn.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index 8c2a4a75d..af00f8e0c 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -2588,8 +2588,6 @@ nrobj_t* nr_txn_event_intrinsics(const nrtxn_t* txn) { params, txn->unscoped_metrics, "WebFrontend/QueueTime", "queueDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "External/all", "externalDuration"); - nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, - "External/all", "externalCallCount"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, From fd2a67f899f04eb8e26cefc4cb1228e3dd5eab04 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 12:12:21 -0700 Subject: [PATCH 54/63] Revert "revert(axiom): externalCallCount fix in lieu of another PR" This reverts commit 2568161c07e6087289e2c8fb434ec0eb09e1173c. --- axiom/nr_txn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index af00f8e0c..8c2a4a75d 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -2588,6 +2588,8 @@ nrobj_t* nr_txn_event_intrinsics(const nrtxn_t* txn) { params, txn->unscoped_metrics, "WebFrontend/QueueTime", "queueDuration"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "External/all", "externalDuration"); + nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, + "External/all", "externalCallCount"); nr_txn_add_metric_total_as_attribute(params, txn->unscoped_metrics, "Datastore/all", "databaseDuration"); nr_txn_add_metric_count_as_attribute(params, txn->unscoped_metrics, From e709661c81e78e2b9a7dea907eb683c803b00e7f Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 13:59:23 -0700 Subject: [PATCH 55/63] Update axiom/nr_segment_message.c Co-authored-by: Michael Fulbright <89205663+mfulb@users.noreply.github.com> --- axiom/nr_segment_message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index b212ccf5c..579254a79 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -45,7 +45,7 @@ static void nr_segment_message_set_attrs( * Metrics created during this call * ---------------------------------------------------------------------------------- * MessageBroker/all Unscoped Always - * MessageBroker/{library}/all coped Always + * MessageBroker/{library}/all Scoped Always * * Metrics created based on MessageBroker/all (in nr_txn_create_rollup_metrics) * ---------------------------------------------------------------------------------- From fde6d510b065a30bc0b242411b5a39a31b86da6a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 14:07:51 -0700 Subject: [PATCH 56/63] chore(axiom): Update comment --- axiom/tests/test_segment_private.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index d21e4dd1e..72ef4f4a2 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -382,6 +382,9 @@ static void test_destroy_typed_attributes(void) { s.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); s.typed_attributes->message.server_address = nr_strdup("localhost"); + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); /* @@ -395,6 +398,9 @@ static void test_destroy_typed_attributes(void) { s.typed_attributes->external.procedure = nr_strdup(test_string); s.typed_attributes->external.status = 200; + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); /* @@ -413,6 +419,9 @@ static void test_destroy_typed_attributes(void) { = nr_strdup(test_string); s.typed_attributes->datastore.instance.database_name = nr_strdup(test_string); + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); } From 12af96f1c587a461066885a918d0d8cd36d3182c Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 14:21:04 -0700 Subject: [PATCH 57/63] chore(axiom): Fixed comment to account for wraparound formatting issue --- axiom/nr_segment_message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 579254a79..fee36c616 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -55,8 +55,9 @@ static void nr_segment_message_set_attrs( * Segment name * ----------------------------------------------------------------------------------- * MessageBroker/{library}/all Always + * For non-temp: * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * non-temp + * For temp: * MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp * * From 6aec35d7650ec9941a75c8f8198a2f14765de0f3 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Wed, 8 Jan 2025 15:05:16 -0700 Subject: [PATCH 58/63] refactor(axiom): move strempty check to nr_segment_set_message nr_segment_set_message was already checking for null, so moving the strempty check there reduced total overall operations. --- axiom/nr_segment.c | 6 +++--- axiom/nr_segment_message.c | 15 +++++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/axiom/nr_segment.c b/axiom/nr_segment.c index 1573cf548..4aaf7c120 100644 --- a/axiom/nr_segment.c +++ b/axiom/nr_segment.c @@ -638,9 +638,9 @@ bool nr_segment_set_message(nr_segment_t* segment, // Initialize the fields of the message attributes, one field per line. segment->typed_attributes->message = (nr_segment_message_t){ .message_action = message->message_action, - .destination_name = message->destination_name ? nr_strdup(message->destination_name) : NULL, - .messaging_system = message->messaging_system ? nr_strdup(message->messaging_system) : NULL, - .server_address = message->server_address ? nr_strdup(message->server_address) : NULL, + .destination_name = nr_strempty(message->destination_name) ? NULL: nr_strdup(message->destination_name), + .messaging_system = nr_strempty(message->messaging_system) ? NULL: nr_strdup(message->messaging_system), + .server_address = nr_strempty(message->server_address) ? NULL: nr_strdup(message->server_address), }; // clang-format on diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index fee36c616..a8bcdf03e 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -25,14 +25,9 @@ static void nr_segment_message_set_attrs( message_attributes.message_action = params->message_action; if (options.message_tracer_segment_parameters_enabled) { - message_attributes.destination_name = nr_strempty(params->destination_name) - ? NULL - : params->destination_name; - message_attributes.messaging_system = nr_strempty(params->messaging_system) - ? NULL - : params->messaging_system; - message_attributes.server_address - = nr_strempty(params->server_address) ? NULL : params->server_address; + message_attributes.destination_name = params->destination_name; + message_attributes.messaging_system = params->messaging_system; + message_attributes.server_address = params->server_address; } nr_segment_set_message(segment, &message_attributes); @@ -57,8 +52,8 @@ static void nr_segment_message_set_attrs( * MessageBroker/{library}/all Always * For non-temp: * MessageBroker/{Library}/{DestinationType}/{Action}/Named/{DestinationName} - * For temp: - * MessageBroker/{Library}/{DestinationType}/{Action}/Temp temp + * For temp: + * MessageBroker/{Library}/{DestinationType}/{Action}/Temp * * * These metrics are dictated by the agent-spec file here: From 97218d6120f6039daa904dcff59bcc18d54c45e1 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 9 Jan 2025 11:39:11 -0700 Subject: [PATCH 59/63] fix(axiom): Clarify comment about NULL assumptions --- axiom/nr_segment_message.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index a8bcdf03e..3ee95d2c9 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -15,6 +15,17 @@ /* * Purpose : Set all the typed message attributes on the segment. + * + * Params : 1. nr_segment_t* ASSUMED TO BE NON-NULL - the segment to set the + * attributes on + * 2. nr_segment_message_params_t* ASSUMED TO BE NON-NULL - the + * parameters set the attributes to + * 3. nrtxnopt_t - the segment options, to determine whether to set + * attributes or not Returns: true on success. + * + * Note: This is a function private to this file and assumes the calling + * function has already checked the input parameters for NULL prior to calling + * this function. */ static void nr_segment_message_set_attrs( nr_segment_t* segment, From 862604b081029206c2072275588076691d30560a Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 9 Jan 2025 13:59:16 -0700 Subject: [PATCH 60/63] fix(axiom): PR responses various comments additional tests refactor nr_segment_message_set_attrs to not take options --- axiom/Makefile | 1 + axiom/nr_segment_message.c | 18 +++--- axiom/nr_segment_traces.c | 16 +++--- axiom/nr_span_event.c | 35 ++++++------ axiom/nr_span_event.h | 18 ++++-- axiom/nr_txn.c | 6 +- axiom/tests/test_segment_message.c | 92 +++++++++++++++--------------- axiom/tests/test_segment_private.c | 20 +++---- axiom/tests/test_segment_traces.c | 3 +- axiom/tests/test_span_event.c | 31 ++++++---- 10 files changed, 133 insertions(+), 107 deletions(-) diff --git a/axiom/Makefile b/axiom/Makefile index aef7c069c..4cce3a6f6 100644 --- a/axiom/Makefile +++ b/axiom/Makefile @@ -17,6 +17,7 @@ # Useful variables: # # AR: The archiver used to build a static library (default: ar). +# CC: The C compiler to use (default: gcc). # CFLAGS: Flags to give the C compiler when building object files. # diff --git a/axiom/nr_segment_message.c b/axiom/nr_segment_message.c index 3ee95d2c9..56e9ed2b9 100644 --- a/axiom/nr_segment_message.c +++ b/axiom/nr_segment_message.c @@ -20,22 +20,22 @@ * attributes on * 2. nr_segment_message_params_t* ASSUMED TO BE NON-NULL - the * parameters set the attributes to - * 3. nrtxnopt_t - the segment options, to determine whether to set - * attributes or not Returns: true on success. + * + * Returns: true on success. * * Note: This is a function private to this file and assumes the calling * function has already checked the input parameters for NULL prior to calling - * this function. + * this function. Calling function is assumed to check the following items for + * NULL: if (NULL == segment || NULL == message_params || NULL == segment->txn) */ static void nr_segment_message_set_attrs( nr_segment_t* segment, - const nr_segment_message_params_t* params, - nrtxnopt_t options) { + const nr_segment_message_params_t* params) { nr_segment_message_t message_attributes = {0}; message_attributes.message_action = params->message_action; - if (options.message_tracer_segment_parameters_enabled) { + if (segment->txn->options.message_tracer_segment_parameters_enabled) { message_attributes.destination_name = params->destination_name; message_attributes.messaging_system = params->messaging_system; message_attributes.server_address = params->server_address; @@ -132,9 +132,9 @@ static char* nr_segment_message_create_metrics( * with spec. */ - if (NR_SPAN_PRODUCER == message_params->message_action) { + if (NR_SPANKIND_PRODUCER == message_params->message_action) { action_string = "Produce"; - } else if (NR_SPAN_CONSUMER == message_params->message_action) { + } else if (NR_SPANKIND_CONSUMER == message_params->message_action) { action_string = "Consume"; } else { action_string = ""; @@ -214,7 +214,7 @@ bool nr_segment_message_end(nr_segment_t** segment_ptr, } } - nr_segment_message_set_attrs(segment, message_params, segment->txn->options); + nr_segment_message_set_attrs(segment, message_params); /* * We set the end time here because we need the duration, (nr_segment_end will diff --git a/axiom/nr_segment_traces.c b/axiom/nr_segment_traces.c index 7bcc34e99..153ccd5c2 100644 --- a/axiom/nr_segment_traces.c +++ b/axiom/nr_segment_traces.c @@ -629,23 +629,23 @@ extern void nr_segment_traces_add_cloud_attributes( */ if (!nr_strempty(cloud_attrs->cloud_region)) { - nr_attributes_agent_add_string(segment->attributes, - NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, - "cloud.region", cloud_attrs->cloud_region); + nr_attributes_agent_add_string( + segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + NR_ATTR_CLOUD_REGION, cloud_attrs->cloud_region); } if (!nr_strempty(cloud_attrs->cloud_account_id)) { nr_attributes_agent_add_string( segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, - "cloud.account.id", cloud_attrs->cloud_account_id); + NR_ATTR_CLOUD_ACCOUNT_ID, cloud_attrs->cloud_account_id); } if (!nr_strempty(cloud_attrs->cloud_resource_id)) { nr_attributes_agent_add_string( segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, - "cloud.resource_id", cloud_attrs->cloud_resource_id); + NR_ATTR_CLOUD_RESOURCE_ID, cloud_attrs->cloud_resource_id); } if (!nr_strempty(cloud_attrs->aws_operation)) { - nr_attributes_agent_add_string(segment->attributes, - NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, - "aws.operation", cloud_attrs->aws_operation); + nr_attributes_agent_add_string( + segment->attributes, NR_CLOUD_AGENT_ATTRIBUTE_DESTINATION, + NR_ATTR_AWS_OPERATION, cloud_attrs->aws_operation); } } diff --git a/axiom/nr_span_event.c b/axiom/nr_span_event.c index a9cea1a40..00987881a 100644 --- a/axiom/nr_span_event.c +++ b/axiom/nr_span_event.c @@ -141,23 +141,23 @@ void nr_span_event_set_category(nr_span_event_t* event, switch (category) { case NR_SPAN_DATASTORE: nro_set_hash_string(event->intrinsics, "category", "datastore"); - nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + nr_span_event_set_spankind(event, NR_SPANKIND_CLIENT); break; case NR_SPAN_GENERIC: nro_set_hash_string(event->intrinsics, "category", "generic"); - nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + nr_span_event_set_spankind(event, NR_SPANKIND_NO_SPANKIND); break; case NR_SPAN_HTTP: nro_set_hash_string(event->intrinsics, "category", "http"); - nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + nr_span_event_set_spankind(event, NR_SPANKIND_CLIENT); break; case NR_SPAN_MESSAGE: nro_set_hash_string(event->intrinsics, "category", "message"); /* give it a default value in case we exit before spankind is set*/ - nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + nr_span_event_set_spankind(event, NR_SPANKIND_NO_SPANKIND); break; } } @@ -169,16 +169,16 @@ void nr_span_event_set_spankind(nr_span_event_t* event, } switch (spankind) { - case NR_SPAN_PRODUCER: + case NR_SPANKIND_PRODUCER: nro_set_hash_string(event->intrinsics, "span.kind", "producer"); break; - case NR_SPAN_CLIENT: + case NR_SPANKIND_CLIENT: nro_set_hash_string(event->intrinsics, "span.kind", "client"); break; - case NR_SPAN_CONSUMER: + case NR_SPANKIND_CONSUMER: nro_set_hash_string(event->intrinsics, "span.kind", "consumer"); break; - case NR_SPAN_NO_SPANKIND: + case NR_SPANKIND_NO_SPANKIND: default: if (nro_get_hash_value(event->intrinsics, "span.kind", NULL)) { nro_set_hash_none(event->intrinsics, "span.kind"); @@ -366,15 +366,16 @@ void nr_span_event_set_message(nr_span_event_t* event, switch (member) { case NR_SPAN_MESSAGE_DESTINATION_NAME: - nro_set_hash_string(event->agent_attributes, "messaging.destination.name", - new_value); + nro_set_hash_string(event->agent_attributes, + NR_ATTR_MESSAGING_DESTINATION_NAME, new_value); break; case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: - nro_set_hash_string(event->agent_attributes, "messaging.system", + nro_set_hash_string(event->agent_attributes, NR_ATTR_MESSAGING_SYSTEM, new_value); break; case NR_SPAN_MESSAGE_SERVER_ADDRESS: - nro_set_hash_string(event->agent_attributes, "server.address", new_value); + nro_set_hash_string(event->agent_attributes, NR_ATTR_SERVER_ADDRESS, + new_value); break; } } @@ -527,13 +528,13 @@ const char* nr_span_event_get_message(const nr_span_event_t* event, switch (member) { case NR_SPAN_MESSAGE_DESTINATION_NAME: return nro_get_hash_string(event->agent_attributes, - "messaging.destination.name", NULL); + NR_ATTR_MESSAGING_DESTINATION_NAME, NULL); case NR_SPAN_MESSAGE_MESSAGING_SYSTEM: - return nro_get_hash_string(event->agent_attributes, "messaging.system", - NULL); + return nro_get_hash_string(event->agent_attributes, + NR_ATTR_MESSAGING_SYSTEM, NULL); case NR_SPAN_MESSAGE_SERVER_ADDRESS: - return nro_get_hash_string(event->agent_attributes, "server.address", - NULL); + return nro_get_hash_string(event->agent_attributes, + NR_ATTR_SERVER_ADDRESS, NULL); } return NULL; } diff --git a/axiom/nr_span_event.h b/axiom/nr_span_event.h index 15a4ee880..2a87b2306 100644 --- a/axiom/nr_span_event.h +++ b/axiom/nr_span_event.h @@ -13,6 +13,14 @@ #include #include +#define NR_ATTR_MESSAGING_DESTINATION_NAME "messaging.destination.name" +#define NR_ATTR_MESSAGING_SYSTEM "messaging.system" +#define NR_ATTR_SERVER_ADDRESS "server.address" +#define NR_ATTR_CLOUD_REGION "cloud.region" +#define NR_ATTR_CLOUD_ACCOUNT_ID "cloud.account.id" +#define NR_ATTR_CLOUD_RESOURCE_ID "cloud.resource_id" +#define NR_ATTR_AWS_OPERATION "aws.operation" + typedef struct _nr_span_event_t nr_span_event_t; /* @@ -39,10 +47,10 @@ typedef enum { * NOT create) c) consumer when the operation type is process */ typedef enum { - NR_SPAN_PRODUCER, - NR_SPAN_CLIENT, - NR_SPAN_CONSUMER, - NR_SPAN_NO_SPANKIND + NR_SPANKIND_PRODUCER, + NR_SPANKIND_CLIENT, + NR_SPANKIND_CONSUMER, + NR_SPANKIND_NO_SPANKIND } nr_span_spankind_t; /* @@ -146,7 +154,7 @@ extern void nr_span_event_set_transaction_name(nr_span_event_t* event, extern void nr_span_event_set_category(nr_span_event_t* event, nr_span_category_t category); extern void nr_span_event_set_spankind(nr_span_event_t* event, - nr_span_spankind_t category); + nr_span_spankind_t spankind); extern void nr_span_event_set_timestamp(nr_span_event_t* event, nrtime_t time); extern void nr_span_event_set_duration(nr_span_event_t* event, nrtime_t duration); diff --git a/axiom/nr_txn.c b/axiom/nr_txn.c index 8c2a4a75d..06c0214ef 100644 --- a/axiom/nr_txn.c +++ b/axiom/nr_txn.c @@ -60,8 +60,10 @@ struct _nr_txn_attribute_t { #define NR_TXN_ATTRIBUTE_TRACE_ERROR \ (NR_ATTRIBUTE_DESTINATION_TXN_TRACE | NR_ATTRIBUTE_DESTINATION_ERROR) -#define NR_TXN_ATTR(X, NAME, DESTS) \ - const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { (NAME), (DESTS) } +#define NR_TXN_ATTR(X, NAME, DESTS) \ + const nr_txn_attribute_t* X = &(nr_txn_attribute_t) { \ + (NAME), (DESTS) \ + } NR_TXN_ATTR(nr_txn_request_uri, "request.uri", diff --git a/axiom/tests/test_segment_message.c b/axiom/tests/test_segment_message.c index 75439210d..a68403caf 100644 --- a/axiom/tests/test_segment_message.c +++ b/axiom/tests/test_segment_message.c @@ -54,13 +54,14 @@ static void test_message_segment(nr_segment_message_params_t* params, /* Check the agent cloud attributes. */ obj = nr_attributes_agent_to_obj(seg->attributes, all); tlib_pass_if_str_equal(expecteds.test_name, expecteds.aws_operation, - nro_get_hash_string(obj, "aws.operation", 0)); - tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_resource_id, - nro_get_hash_string(obj, "cloud.resource_id", 0)); + nro_get_hash_string(obj, NR_ATTR_AWS_OPERATION, 0)); + tlib_pass_if_str_equal( + expecteds.test_name, expecteds.cloud_resource_id, + nro_get_hash_string(obj, NR_ATTR_CLOUD_RESOURCE_ID, 0)); tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_account_id, - nro_get_hash_string(obj, "cloud.account.id", 0)); + nro_get_hash_string(obj, NR_ATTR_CLOUD_ACCOUNT_ID, 0)); tlib_pass_if_str_equal(expecteds.test_name, expecteds.cloud_region, - nro_get_hash_string(obj, "cloud.region", 0)); + nro_get_hash_string(obj, NR_ATTR_CLOUD_REGION, 0)); nro_delete(obj); test_segment_message_end_and_keep(&seg, params); @@ -99,6 +100,7 @@ static void test_bad_parameters(void) { "expected false"); seg_null_ptr = NULL; + tlib_pass_if_false("bad parameters", nr_segment_message_end(&seg_null_ptr, ¶ms), "expected false"); @@ -127,7 +129,7 @@ static void test_segment_message_destination_type(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -150,7 +152,7 @@ static void test_segment_message_destination_type(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TEMP_QUEUE, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -173,7 +175,7 @@ static void test_segment_message_destination_type(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_EXCHANGE, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -196,7 +198,7 @@ static void test_segment_message_destination_type(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -219,7 +221,7 @@ static void test_segment_message_destination_type(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_QUEUE, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -248,16 +250,16 @@ static void test_segment_message_message_action(void) { * destination_name */ - /* Test NR_SPAN_PRODUCER message action */ + /* Test NR_SPANKIND_PRODUCER message action */ test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ - .test_name = "Test NR_SPAN_PRODUCER message action", + .test_name = "Test NR_SPANKIND_PRODUCER message action", .name = "MessageBroker/SQS/Topic/Produce/Named/my_queue_or_topic", .txn_rollup_metric = "MessageBroker/all", .library_metric = "MessageBroker/SQS/all", @@ -270,17 +272,17 @@ static void test_segment_message_message_action(void) { .server_address = NULL, .aws_operation = NULL}); - /* Test NR_SPAN_CONSUMER message action */ + /* Test NR_SPANKIND_CONSUMER message action */ test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_CONSUMER, + .message_action = NR_SPANKIND_CONSUMER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ - .test_name = "Test NR_SPAN_CONSUMER message action", + .test_name = "Test NR_SPANKIND_CONSUMER message action", .name = "MessageBroker/SQS/Topic/Consume/Named/my_queue_or_topic", .txn_rollup_metric = "MessageBroker/all", .library_metric = "MessageBroker/SQS/all", @@ -294,18 +296,18 @@ static void test_segment_message_message_action(void) { .aws_operation = NULL}); /* - * Test NR_SPAN_CLIENT message action; this is not + * Test NR_SPANKIND_CLIENT message action; this is not * allowed for message segments, should show unknown. */ test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_CLIENT, + .message_action = NR_SPANKIND_CLIENT, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, (segment_message_expecteds_t){ - .test_name = "Test NR_SPAN_CLIENT message action", + .test_name = "Test NR_SPANKIND_CLIENT message action", .name = "MessageBroker/SQS/Topic//Named/my_queue_or_topic", .txn_rollup_metric = "MessageBroker/all", .library_metric = "MessageBroker/SQS/all", @@ -331,7 +333,7 @@ static void test_segment_message_library(void) { test_message_segment( &(nr_segment_message_params_t){ .library = NULL, - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -355,7 +357,7 @@ static void test_segment_message_library(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -379,7 +381,7 @@ static void test_segment_message_library(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_queue_or_topic"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -410,7 +412,7 @@ static void test_segment_message_destination_name(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = NULL}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -432,7 +434,7 @@ static void test_segment_message_destination_name(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = ""}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -454,7 +456,7 @@ static void test_segment_message_destination_name(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -483,7 +485,7 @@ static void test_segment_message_cloud_region(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -505,7 +507,7 @@ static void test_segment_message_cloud_region(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_region = ""}, @@ -528,7 +530,7 @@ static void test_segment_message_cloud_region(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_region = "wild-west-1"}, @@ -558,7 +560,7 @@ static void test_segment_message_cloud_account_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -580,7 +582,7 @@ static void test_segment_message_cloud_account_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_account_id = ""}, @@ -603,7 +605,7 @@ static void test_segment_message_cloud_account_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_account_id = "12345678"}, @@ -634,7 +636,7 @@ static void test_segment_message_messaging_system(void) { &(nr_segment_message_params_t){ .messaging_system = NULL, .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -657,7 +659,7 @@ static void test_segment_message_messaging_system(void) { &(nr_segment_message_params_t){ .messaging_system = "", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -680,7 +682,7 @@ static void test_segment_message_messaging_system(void) { &(nr_segment_message_params_t){ .messaging_system = "my_messaging_system", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -709,7 +711,7 @@ static void test_segment_message_cloud_resource_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -731,7 +733,7 @@ static void test_segment_message_cloud_resource_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_resource_id = ""}, @@ -754,7 +756,7 @@ static void test_segment_message_cloud_resource_id(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.cloud_resource_id = "my_resource_id"}, @@ -785,7 +787,7 @@ static void test_segment_message_server_address(void) { &(nr_segment_message_params_t){ .server_address = "localhost", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -808,7 +810,7 @@ static void test_segment_message_server_address(void) { &(nr_segment_message_params_t){ .server_address = "", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -831,7 +833,7 @@ static void test_segment_message_server_address(void) { &(nr_segment_message_params_t){ .server_address = "localhost", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -860,7 +862,7 @@ static void test_segment_message_aws_operation(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){0}, true /* enable attributes */, @@ -882,7 +884,7 @@ static void test_segment_message_aws_operation(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.aws_operation = ""}, @@ -905,7 +907,7 @@ static void test_segment_message_aws_operation(void) { test_message_segment( &(nr_segment_message_params_t){ .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage"}, @@ -936,7 +938,7 @@ static void test_segment_message_parameters_enabled(void) { .server_address = "localhost", .messaging_system = "my_system", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage", @@ -967,7 +969,7 @@ static void test_segment_message_parameters_enabled(void) { .server_address = "localhost", .messaging_system = "my_system", .library = "SQS", - .message_action = NR_SPAN_PRODUCER, + .message_action = NR_SPANKIND_PRODUCER, .destination_type = NR_MESSAGE_DESTINATION_TYPE_TOPIC, .destination_name = "my_destination"}, &(nr_segment_cloud_attrs_t){.aws_operation = "sendMessage", diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index 72ef4f4a2..5ee162da6 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -319,7 +319,7 @@ static void test_set_destroy_external_fields(void) { static void test_set_destroy_message_fields(void) { nr_segment_t s = {.type = NR_SEGMENT_MESSAGE}; - nr_segment_message_t m = {.message_action = NR_SPAN_CLIENT, + nr_segment_message_t m = {.message_action = NR_SPANKIND_CLIENT, .messaging_system = "my_messaging_system", .server_address = "localhost"}; @@ -382,9 +382,9 @@ static void test_destroy_typed_attributes(void) { s.typed_attributes->message.messaging_system = nr_strdup("aws_sqs"); s.typed_attributes->message.server_address = nr_strdup("localhost"); - /* - * Valgrind shall affirm that the attributes were cleaned up. - */ + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); /* @@ -398,9 +398,9 @@ static void test_destroy_typed_attributes(void) { s.typed_attributes->external.procedure = nr_strdup(test_string); s.typed_attributes->external.status = 200; - /* - * Valgrind shall affirm that the attributes were cleaned up. - */ + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); /* @@ -419,9 +419,9 @@ static void test_destroy_typed_attributes(void) { = nr_strdup(test_string); s.typed_attributes->datastore.instance.database_name = nr_strdup(test_string); - /* - * Valgrind shall affirm that the attributes were cleaned up. - */ + /* + * Valgrind shall affirm that the attributes were cleaned up. + */ nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); } diff --git a/axiom/tests/test_segment_traces.c b/axiom/tests/test_segment_traces.c index ac5db9642..b43e15b28 100644 --- a/axiom/tests/test_segment_traces.c +++ b/axiom/tests/test_segment_traces.c @@ -93,7 +93,8 @@ #define SPAN_EVENT_COMPARE_MESSAGE(span_event, expected_destination_name, \ expected_messaging_system, \ expected_server_address) \ - tlib_pass_if_str_equal("destination.name", expected_destination_name, \ + tlib_pass_if_str_equal("messaging.destination.name", \ + expected_destination_name, \ nr_span_event_get_message( \ span_event, NR_SPAN_MESSAGE_DESTINATION_NAME)); \ tlib_pass_if_str_equal("messaging.system", expected_messaging_system, \ diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index f3be09b0e..d92cceb3e 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -267,33 +267,40 @@ static void test_span_event_spankind(void) { nr_span_event_t* event = nr_span_event_create(); // Test : the default is NULL (spankind must be explicitly set) - tlib_pass_if_str_equal("The default category", NULL, + tlib_pass_if_str_equal("The default spankind is NULL", NULL, nr_span_event_get_spankind(event)); // Test : A null event returns NULL - tlib_pass_if_null("The default category", nr_span_event_get_spankind(NULL)); + tlib_pass_if_null("nr_span_event_get_spankind(NULL) returns NULL", + nr_span_event_get_spankind(NULL)); - // Test : passing a NULL event should not blow up - nr_span_event_set_spankind(NULL, NR_SPAN_PRODUCER); + // Test : passing a NULL event should not crash + nr_span_event_set_spankind(NULL, NR_SPANKIND_PRODUCER); + + // Test : invalid spankind + nr_span_event_set_spankind(event, 255); + tlib_pass_if_str_equal( + "Invalid spankind value doesn't crash and sets spankind to none (NULL)", + NULL, nr_span_event_get_spankind(event)); // Test : setting the spankind back and forth - nr_span_event_set_spankind(event, NR_SPAN_NO_SPANKIND); + nr_span_event_set_spankind(event, NR_SPANKIND_NO_SPANKIND); tlib_pass_if_str_equal( "Spankind should be the one we set - no spankind (NULL)", NULL, nr_span_event_get_spankind(event)); // Test : setting the spankind back and forth - nr_span_event_set_spankind(event, NR_SPAN_PRODUCER); + nr_span_event_set_spankind(event, NR_SPANKIND_PRODUCER); tlib_pass_if_str_equal("Spankind should be the one we set - producer", "producer", nr_span_event_get_spankind(event)); // Test : setting the spankind back and forth - nr_span_event_set_spankind(event, NR_SPAN_CLIENT); + nr_span_event_set_spankind(event, NR_SPANKIND_CLIENT); tlib_pass_if_str_equal("Spankind should be the one we set - client", "client", nr_span_event_get_spankind(event)); // Test : setting the spankind back and forth - nr_span_event_set_spankind(event, NR_SPAN_CONSUMER); + nr_span_event_set_spankind(event, NR_SPANKIND_CONSUMER); tlib_pass_if_str_equal("Spankind should be the one we set - consumer", "consumer", nr_span_event_get_spankind(event)); @@ -478,7 +485,7 @@ static void test_span_events_extern_get_and_set(void) { static void test_span_event_message_string_get_and_set(void) { nr_span_event_t* event = nr_span_event_create(); - // Test : that is does not blow up when we give the setter a NULL pointer + // Test : that is does not crash when we give the setter a NULL pointer nr_span_event_set_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME, "wallaby"); tlib_pass_if_null( "the destination name should still be NULL", @@ -488,12 +495,16 @@ static void test_span_event_message_string_get_and_set(void) { "given a NULL value we should get a NULL", nr_span_event_get_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME)); - // Test : the getter should not blow up when we send it an event with a NULL + // Test : the getter should not crash when we send it an event with a NULL // component tlib_pass_if_null( "NULL event -> NULL component", nr_span_event_get_message(NULL, NR_SPAN_MESSAGE_DESTINATION_NAME)); + // Test : send getter invalid range + tlib_pass_if_null("invalid range sent to nr_span_event_get_message", + nr_span_event_get_message(event, 54321)); + // Test : setting the destination name back and forth behaves as expected nr_span_event_set_message(event, NR_SPAN_MESSAGE_DESTINATION_NAME, "chicken"); tlib_pass_if_str_equal( From 925b94caf9fb5ce2999efcf57af0572f9a7938a0 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Thu, 9 Jan 2025 14:11:01 -0700 Subject: [PATCH 61/63] fix(axiom): comment update --- axiom/nr_segment_message.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axiom/nr_segment_message.h b/axiom/nr_segment_message.h index b9f0d7ac0..2104e3f35 100644 --- a/axiom/nr_segment_message.h +++ b/axiom/nr_segment_message.h @@ -23,7 +23,7 @@ typedef enum _nr_segment_message_destination_type_t { } nr_segment_message_destination_type_t; typedef struct { - /* All strings are null-terminated. When unset, the strings are ingored. */ + /* All strings are null-terminated. When NULL/empty the values are ingored. */ /* Only used for creating metrics. */ char* library; /* Library; Possible values are SQS, SNS, RabbitMQ, JMS */ From 4f91a63f1a1220ef144733f0abc4ed0dad9328c4 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Fri, 10 Jan 2025 07:40:37 -0700 Subject: [PATCH 62/63] chore(axiom): Comment update --- axiom/tests/test_span_event.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/axiom/tests/test_span_event.c b/axiom/tests/test_span_event.c index d92cceb3e..ff44ab1cd 100644 --- a/axiom/tests/test_span_event.c +++ b/axiom/tests/test_span_event.c @@ -267,8 +267,9 @@ static void test_span_event_spankind(void) { nr_span_event_t* event = nr_span_event_create(); // Test : the default is NULL (spankind must be explicitly set) - tlib_pass_if_str_equal("The default spankind is NULL", NULL, - nr_span_event_get_spankind(event)); + tlib_pass_if_str_equal( + "When not explicitly set, The default spankind is NULL", NULL, + nr_span_event_get_spankind(event)); // Test : A null event returns NULL tlib_pass_if_null("nr_span_event_get_spankind(NULL) returns NULL", From 0670292ebb5d1562c4e7f43518bdeaf59e8a8186 Mon Sep 17 00:00:00 2001 From: Amber Sistla Date: Fri, 10 Jan 2025 09:04:45 -0700 Subject: [PATCH 63/63] test(axiom): Ensure typed_attributes is NULL after destruction --- axiom/tests/test_segment_private.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/axiom/tests/test_segment_private.c b/axiom/tests/test_segment_private.c index 5ee162da6..82e0dfd80 100644 --- a/axiom/tests/test_segment_private.c +++ b/axiom/tests/test_segment_private.c @@ -367,11 +367,23 @@ static void test_destroy_typed_attributes(void) { */ nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, NULL); nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); + tlib_pass_if_null( + "Even with bad parameters, nr_segment_destroy_typed_attributes should " + "not crash and s.typed_attributes should be NULL", + s.typed_attributes); nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, NULL); nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); + tlib_pass_if_null( + "Even with bad parameters, nr_segment_destroy_typed_attributes should " + "not crash and s.typed_attributes should be NULL", + s.typed_attributes); nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, NULL); nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); + tlib_pass_if_null( + "Even with bad parameters, nr_segment_destroy_typed_attributes should " + "not crash and s.typed_attributes should be NULL", + s.typed_attributes); /* * Test : Clean up typed attributes for a message segment @@ -386,7 +398,10 @@ static void test_destroy_typed_attributes(void) { * Valgrind shall affirm that the attributes were cleaned up. */ nr_segment_destroy_typed_attributes(NR_SEGMENT_MESSAGE, &s.typed_attributes); - + tlib_pass_if_null( + "After nr_segment_destroy_typed_attributes, s.typed_attributes should be " + "NULL", + s.typed_attributes); /* * Test : Clean up typed attributes for an external segment */ @@ -402,6 +417,10 @@ static void test_destroy_typed_attributes(void) { * Valgrind shall affirm that the attributes were cleaned up. */ nr_segment_destroy_typed_attributes(NR_SEGMENT_EXTERNAL, &s.typed_attributes); + tlib_pass_if_null( + "After nr_segment_destroy_typed_attributes, s.typed_attributes should be " + "NULL", + s.typed_attributes); /* * Test : Clean up typed attributes for a datastore segment @@ -424,6 +443,10 @@ static void test_destroy_typed_attributes(void) { */ nr_segment_destroy_typed_attributes(NR_SEGMENT_DATASTORE, &s.typed_attributes); + tlib_pass_if_null( + "After nr_segment_destroy_typed_attributes, s.typed_attributes should be " + "NULL", + s.typed_attributes); } static void test_destroy_fields(void) {