Skip to content

Commit 9f9a776

Browse files
committed
fix: add telemetry
1 parent c62fd28 commit 9f9a776

File tree

4 files changed

+1027
-905
lines changed

4 files changed

+1027
-905
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ include_directories(
1616
)
1717

1818
# Add redis_secret.cpp to the sources
19-
set(EXTENSION_SOURCES
19+
set(EXTENSION_SOURCES
2020
src/redis_extension.cpp
2121
src/redis_secret.cpp
22+
src/query_farm_telemetry.cpp
2223
)
2324

2425
build_static_extension(${TARGET_NAME} ${EXTENSION_SOURCES})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
#include <string>
3+
#include "duckdb.hpp"
4+
5+
#if defined(_WIN32) || defined(_WIN64)
6+
// Windows: functions are hidden by default unless exported
7+
#define INTERNAL_FUNC
8+
#elif defined(__GNUC__) || defined(__clang__)
9+
// Linux / macOS: hide symbol using visibility attribute
10+
#define INTERNAL_FUNC __attribute__((visibility("hidden")))
11+
#else
12+
#define INTERNAL_FUNC
13+
#endif
14+
15+
namespace duckdb {
16+
void QueryFarmSendTelemetry(ExtensionLoader &loader, const string &extension_name, const string &extension_version);
17+
}

src/query_farm_telemetry.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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

Comments
 (0)