1+ #include " query_farm_telemetry.hpp"
2+ #include < thread>
3+ #include " duckdb.hpp"
4+ #include " duckdb/common/http_util.hpp"
5+ #include " yyjson.hpp"
6+ #include " duckdb/main/extension_helper.hpp"
7+ #include " duckdb/main/config.hpp"
8+ #include < cstdlib>
9+ #include < future>
10+ using namespace duckdb_yyjson ; // NOLINT
11+
12+ namespace duckdb
13+ {
14+
15+ namespace
16+ {
17+
18+ // Function to send the actual HTTP request
19+ void sendHTTPRequest (shared_ptr<DatabaseInstance> db, char *json_body, size_t json_body_size)
20+ {
21+ const string TARGET_URL (" https://duckdb-in.query-farm.services/" );
22+
23+ HTTPHeaders headers;
24+ headers.Insert (" Content-Type" , " application/json" );
25+
26+ auto &http_util = HTTPUtil::Get (*db);
27+ unique_ptr<HTTPParams> params = http_util.InitializeParameters (*db, TARGET_URL);
28+
29+ PostRequestInfo post_request (TARGET_URL, headers, *params, reinterpret_cast <const_data_ptr_t >(json_body),
30+ json_body_size);
31+ try
32+ {
33+ auto response = http_util.Request (post_request);
34+ }
35+ catch (const std::exception &e)
36+ {
37+ // ignore all errors.
38+ }
39+
40+ free (json_body);
41+ return ;
42+ }
43+
44+ } // namespace
45+
46+ INTERNAL_FUNC void QueryFarmSendTelemetry (ExtensionLoader &loader, const string &extension_name,
47+ const string &extension_version)
48+ {
49+ const char *opt_out = std::getenv (" QUERY_FARM_TELEMETRY_OPT_OUT" );
50+ if (opt_out != nullptr )
51+ {
52+ return ;
53+ }
54+
55+ auto &dbconfig = DBConfig::GetConfig (loader.GetDatabaseInstance ());
56+ auto old_value = dbconfig.options .autoinstall_known_extensions ;
57+ dbconfig.options .autoinstall_known_extensions = false ;
58+ try
59+ {
60+ ExtensionHelper::AutoLoadExtension (loader.GetDatabaseInstance (), " httpfs" );
61+ }
62+ catch (...)
63+ {
64+ dbconfig.options .autoinstall_known_extensions = old_value;
65+ return ;
66+ }
67+
68+ dbconfig.options .autoinstall_known_extensions = old_value;
69+ if (!loader.GetDatabaseInstance ().ExtensionIsLoaded (" httpfs" ))
70+ {
71+ return ;
72+ }
73+
74+ // Initialize the telemetry sender
75+ auto doc = yyjson_mut_doc_new (nullptr );
76+
77+ auto result_obj = yyjson_mut_obj (doc);
78+ yyjson_mut_doc_set_root (doc, result_obj);
79+
80+ auto platform = DuckDB::Platform ();
81+
82+ yyjson_mut_obj_add_str (doc, result_obj, " extension_name" , extension_name.c_str ());
83+ yyjson_mut_obj_add_str (doc, result_obj, " extension_version" , extension_version.c_str ());
84+ yyjson_mut_obj_add_str (doc, result_obj, " user_agent" , " query-farm/20251011" );
85+ yyjson_mut_obj_add_str (doc, result_obj, " duckdb_platform" , platform.c_str ());
86+ yyjson_mut_obj_add_str (doc, result_obj, " duckdb_library_version" , DuckDB::LibraryVersion ());
87+ yyjson_mut_obj_add_str (doc, result_obj, " duckdb_release_codename" , DuckDB::ReleaseCodename ());
88+ yyjson_mut_obj_add_str (doc, result_obj, " duckdb_source_id" , DuckDB::SourceID ());
89+
90+ size_t telemetry_len;
91+ auto telemetry_data =
92+ yyjson_mut_val_write_opts (result_obj, YYJSON_WRITE_ALLOW_INF_AND_NAN, NULL , &telemetry_len, nullptr );
93+
94+ if (telemetry_data == nullptr )
95+ {
96+ throw SerializationException (" Failed to serialize telemetry data." );
97+ }
98+
99+ yyjson_mut_doc_free (doc);
100+
101+ #ifndef __EMSCRIPTEN__
102+ [[maybe_unused]] auto _ = std::async (
103+ std::launch::async, [db_ptr = loader.GetDatabaseInstance ().shared_from_this (), json = telemetry_data,
104+ len = telemetry_len]() mutable
105+ { sendHTTPRequest (std::move (db_ptr), json, len); });
106+ #else
107+ sendHTTPRequest (loader.GetDatabaseInstance ().shared_from_this (), telemetry_data, telemetry_len);
108+ #endif
109+ }
110+
111+ } // namespace duckdb
0 commit comments