Skip to content

[LLDB][Telemetry] Collect telemetry from client when allowed. #129728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Apr 26, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
21103ad
[LLDB][Telemetry] Collect telemetry from client when allowed.
oontvoo Mar 4, 2025
c0cf1c0
formatting
oontvoo Mar 4, 2025
4b13494
Merge branch 'main' into client
oontvoo Mar 18, 2025
11fd330
reconcile with new api change
oontvoo Mar 19, 2025
1aff2b1
Merge branch 'main' into client
oontvoo Mar 24, 2025
4718da4
formatting
oontvoo Mar 24, 2025
8b15611
Update SBDebugger.h
oontvoo Mar 24, 2025
a5a8ac7
Update lldb/source/API/SBDebugger.cpp
oontvoo Mar 25, 2025
4990441
Update lldb/source/Core/Telemetry.cpp
oontvoo Mar 25, 2025
63b80b2
Update lldb/source/Core/Telemetry.cpp
oontvoo Mar 25, 2025
56a2018
Update lldb/unittests/Core/TelemetryTest.cpp
oontvoo Mar 25, 2025
a31d160
address review comments
oontvoo Mar 25, 2025
60eb43a
rename
oontvoo Mar 25, 2025
f6f3852
rename again
oontvoo Mar 25, 2025
2d2d63d
update Telemetry
oontvoo Mar 25, 2025
eb4b0f1
update
oontvoo Mar 25, 2025
b875599
add client_name field
oontvoo Mar 26, 2025
c35e38e
disable client telemetry for SWIG
oontvoo Mar 26, 2025
31a0ed2
formatting
oontvoo Mar 26, 2025
ef5257e
Update SBDebugger.h
oontvoo Mar 26, 2025
fa90be0
Merge branch 'main' into client
oontvoo Mar 27, 2025
60de76d
formatting
oontvoo Mar 27, 2025
654f8ca
use GetClientName
oontvoo Mar 27, 2025
1c56b80
define macro to disable client-telemetry
oontvoo Mar 28, 2025
4c161d8
typo
oontvoo Mar 28, 2025
b408b88
update
oontvoo Mar 28, 2025
ce679cd
Merge branch 'main' into client
oontvoo Apr 24, 2025
af0504c
put condition behind ifndef SWIG
oontvoo Apr 24, 2025
253291f
remove unnecessary ifdef branch
oontvoo Apr 25, 2025
0a5da4a
Merge branch 'main' into client
oontvoo Apr 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into client
  • Loading branch information
oontvoo authored Mar 18, 2025
commit 4b134946c5f3aa315f5f4cb7cddfa571ff110a6d
63 changes: 57 additions & 6 deletions lldb/include/lldb/Core/Telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ namespace lldb_private {
namespace telemetry {

struct LLDBConfig : public ::llvm::telemetry::Config {
// If true, we will collect telemetry from LLDB's clients (eg., lldb-dap) via
// If true, we will collect full details about a debug command (eg., args and
// original command). Note: This may contain PII, hence can only be enabled by
// the vendor while creating the Manager.
const bool detailed_command_telemetry;

// If true, we will collect telemetry from LLDB's clients (eg., lldb-dap) via
// the SB interface. Must also be enabled by the vendor while creating the
// manager.
const bool m_enable_client_telemetry;

explicit LLDBConfig(bool enable_telemetry, bool enable_client_telemetry)
const bool enable_client_telemetry;
explicit LLDBConfig(bool enable_telemetry, bool detailed_command_telemetry, bool enable_client_telemetry)
: ::llvm::telemetry::Config(enable_telemetry),
m_enable_client_telemetry(enable_client_telemetry) {}
detailed_command_telemetry(detailed_command_telemetry),
enable_client_telemetry(enable_client_telemetry){}
};

// We expect each (direct) subclass of LLDBTelemetryInfo to
Expand Down Expand Up @@ -84,6 +90,52 @@ struct ClientInfo : public LLDBBaseTelemetryInfo {
std::string request_name;
std::optional<std::string> error_msg;
};

struct CommandInfo : public LLDBBaseTelemetryInfo {
/// If the command is/can be associated with a target entry this field
/// contains that target's UUID. <EMPTY> otherwise.
UUID target_uuid;
/// A unique ID for a command so the manager can match the start entry with
/// its end entry. These values only need to be unique within the same
/// session. Necessary because we'd send off an entry right before a command's
/// execution and another right after. This is to avoid losing telemetry if
/// the command does not execute successfully.
uint64_t command_id;
/// The command name(eg., "breakpoint set")
std::string command_name;
/// These two fields are not collected by default due to PII risks.
/// Vendor may allow them by setting the
/// LLDBConfig::detailed_command_telemetry.
/// @{
std::optional<std::string> original_command;
std::optional<std::string> args;
/// @}
/// Return status of a command and any error description in case of error.
std::optional<lldb::ReturnStatus> ret_status;
std::optional<std::string> error_data;

CommandInfo() = default;

llvm::telemetry::KindType getKind() const override {
return LLDBEntryKind::CommandInfo;
}

static bool classof(const llvm::telemetry::TelemetryInfo *T) {
return (T->getKind() & LLDBEntryKind::CommandInfo) ==
LLDBEntryKind::CommandInfo;
}

void serialize(llvm::telemetry::Serializer &serializer) const override;

static uint64_t GetNextId();

private:
// We assign each command (in the same session) a unique id so that their
// "start" and "end" entries can be matched up.
// These values don't need to be unique across runs (because they are
// secondary-key), hence a simple counter is sufficent.
static std::atomic<uint64_t> g_command_id_seed;
};

struct DebuggerInfo : public LLDBBaseTelemetryInfo {
std::string lldb_version;
Expand Down Expand Up @@ -117,7 +169,6 @@ class TelemetryManager : public llvm::telemetry::Manager {
virtual void
DispatchClientTelemery(const lldb_private::StructuredDataImpl &entry,
Debugger *debugger);

virtual llvm::StringRef GetInstanceName() const = 0;

static TelemetryManager *GetInstance();
Expand Down
16 changes: 10 additions & 6 deletions lldb/source/Core/Telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ void DebuggerInfo::serialize(Serializer &serializer) const {
serializer.write("is_exit_entry", is_exit_entry);
}

std::atomic<uint64_t> CommandInfo::g_command_id_seed = 0;
uint64_t CommandInfo::GetNextId() { return g_command_id_seed.fetch_add(1); }

TelemetryManager::TelemetryManager(std::unique_ptr<LLDBConfig> config)
: m_config(std::move(config)), m_id(MakeUUID()) {}

Expand Down Expand Up @@ -145,6 +148,7 @@ void TelemetryManager::DispatchClientTelemetry(
"Failed to dispatch client telemetry");
}


class NoOpTelemetryManager : public TelemetryManager {
public:
llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override {
Expand All @@ -156,18 +160,18 @@ class NoOpTelemetryManager : public TelemetryManager {
: TelemetryManager(std::make_unique<LLDBConfig>(
/*EnableTelemetry*/ false, /*DetailedCommand*/ false)) {}

llvm::StringRef GetInstanceName() const override {
virtual llvm::StringRef GetInstanceName() const override {
return "NoOpTelemetryManager";
}

llvm::Error dispatch(llvm::telemetry::TelemetryInfo *entry) override {
DispatchClientTelemetry(
const lldb_private::StructuredDataImpl &entry, Debugger *debugger) override {
// Does nothing.
return llvm::Error::success();
}

void DispatchClientTelemetry(const lldb_private::StructuredDataImpl &entry,
Debugger *debugger) override {

llvm::Error dispatch(llvm::telemetry::TelemetryInfo *entry) override {
// Does nothing.
return llvm::Error::success();
}

static NoOpTelemetryManager *GetInstance() {
Expand Down
57 changes: 10 additions & 47 deletions lldb/tools/lldb-dap/DAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,56 +672,19 @@ void DAP::SetTarget(const lldb::SBTarget target) {
}
}

PacketStatus DAP::GetNextObject(llvm::json::Object &object) {
std::string json = ReadJSON();
if (json.empty())
return PacketStatus::EndOfFile;

llvm::StringRef json_sref(json);
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
if (!json_value) {
auto error = json_value.takeError();
if (log) {
std::string error_str;
llvm::raw_string_ostream strm(error_str);
strm << error;
*log << "error: failed to parse JSON: " << error_str << std::endl
<< json << std::endl;
}
return PacketStatus::JSONMalformed;
}

if (log) {
*log << llvm::formatv("{0:2}", *json_value).str() << std::endl;
}

llvm::json::Object *object_ptr = json_value->getAsObject();
if (!object_ptr) {
if (log)
*log << "error: json packet isn't a object" << std::endl;
return PacketStatus::JSONNotObject;
}
object = *object_ptr;
return PacketStatus::Success;
}

bool DAP::HandleObject(const llvm::json::Object &object) {
TelemetryDispatcher dispatcher;

const auto packet_type = GetString(object, "type");
if (packet_type == "request") {
const auto command = GetString(object, "command");
dispatcher.set("request_name", command);
auto new_handler_pos = request_handlers.find(command);
if (new_handler_pos != request_handlers.end()) {
(*new_handler_pos->second)(object);
bool DAP::HandleObject(const protocol::Message &M) {
TelemetryDispatcher dispatcher;
if (const auto *req = std::get_if<protocol::Request>(&M)) {
auto handler_pos = request_handlers.find(req->command);
dispatcher.set("request_name", req->command);
if (handler_pos != request_handlers.end()) {
(*handler_pos->second)(*req);
return true; // Success
}

dispatcher.set("error", llvm::Twine("unhandled-command:" + command).str());
if (log)
*log << "error: unhandled command \"" << command.data() << "\""
<< std::endl;
dispatcher.set("error", llvm::Twine("unhandled-command:" + req->command).str());
DAP_LOG(log, "({0}) error: unhandled command '{1}'",
transport.GetClientName(), req->command);
return false; // Fail
}

Expand Down
3 changes: 3 additions & 0 deletions lldb/tools/lldb-dap/LLDBUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ class TelemetryDispatcher {
SBDebugger *debugger;
};

/// Take ownership of the stored error.
llvm::Error ToError(const lldb::SBError &error);

} // namespace lldb_dap

#endif
4 changes: 2 additions & 2 deletions lldb/unittests/Core/TelemetryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class TestDestination : public llvm::telemetry::Destination {
class FakePlugin : public telemetry::TelemetryManager {
public:
FakePlugin()
: telemetry::TelemetryManager(
std::make_unique<telemetry::LLDBConfig>(true, true)) {}
: telemetry::TelemetryManager(std::make_unique<telemetry::LLDBConfig>(
/*enable_telemetry=*/true, /*detailed_command_telemetry=*/true, /*enable_client_telemetry*/true)) {}

// TelemetryManager interface
llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override {
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.