From 5869a12307680b55cc32077a5641c1bf4789df72 Mon Sep 17 00:00:00 2001 From: Alejandro Estringana Ruiz Date: Mon, 17 Jun 2024 11:48:12 +0200 Subject: [PATCH] Add span field meta_struct (#2673) Add new field meta_struct to the span. This new field is a map where its values are encoded to msgpack and then the resulting codification to msgpack binary --- ext/ddtrace.c | 1 + ext/ddtrace.stub.php | 7 ++++ ext/ddtrace_arginfo.h | 8 +++- ext/serializer.c | 68 ++++++++++++++++++++++++++++++- ext/span.h | 1 + tests/ext/active_span.phpt | 5 ++- tests/ext/meta_struct.phpt | 33 +++++++++++++++ tests/ext/sandbox/span_clone.phpt | 15 +++++-- 8 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 tests/ext/meta_struct.phpt diff --git a/ext/ddtrace.c b/ext/ddtrace.c index 254c2a3804..4c89e3cc0c 100644 --- a/ext/ddtrace.c +++ b/ext/ddtrace.c @@ -708,6 +708,7 @@ static zend_object *dd_init_span_data_object(zend_class_entry *class_type, ddtra // Not handled in arginfo on these old versions array_init(&span->property_meta); array_init(&span->property_metrics); + array_init(&span->property_meta_struct); array_init(&span->property_links); array_init(&span->property_peer_service_sources); #endif diff --git a/ext/ddtrace.stub.php b/ext/ddtrace.stub.php index 017dbbcacc..b03d25973e 100644 --- a/ext/ddtrace.stub.php +++ b/ext/ddtrace.stub.php @@ -94,6 +94,13 @@ class SpanData { */ public string $version = ""; + /** + * @var string[] Meta struct can be used to send any data to the backend. The peculiarity of meta struct is + * that the values are encoded with msgpack when sent to the agent. The values are first encoded to msgpack + * and then, encoded again with msgpack to binary + */ + public array $meta_struct = []; + /** * @var string|null The type of request which can be set to: web, db, cache, or custom (Optional). Inherited * from parent. diff --git a/ext/ddtrace_arginfo.h b/ext/ddtrace_arginfo.h index 98b588e7aa..110af1c4e2 100644 --- a/ext/ddtrace_arginfo.h +++ b/ext/ddtrace_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 190a99779c21033f0812df6365a7ebdd87057727 */ + * Stub hash: a92829eefe1ee642b3357f1eef2900f1336e462f */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_trace_method, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, className, IS_STRING, 0) @@ -565,6 +565,12 @@ static zend_class_entry *register_class_DDTrace_SpanData(void) zend_declare_typed_property(class_entry, property_version_name, &property_version_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_version_name); + zval property_meta_struct_default_value; + ZVAL_EMPTY_ARRAY(&property_meta_struct_default_value); + zend_string *property_meta_struct_name = zend_string_init("meta_struct", sizeof("meta_struct") - 1, 1); + zend_declare_typed_property(class_entry, property_meta_struct_name, &property_meta_struct_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_meta_struct_name); + zval property_type_default_value; ZVAL_EMPTY_STRING(&property_type_default_value); zend_string *property_type_name = zend_string_init("type", sizeof("type") - 1, 1); diff --git a/ext/serializer.c b/ext/serializer.c index e10b774385..44171a08d6 100644 --- a/ext/serializer.c +++ b/ext/serializer.c @@ -63,8 +63,10 @@ static void mpack_write_utf8_lossy_cstr(mpack_writer_t *writer, const char *str, #define KEY_TRACE_ID "trace_id" #define KEY_SPAN_ID "span_id" #define KEY_PARENT_ID "parent_id" +#define KEY_META_STRUCT "meta_struct" static int msgpack_write_zval(mpack_writer_t *writer, zval *trace, int level); +static void serialize_meta_struct(mpack_writer_t *writer, zval *trace); static int write_hash_table(mpack_writer_t *writer, HashTable *ht, int level) { zval *tmp; @@ -89,6 +91,7 @@ static int write_hash_table(mpack_writer_t *writer, HashTable *ht, int level) { ZEND_HASH_FOREACH_KEY_VAL_IND(ht, num_key, string_key, tmp) { // Writing the key, if associative bool zval_string_as_uint64 = false; + bool is_meta_struct = false; if (is_assoc == 1) { char num_str_buf[MAX_ID_BUFSIZ], *key; size_t len; @@ -105,11 +108,17 @@ static int write_hash_table(mpack_writer_t *writer, HashTable *ht, int level) { (0 == strcmp(KEY_TRACE_ID, key) || 0 == strcmp(KEY_SPAN_ID, key) || 0 == strcmp(KEY_PARENT_ID, key))) { zval_string_as_uint64 = true; } + if (level <= 3 && + (0 == strcmp(KEY_META_STRUCT, key))) { + is_meta_struct = true; + } } // Writing the value if (zval_string_as_uint64) { mpack_write_u64(writer, strtoull(Z_STRVAL_P(tmp), NULL, 10)); + } else if(is_meta_struct) { + serialize_meta_struct(writer, tmp); } else if (msgpack_write_zval(writer, tmp, level) != 1) { return 0; } @@ -128,7 +137,6 @@ static int msgpack_write_zval(mpack_writer_t *writer, zval *trace, int level) { if (Z_TYPE_P(trace) == IS_REFERENCE) { trace = Z_REFVAL_P(trace); } - switch (Z_TYPE_P(trace)) { case IS_ARRAY: if (write_hash_table(writer, Z_ARRVAL_P(trace), level + 1) != 1) { @@ -159,6 +167,26 @@ static int msgpack_write_zval(mpack_writer_t *writer, zval *trace, int level) { return 1; } +static void serialize_meta_struct(mpack_writer_t *writer, zval *meta_struct) { + zval *tmp; + zend_string *string_key; + + HashTable *ht = Z_ARRVAL_P(meta_struct); + + mpack_start_map(writer, zend_hash_num_elements(ht)); + + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(ht, string_key, tmp) { + if (!string_key) { + continue; + } + mpack_write_cstr(writer, ZSTR_VAL(string_key)); + mpack_write_bin(writer, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + } + ZEND_HASH_FOREACH_END(); + + mpack_finish_map(writer); +} + int ddtrace_serialize_simple_array_into_c_string(zval *trace, char **data_p, size_t *size_p) { // encode to memory buffer char *data; @@ -1017,6 +1045,26 @@ static void dd_serialize_array_metrics_recursively(zend_array *target, zend_stri dd_serialize_array_recursively(target, str, value, true); } +static void dd_serialize_array_meta_struct_recursively(zend_array *target, zend_string *str, zval *value) { + char *data; + size_t size; + + mpack_writer_t writer; + mpack_writer_init_growable(&writer, &data, &size); + int result = msgpack_write_zval(&writer, value, 5); + mpack_writer_destroy(&writer); + + if (size == 0 || result == 0) { + return; + } + + zval serialised; + ZVAL_STRINGL(&serialised, data, size); + + zend_hash_update(target, str, &serialised); + free(data); +} + struct iter { // caller owns key/value bool (*next)(struct iter *self, zend_string **key, zend_string **value); @@ -1426,7 +1474,6 @@ static zend_always_inline double strconv_parse_bool(zend_string *str) { void ddtrace_serialize_span_to_array(ddtrace_span_data *span, zval *array) { bool is_root_span = span->std.ce == ddtrace_ce_root_span_data; - zval *el; zval zv; el = &zv; @@ -1794,6 +1841,23 @@ void ddtrace_serialize_span_to_array(ddtrace_span_data *span, zval *array) { zend_array_destroy(Z_ARR(metrics_zv)); } + zend_array *meta_struct = ddtrace_property_array(&span->property_meta_struct); + zval meta_struct_zv; + array_init(&meta_struct_zv); + zend_string *ms_str_key; + zval *ms_val; + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(meta_struct, ms_str_key, ms_val) { + if (ms_str_key) { + dd_serialize_array_meta_struct_recursively(Z_ARRVAL(meta_struct_zv), ms_str_key, ms_val); + } + } + ZEND_HASH_FOREACH_END(); + if (zend_hash_num_elements(Z_ARR(meta_struct_zv))) { + zend_hash_str_add_new(Z_ARR_P(el), ZEND_STRL("meta_struct"), &meta_struct_zv); + } else { + zend_array_destroy(Z_ARR(meta_struct_zv)); + } + add_next_index_zval(array, el); } diff --git a/ext/span.h b/ext/span.h index 4391d9733a..dd236985b4 100644 --- a/ext/span.h +++ b/ext/span.h @@ -45,6 +45,7 @@ typedef union ddtrace_span_properties { zval property_service; zval property_env; zval property_version; + zval property_meta_struct; zval property_type; zval property_meta; zval property_metrics; diff --git a/tests/ext/active_span.phpt b/tests/ext/active_span.phpt index edbd2537e3..56b4911b40 100644 --- a/tests/ext/active_span.phpt +++ b/tests/ext/active_span.phpt @@ -28,7 +28,7 @@ var_dump(DDTrace\active_span() == DDTrace\active_span()); Hello, Datadog. greet tracer. bool(true) -object(DDTrace\RootSpanData)#%d (18) { +object(DDTrace\RootSpanData)#%d (19) { ["name"]=> string(15) "active_span.php" ["resource"]=> @@ -39,6 +39,9 @@ object(DDTrace\RootSpanData)#%d (18) { string(0) "" ["version"]=> string(0) "" + ["meta_struct"]=> + array(0) { + } ["type"]=> string(3) "cli" ["meta"]=> diff --git a/tests/ext/meta_struct.phpt b/tests/ext/meta_struct.phpt new file mode 100644 index 0000000000..fc541516e6 --- /dev/null +++ b/tests/ext/meta_struct.phpt @@ -0,0 +1,33 @@ +--TEST-- +Add meta struct string +--FILE-- + $value) { + $hex = []; + $length = strlen($value); + for ($i = 0; $i < $length; $i++) { + $hex[] = bin2hex($value[$i]); + } + var_dump($key, implode(' ', $hex)); + } +} + +$span = DDTrace\start_span(); +$span->meta_struct["foo"] = "bar"; +$span->meta_struct["john"] = ["Doe"]; +DDTrace\close_span(); + +$spans = dd_trace_serialize_closed_spans(); + +foreach ($spans as $span) +{ + dd_trace_unserialize_trace_hex($span["meta_struct"]); +} + +?> +--EXPECTF-- +string(3) "foo" +string(11) "a3 62 61 72" +string(4) "john" +string(14) "91 a3 44 6f 65" diff --git a/tests/ext/sandbox/span_clone.phpt b/tests/ext/sandbox/span_clone.phpt index 38eb594cc7..4ffed7a2ad 100644 --- a/tests/ext/sandbox/span_clone.phpt +++ b/tests/ext/sandbox/span_clone.phpt @@ -24,7 +24,7 @@ var_dump(dd_trace_serialize_closed_spans()); ?> --EXPECTF-- -object(DDTrace\RootSpanData)#%d (18) { +object(DDTrace\RootSpanData)#%d (19) { ["name"]=> string(3) "foo" ["resource"]=> @@ -35,6 +35,9 @@ object(DDTrace\RootSpanData)#%d (18) { string(0) "" ["version"]=> string(0) "" + ["meta_struct"]=> + array(0) { + } ["type"]=> string(3) "cli" ["meta"]=> @@ -82,7 +85,7 @@ object(DDTrace\RootSpanData)#%d (18) { ["traceId"]=> string(32) "%s" } -object(DDTrace\RootSpanData)#%d (18) { +object(DDTrace\RootSpanData)#%d (19) { ["name"]=> string(5) "dummy" ["resource"]=> @@ -93,6 +96,9 @@ object(DDTrace\RootSpanData)#%d (18) { string(0) "" ["version"]=> string(0) "" + ["meta_struct"]=> + array(0) { + } ["type"]=> string(3) "cli" ["meta"]=> @@ -127,7 +133,7 @@ object(DDTrace\RootSpanData)#%d (18) { NULL } ["active"]=> - object(DDTrace\RootSpanData)#%d (18) { + object(DDTrace\RootSpanData)#%d (19) { ["name"]=> string(3) "foo" ["resource"]=> @@ -138,6 +144,9 @@ object(DDTrace\RootSpanData)#%d (18) { string(0) "" ["version"]=> string(0) "" + ["meta_struct"]=> + array(0) { + } ["type"]=> string(3) "cli" ["meta"]=>