1313#include " lldb/Interpreter/CommandReturnObject.h"
1414#include " lldb/Utility/LLDBLog.h"
1515#include " lldb/Utility/StructuredData.h"
16+ #include " lldb/Utility/UUID.h"
1617#include " lldb/lldb-forward.h"
1718#include " llvm/ADT/FunctionExtras.h"
1819#include " llvm/ADT/StringExtras.h"
1920#include " llvm/ADT/StringRef.h"
2021#include " llvm/Support/JSON.h"
2122#include " llvm/Telemetry/Telemetry.h"
23+ #include < atomic>
2224#include < chrono>
2325#include < ctime>
2426#include < memory>
2830namespace lldb_private {
2931namespace telemetry {
3032
33+ struct LLDBConfig : public ::llvm::telemetry::Config {
34+ // If true, we will collect full details about a debug command (eg., args and
35+ // original command). Note: This may contain PII, hence can only be enabled by
36+ // the vendor while creating the Manager.
37+ const bool detailed_command_telemetry;
38+
39+ explicit LLDBConfig (bool enable_telemetry, bool detailed_command_telemetry)
40+ : ::llvm::telemetry::Config(enable_telemetry),
41+ detailed_command_telemetry(detailed_command_telemetry) {}
42+ };
43+
3144// We expect each (direct) subclass of LLDBTelemetryInfo to
3245// have an LLDBEntryKind in the form 0b11xxxxxxxx
3346// Specifically:
@@ -37,6 +50,7 @@ namespace telemetry {
3750// must have their LLDBEntryKind in the similar form (ie., share common prefix)
3851struct LLDBEntryKind : public ::llvm::telemetry::EntryKind {
3952 static const llvm::telemetry::KindType BaseInfo = 0b11000000 ;
53+ static const llvm::telemetry::KindType CommandInfo = 0b11010000 ;
4054 static const llvm::telemetry::KindType DebuggerInfo = 0b11000100 ;
4155};
4256
@@ -66,6 +80,52 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo {
6680 void serialize (llvm::telemetry::Serializer &serializer) const override ;
6781};
6882
83+ struct CommandInfo : public LLDBBaseTelemetryInfo {
84+ // / If the command is/can be associated with a target entry this field
85+ // / contains that target's UUID. <EMPTY> otherwise.
86+ UUID target_uuid;
87+ // / A unique ID for a command so the manager can match the start entry with
88+ // / its end entry. These values only need to be unique within the same
89+ // / session. Necessary because we'd send off an entry right before a command's
90+ // / execution and another right after. This is to avoid losing telemetry if
91+ // / the command does not execute successfully.
92+ uint64_t command_id;
93+ // / The command name(eg., "breakpoint set")
94+ std::string command_name;
95+ // / These two fields are not collected by default due to PII risks.
96+ // / Vendor may allow them by setting the
97+ // / LLDBConfig::detailed_command_telemetry.
98+ // / @{
99+ std::optional<std::string> original_command;
100+ std::optional<std::string> args;
101+ // / @}
102+ // / Return status of a command and any error description in case of error.
103+ std::optional<lldb::ReturnStatus> ret_status;
104+ std::optional<std::string> error_data;
105+
106+ CommandInfo () = default ;
107+
108+ llvm::telemetry::KindType getKind () const override {
109+ return LLDBEntryKind::CommandInfo;
110+ }
111+
112+ static bool classof (const llvm::telemetry::TelemetryInfo *T) {
113+ return (T->getKind () & LLDBEntryKind::CommandInfo) ==
114+ LLDBEntryKind::CommandInfo;
115+ }
116+
117+ void serialize (llvm::telemetry::Serializer &serializer) const override ;
118+
119+ static uint64_t GetNextId ();
120+
121+ private:
122+ // We assign each command (in the same session) a unique id so that their
123+ // "start" and "end" entries can be matched up.
124+ // These values don't need to be unique across runs (because they are
125+ // secondary-key), hence a simple counter is sufficent.
126+ static std::atomic<uint64_t > g_command_id_seed;
127+ };
128+
69129struct DebuggerInfo : public LLDBBaseTelemetryInfo {
70130 std::string lldb_version;
71131
@@ -93,64 +153,76 @@ class TelemetryManager : public llvm::telemetry::Manager {
93153public:
94154 llvm::Error preDispatch (llvm::telemetry::TelemetryInfo *entry) override ;
95155
96- const llvm::telemetry::Config *GetConfig ();
156+ const LLDBConfig *GetConfig () { return m_config. get (); }
97157
98158 virtual llvm::StringRef GetInstanceName () const = 0;
99159
100160 static TelemetryManager *GetInstance ();
101161
102- static TelemetryManager *GetInstanceIfEnabled ();
103-
104162protected:
105- TelemetryManager (std::unique_ptr<llvm::telemetry::Config > config);
163+ TelemetryManager (std::unique_ptr<LLDBConfig > config);
106164
107165 static void SetInstance (std::unique_ptr<TelemetryManager> manger);
108166
109167private:
110- std::unique_ptr<llvm::telemetry::Config > m_config;
168+ std::unique_ptr<LLDBConfig > m_config;
111169 // Each instance of a TelemetryManager is assigned a unique ID.
112170 const std::string m_id;
113-
114171 static std::unique_ptr<TelemetryManager> g_instance;
115172};
116173
117174// / Helper RAII class for collecting telemetry.
118175template <typename Info> struct ScopedDispatcher {
119176 // The debugger pointer is optional because we may not have a debugger yet.
120177 // In that case, caller must set the debugger later.
121- ScopedDispatcher (llvm::unique_function<void (Info *info)> callback,
178+ ScopedDispatcher (Debugger *debugger = nullptr ) {
179+ // Start the timer.
180+ m_start_time = std::chrono::steady_clock::now ();
181+ this ->debugger = debugger;
182+ }
183+ ScopedDispatcher (llvm::unique_function<void (Info *info)> final_callback,
122184 Debugger *debugger = nullptr )
123- : m_callback (std::move(callback )) {
185+ : m_final_callback (std::move(final_callback )) {
124186 // Start the timer.
125187 m_start_time = std::chrono::steady_clock::now ();
126- m_info. debugger = debugger;
188+ this -> debugger = debugger;
127189 }
128190
129- void SetDebugger (Debugger *debugger) { m_info. debugger = debugger; }
191+ void SetDebugger (Debugger *debugger) { this -> debugger = debugger; }
130192
131- ~ScopedDispatcher () {
132- // If Telemetry is disabled (either at buildtime or runtime),
133- // then don't do anything.
134- TelemetryManager *manager = TelemetryManager::GetInstanceIfEnabled ();
135- if (!manager)
136- return ;
193+ void DispatchOnExit (llvm::unique_function<void (Info *info)> final_callback) {
194+ // We probably should not be overriding previously set cb.
195+ assert (!m_final_callback);
196+ m_final_callback = std::move (final_callback);
197+ }
137198
138- m_info.start_time = m_start_time;
139- // Populate common fields that we can only set now.
140- m_info.end_time = std::chrono::steady_clock::now ();
141- // The callback will set the remaining fields.
142- m_callback (&m_info);
199+ void DispatchNow (llvm::unique_function<void (Info *info)> populate_fields_cb) {
200+ TelemetryManager *manager = TelemetryManager::GetInstance ();
201+ if (!manager->GetConfig ()->EnableTelemetry )
202+ return ;
203+ Info info;
204+ // Populate the common fields we know about.
205+ info.start_time = m_start_time;
206+ info.end_time = std::chrono::steady_clock::now ();
207+ info.debugger = debugger;
208+ // The callback will set the rest.
209+ populate_fields_cb (&info);
143210 // And then we dispatch.
144- if (llvm::Error er = manager->dispatch (&m_info )) {
211+ if (llvm::Error er = manager->dispatch (&info )) {
145212 LLDB_LOG_ERROR (GetLog (LLDBLog::Object), std::move (er),
146- " Failed to dispatch entry of type: {0}" , m_info .getKind ());
213+ " Failed to dispatch entry of type: {0}" , info .getKind ());
147214 }
148215 }
149216
217+ ~ScopedDispatcher () {
218+ if (m_final_callback)
219+ DispatchNow (std::move (m_final_callback));
220+ }
221+
150222private:
151223 SteadyTimePoint m_start_time;
152- llvm::unique_function<void (Info *info)> m_callback ;
153- Info m_info ;
224+ llvm::unique_function<void (Info *info)> m_final_callback ;
225+ Debugger *debugger ;
154226};
155227
156228} // namespace telemetry
0 commit comments