diff --git a/src/datadog/telemetry/telemetry_impl.cpp b/src/datadog/telemetry/telemetry_impl.cpp index b76738f76..33159ea33 100644 --- a/src/datadog/telemetry/telemetry_impl.cpp +++ b/src/datadog/telemetry/telemetry_impl.cpp @@ -617,27 +617,24 @@ std::string Telemetry::app_started_payload() { /// is no need to declare it. if (product.name == Product::Name::tracing) continue; - auto p = nlohmann::json{ - {to_string(product.name), - nlohmann::json{ - {"version", product.version}, - {"enabled", product.enabled}, - }}, + auto product_details = nlohmann::json{ + {"version", product.version}, + {"enabled", product.enabled}, }; if (product.error_code || product.error_message) { - auto p_error = nlohmann::json{}; + auto product_error = nlohmann::json{}; if (product.error_code) { - p_error.emplace("code", *product.error_code); + product_error.emplace("code", *product.error_code); } if (product.error_message) { - p_error.emplace("message", *product.error_message); + product_error.emplace("message", *product.error_message); } - p.emplace("error", std::move(p_error)); + product_details.emplace("error", std::move(product_error)); } - product_json.emplace(std::move(p)); + product_json.emplace(to_string(product.name), std::move(product_details)); } auto app_started_msg = nlohmann::json{ diff --git a/src/datadog/tracer_config.cpp b/src/datadog/tracer_config.cpp index 4fe4f2fc6..a746bbe38 100644 --- a/src/datadog/tracer_config.cpp +++ b/src/datadog/tracer_config.cpp @@ -472,6 +472,21 @@ Expected finalize_config(const TracerConfig &user_config, final_config.telemetry.products.emplace_back(telemetry::Product{ telemetry::Product::Name::tracing, true, tracer_version, nullopt, nullopt, final_config.metadata}); + + const bool has_appsec_product = std::any_of( + final_config.telemetry.products.begin(), + final_config.telemetry.products.end(), [](const auto &product) { + return product.name == telemetry::Product::Name::appsec; + }); + if (!has_appsec_product) { + final_config.telemetry.products.emplace_back( + telemetry::Product{telemetry::Product::Name::appsec, + false, + tracer_version, + nullopt, + nullopt, + {}}); + } } else { return std::move(telemetry_final_config.error()); } diff --git a/test/telemetry/test_telemetry.cpp b/test/telemetry/test_telemetry.cpp index 9119892c7..d8c9fed31 100644 --- a/test/telemetry/test_telemetry.cpp +++ b/test/telemetry/test_telemetry.cpp @@ -329,6 +329,33 @@ TELEMETRY_IMPLEMENTATION_TEST("Tracer telemetry lifecycle") { } } } + + SECTION("With AppSec product state") { + client->clear(); + + Configuration cfg; + cfg.products.emplace_back(Product{Product::Name::appsec, + false, + "1.2.3", + 12, + "Error initializing WAF", + {}}); + + auto telemetry = + Telemetry::create(*finalize_config(cfg), tracer_signature, logger, + client, scheduler, *url); + + const auto message_batch = nlohmann::json::parse(client->request_body); + const auto& appsec = + message_batch["payload"][0]["payload"]["products"]["appsec"]; + + CHECK(appsec == + nlohmann::json{ + {"version", "1.2.3"}, + {"enabled", false}, + {"error", + {{"code", 12}, {"message", "Error initializing WAF"}}}}); + } } SECTION("dtor send app-closing message") { diff --git a/test/test_tracer_config.cpp b/test/test_tracer_config.cpp index f23f88935..136722fe2 100644 --- a/test/test_tracer_config.cpp +++ b/test/test_tracer_config.cpp @@ -1626,6 +1626,52 @@ TRACER_CONFIG_TEST("telemetry products contain configuration precedence") { } } +TRACER_CONFIG_TEST("telemetry includes AppSec product state") { + SECTION("AppSec defaults to disabled") { + auto finalized = finalize_config(TracerConfig{}); + REQUIRE(finalized); + + const datadog::telemetry::Product* appsec = nullptr; + for (const auto& product : finalized->telemetry.products) { + if (product.name == datadog::telemetry::Product::Name::appsec) { + appsec = &product; + break; + } + } + + REQUIRE(appsec != nullptr); + CHECK(appsec->enabled == false); + CHECK(appsec->version == tracer_version); + CHECK(appsec->error_code == nullopt); + CHECK(appsec->error_message == nullopt); + } + + SECTION("caller-provided AppSec state is preserved") { + TracerConfig config; + config.telemetry.products.emplace_back( + datadog::telemetry::Product{datadog::telemetry::Product::Name::appsec, + true, + "1.2.3", + nullopt, + nullopt, + {}}); + + auto finalized = finalize_config(config); + REQUIRE(finalized); + + std::size_t appsec_count = 0; + for (const auto& product : finalized->telemetry.products) { + if (product.name != datadog::telemetry::Product::Name::appsec) continue; + + ++appsec_count; + CHECK(product.enabled == true); + CHECK(product.version == "1.2.3"); + } + + CHECK(appsec_count == 1); + } +} + TRACER_CONFIG_TEST("Tracer construction publishes tracer info file") { #ifndef __linux__ SUCCEED("In-memory tracer info file is Linux-only");