|
14 | 14 | #include "request_abort.h"
|
15 | 15 | #include "tags.h"
|
16 | 16 | #include <ext/standard/base64.h>
|
| 17 | +#include <mpack.h> |
| 18 | +#include <stdatomic.h> |
17 | 19 |
|
18 | 20 | typedef struct _dd_omsg {
|
19 | 21 | zend_llist iovecs;
|
@@ -437,7 +439,71 @@ static void _command_process_stack_trace_parameters(mpack_node_t root)
|
437 | 439 | }
|
438 | 440 | }
|
439 | 441 |
|
440 |
| -dd_result _command_process_actions(mpack_node_t root, struct req_info *ctx) |
| 442 | +static dd_result _command_process_actions( |
| 443 | + mpack_node_t root, struct req_info *ctx); |
| 444 | + |
| 445 | +/* |
| 446 | + * array( |
| 447 | + * 0: [<"ok" / "record" / "block" / "redirect">, |
| 448 | + * [if block/redirect parameters: (map)]] |
| 449 | + * 1: [if block/redirect/record: appsec span data (array of strings: json |
| 450 | + * fragments)], |
| 451 | + * 2: [force keep: bool] |
| 452 | + * 3: [meta: map] |
| 453 | + * 4: [metrics: map] |
| 454 | + * 5: [telemetry metrics: map string -> |
| 455 | + * array(array(value: double, tags: string)]) |
| 456 | + * ) |
| 457 | + */ |
| 458 | +#define RESP_INDEX_ACTION_PARAMS 0 |
| 459 | +#define RESP_INDEX_APPSEC_SPAN_DATA 1 |
| 460 | +#define RESP_INDEX_FORCE_KEEP 2 |
| 461 | +#define RESP_INDEX_SPAN_META 3 |
| 462 | +#define RESP_INDEX_SPAN_METRICS 4 |
| 463 | +#define RESP_INDEX_TELEMETRY_METRICS 5 |
| 464 | + |
| 465 | +dd_result dd_command_proc_resp_verd_span_data( |
| 466 | + mpack_node_t root, void *unspecnull _ctx) |
| 467 | +{ |
| 468 | + struct req_info *ctx = _ctx; |
| 469 | + assert(ctx != NULL); |
| 470 | + |
| 471 | + mpack_node_t actions = mpack_node_array_at(root, RESP_INDEX_ACTION_PARAMS); |
| 472 | + dd_result res = _command_process_actions(actions, ctx); |
| 473 | + |
| 474 | + if (res == dd_should_block || res == dd_should_redirect || |
| 475 | + res == dd_should_record) { |
| 476 | + _set_appsec_span_data( |
| 477 | + mpack_node_array_at(root, RESP_INDEX_APPSEC_SPAN_DATA)); |
| 478 | + } |
| 479 | + |
| 480 | + mpack_node_t force_keep = mpack_node_array_at(root, RESP_INDEX_FORCE_KEEP); |
| 481 | + if (mpack_node_type(force_keep) == mpack_type_bool && |
| 482 | + mpack_node_bool(force_keep)) { |
| 483 | + dd_tags_set_sampling_priority(); |
| 484 | + } |
| 485 | + |
| 486 | + if (mpack_node_array_length(root) >= RESP_INDEX_SPAN_METRICS + 1 && |
| 487 | + ctx->root_span) { |
| 488 | + zend_object *span = ctx->root_span; |
| 489 | + |
| 490 | + mpack_node_t meta = mpack_node_array_at(root, RESP_INDEX_SPAN_META); |
| 491 | + dd_command_process_meta(meta, span); |
| 492 | + mpack_node_t metrics = |
| 493 | + mpack_node_array_at(root, RESP_INDEX_SPAN_METRICS); |
| 494 | + dd_command_process_metrics(metrics, span); |
| 495 | + } |
| 496 | + |
| 497 | + if (mpack_node_array_length(root) >= RESP_INDEX_TELEMETRY_METRICS + 1) { |
| 498 | + dd_command_process_telemetry_metrics( |
| 499 | + mpack_node_array_at(root, RESP_INDEX_TELEMETRY_METRICS)); |
| 500 | + } |
| 501 | + |
| 502 | + return res; |
| 503 | +} |
| 504 | + |
| 505 | +static dd_result _command_process_actions( |
| 506 | + mpack_node_t root, struct req_info *ctx) |
441 | 507 | {
|
442 | 508 | size_t actions = mpack_node_array_length(root);
|
443 | 509 | dd_result res = dd_success;
|
@@ -482,42 +548,6 @@ dd_result _command_process_actions(mpack_node_t root, struct req_info *ctx)
|
482 | 548 | return res;
|
483 | 549 | }
|
484 | 550 |
|
485 |
| -dd_result dd_command_proc_resp_verd_span_data( |
486 |
| - mpack_node_t root, void *unspecnull _ctx) |
487 |
| -{ |
488 |
| - struct req_info *ctx = _ctx; |
489 |
| - assert(ctx != NULL); |
490 |
| - |
491 |
| - mpack_node_t actions = mpack_node_array_at(root, 0); |
492 |
| - |
493 |
| - dd_result res = _command_process_actions(actions, ctx); |
494 |
| - |
495 |
| - if (res == dd_should_block || res == dd_should_redirect || |
496 |
| - res == dd_should_record) { |
497 |
| - _set_appsec_span_data(mpack_node_array_at(root, 1)); |
498 |
| - } |
499 |
| - |
500 |
| - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) |
501 |
| - mpack_node_t force_keep = mpack_node_array_at(root, 2); |
502 |
| - if (mpack_node_type(force_keep) == mpack_type_bool && |
503 |
| - mpack_node_bool(force_keep)) { |
504 |
| - dd_tags_set_sampling_priority(); |
505 |
| - } |
506 |
| - |
507 |
| - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) |
508 |
| - if (mpack_node_array_length(root) >= 5 && ctx->root_span) { |
509 |
| - zend_object *span = ctx->root_span; |
510 |
| - |
511 |
| - mpack_node_t meta = mpack_node_array_at(root, 3); |
512 |
| - dd_command_process_meta(meta, span); |
513 |
| - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) |
514 |
| - mpack_node_t metrics = mpack_node_array_at(root, 4); |
515 |
| - dd_command_process_metrics(metrics, span); |
516 |
| - } |
517 |
| - |
518 |
| - return res; |
519 |
| -} |
520 |
| - |
521 | 551 | static void _add_appsec_span_data_frag(mpack_node_t node)
|
522 | 552 | {
|
523 | 553 | const char *data = mpack_node_data(node);
|
@@ -648,6 +678,104 @@ bool dd_command_process_metrics(mpack_node_t root, zend_object *nonnull span)
|
648 | 678 | return true;
|
649 | 679 | }
|
650 | 680 |
|
| 681 | +static void _handle_telemetry_metric(const char *nonnull key_str, |
| 682 | + size_t key_len, double value, const char *nonnull tags_str, |
| 683 | + size_t tags_len); |
| 684 | + |
| 685 | +bool dd_command_process_telemetry_metrics(mpack_node_t metrics) |
| 686 | +{ |
| 687 | + if (mpack_node_type(metrics) != mpack_type_map) { |
| 688 | + return false; |
| 689 | + } |
| 690 | + |
| 691 | + if (!ddtrace_metric_register_buffer) { |
| 692 | + mlog_g(dd_log_debug, "ddtrace_metric_register_buffer unavailable"); |
| 693 | + return true; |
| 694 | + } |
| 695 | + |
| 696 | + for (size_t i = 0; i < mpack_node_map_count(metrics); i++) { |
| 697 | + mpack_node_t key = mpack_node_map_key_at(metrics, i); |
| 698 | + |
| 699 | + const char *key_str = mpack_node_str(key); |
| 700 | + if (!key_str) { |
| 701 | + continue; |
| 702 | + } |
| 703 | + |
| 704 | + size_t key_len = mpack_node_strlen(key); |
| 705 | + mpack_node_t arr_value = mpack_node_map_value_at(metrics, i); |
| 706 | + |
| 707 | + for (size_t j = 0; j < mpack_node_array_length(arr_value); j++) { |
| 708 | + mpack_node_t value = mpack_node_array_at(arr_value, j); |
| 709 | + mpack_node_t dval_node = mpack_node_array_at(value, 0); |
| 710 | + double dval = mpack_node_double(dval_node); |
| 711 | + |
| 712 | + const char *tags_str = ""; |
| 713 | + size_t tags_len = 0; |
| 714 | + if (mpack_node_array_length(value) >= 2) { |
| 715 | + mpack_node_t tags = mpack_node_array_at(value, 1); |
| 716 | + tags_str = mpack_node_str(tags); |
| 717 | + tags_len = mpack_node_strlen(tags); |
| 718 | + } |
| 719 | + if (mpack_node_error(metrics) != mpack_ok) { |
| 720 | + break; |
| 721 | + } |
| 722 | + |
| 723 | + _handle_telemetry_metric( |
| 724 | + key_str, key_len, dval, tags_str, tags_len); |
| 725 | + } |
| 726 | + } |
| 727 | + |
| 728 | + return true; |
| 729 | +} |
| 730 | + |
| 731 | +static void _init_zstr( |
| 732 | + zend_string *_Atomic *nonnull zstr, const char *nonnull str, size_t len) |
| 733 | +{ |
| 734 | + zend_string *zstr_cur = atomic_load_explicit(zstr, memory_order_acquire); |
| 735 | + if (zstr_cur != NULL) { |
| 736 | + return; |
| 737 | + } |
| 738 | + zend_string *zstr_new = zend_string_init(str, len, 1); |
| 739 | + if (atomic_compare_exchange_strong_explicit(zstr, &(zend_string *){NULL}, |
| 740 | + zstr_new, memory_order_release, memory_order_relaxed)) { |
| 741 | + return; |
| 742 | + } |
| 743 | + zend_string_release(zstr_new); |
| 744 | +} |
| 745 | + |
| 746 | +// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) |
| 747 | +void _handle_telemetry_metric(const char *nonnull key_str, size_t key_len, |
| 748 | + double value, const char *nonnull tags_str, size_t tags_len) |
| 749 | +{ |
| 750 | +#define HANDLE_METRIC(name, type) \ |
| 751 | + do { \ |
| 752 | + if (key_len == sizeof(name "") - 1 && \ |
| 753 | + memcmp(key_str, name, key_len) == 0) { \ |
| 754 | + static zend_string *_Atomic key_zstr; \ |
| 755 | + _init_zstr(&key_zstr, name, sizeof(name) - 1); \ |
| 756 | + zend_string *tags_zstr = zend_string_init(tags_str, tags_len, 1); \ |
| 757 | + ddtrace_metric_register_buffer( \ |
| 758 | + key_zstr, type, DDTRACE_METRIC_NAMESPACE_APPSEC); \ |
| 759 | + ddtrace_metric_add_point(key_zstr, value, tags_zstr); \ |
| 760 | + zend_string_release(tags_zstr); \ |
| 761 | + mlog_g(dd_log_debug, \ |
| 762 | + "Telemetry metric %.*s added with tags %.*s and value %f", \ |
| 763 | + (int)key_len, key_str, (int)tags_len, tags_str, value); \ |
| 764 | + return; \ |
| 765 | + } \ |
| 766 | + } while (0) |
| 767 | + |
| 768 | + HANDLE_METRIC("waf.requests", DDTRACE_METRIC_TYPE_COUNT); |
| 769 | + HANDLE_METRIC("waf.updates", DDTRACE_METRIC_TYPE_COUNT); |
| 770 | + HANDLE_METRIC("waf.init", DDTRACE_METRIC_TYPE_COUNT); |
| 771 | + HANDLE_METRIC("waf.config_errors", DDTRACE_METRIC_TYPE_COUNT); |
| 772 | + |
| 773 | + HANDLE_METRIC("remote_config.first_pull", DDTRACE_METRIC_TYPE_GAUGE); |
| 774 | + HANDLE_METRIC("remote_config.last_success", DDTRACE_METRIC_TYPE_GAUGE); |
| 775 | + |
| 776 | + mlog_g(dd_log_info, "Unknown telemetry metric %.*s", (int)key_len, key_str); |
| 777 | +} |
| 778 | + |
651 | 779 | static void _dump_in_msg(
|
652 | 780 | dd_log_level_t lvl, const char *nonnull data, size_t data_len)
|
653 | 781 | {
|
|
0 commit comments