1212#include " lldb/Core/StructuredDataImpl.h"
1313#include " lldb/Interpreter/CommandReturnObject.h"
1414#include " lldb/Utility/StructuredData.h"
15+ #include " lldb/Utility/LLDBLog.h"
1516#include " lldb/lldb-forward.h"
1617#include " llvm/ADT/StringExtras.h"
1718#include " llvm/ADT/StringRef.h"
19+ #include " llvm/ADT/FunctionExtras.h"
1820#include " llvm/Support/JSON.h"
1921#include " llvm/Telemetry/Telemetry.h"
22+ #include < atomic>
2023#include < chrono>
2124#include < ctime>
2225#include < memory>
2730namespace lldb_private {
2831namespace telemetry {
2932
33+ struct LLDBConfig : public ::llvm::telemetry::Config {
34+ const bool m_collect_original_command;
35+
36+ explicit LLDBConfig (bool enable_telemetry, bool collect_original_command)
37+ : ::llvm::telemetry::Config(enable_telemetry), m_collect_original_command(collect_original_command) {}
38+ };
39+
3040struct LLDBEntryKind : public ::llvm::telemetry::EntryKind {
31- static const llvm::telemetry::KindType BaseInfo = 0b11000 ;
41+ static const llvm::telemetry::KindType BaseInfo = 0b11000000 ;
42+ static const llvm::telemetry::KindType CommandInfo = 0b11010000 ;
3243};
3344
3445// / Defines a convenient type for timestamp of various events.
@@ -41,6 +52,7 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo {
4152 std::optional<SteadyTimePoint> end_time;
4253 // TBD: could add some memory stats here too?
4354
55+ lldb::user_id_t debugger_id = LLDB_INVALID_UID;
4456 Debugger *debugger;
4557
4658 // For dyn_cast, isa, etc operations.
@@ -56,26 +68,135 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo {
5668 void serialize (llvm::telemetry::Serializer &serializer) const override ;
5769};
5870
71+
72+ struct CommandInfo : public LLDBBaseTelemetryInfo {
73+
74+ // If the command is/can be associated with a target entry this field contains
75+ // that target's UUID. <EMPTY> otherwise.
76+ std::string target_uuid;
77+ // A unique ID for a command so the manager can match the start entry with
78+ // its end entry. These values only need to be unique within the same session.
79+ // Necessary because we'd send off an entry right before a command's execution
80+ // and another right after. This is to avoid losing telemetry if the command
81+ // does not execute successfully.
82+ int command_id;
83+
84+ // Eg., "breakpoint set"
85+ std::string command_name;
86+
87+ // !!NOTE!! These two fields are not collected (upstream) due to PII risks.
88+ // (Downstream impl may add them if needed).
89+ // std::string original_command;
90+ // std::string args;
91+
92+ lldb::ReturnStatus ret_status;
93+ std::string error_data;
94+
95+
96+ CommandInfo () = default ;
97+
98+ llvm::telemetry::KindType getKind () const override { return LLDBEntryKind::CommandInfo; }
99+
100+ static bool classof (const llvm::telemetry::TelemetryInfo *T) {
101+ return (T->getKind () & LLDBEntryKind::CommandInfo) == LLDBEntryKind::CommandInfo;
102+ }
103+
104+ void serialize (Serializer &serializer) const override ;
105+ };
106+
59107// / The base Telemetry manager instance in LLDB.
60108// / This class declares additional instrumentation points
61109// / applicable to LLDB.
62110class TelemetryManager : public llvm ::telemetry::Manager {
63111public:
64112 llvm::Error preDispatch (llvm::telemetry::TelemetryInfo *entry) override ;
65113
114+ int MakeNextCommandId ();
115+
116+ LLDBConfig* GetConfig () { return m_config.get (); }
117+
66118 virtual llvm::StringRef GetInstanceName () const = 0;
67119 static TelemetryManager *getInstance ();
68120
69121protected:
70- TelemetryManager (std::unique_ptr<llvm::telemetry::Config > config);
122+ TelemetryManager (std::unique_ptr<LLDBConfig > config);
71123
72124 static void setInstance (std::unique_ptr<TelemetryManager> manger);
73125
74126private:
75- std::unique_ptr<llvm::telemetry::Config> m_config;
127+ std::unique_ptr<LLDBConfig> m_config;
128+ const std::string m_id;
129+ // We assign each command (in the same session) a unique id so that their
130+ // "start" and "end" entries can be matched up.
131+ // These values don't need to be unique across runs (because they are
132+ // secondary-key), hence a simple counter is sufficent.
133+ std::atomic<int > command_id_seed = 0 ;
76134 static std::unique_ptr<TelemetryManager> g_instance;
77135};
78136
137+ // / Helper RAII class for collecting telemetry.
138+ template <typename Info> struct ScopedDispatcher {
139+ // The debugger pointer is optional because we may not have a debugger yet.
140+ // In that case, caller must set the debugger later.
141+ ScopedDispatcher (Debugger *debugger = nullptr ) {
142+ // Start the timer.
143+ m_start_time = std::chrono::steady_clock::now ();
144+ debugger = debugger;
145+ }
146+ ScopedDispatcher (llvm::unique_function<void (Info *info)> final_callback,
147+ Debugger *debugger = nullptr )
148+ : m_final_callback(std::move(final_callback)) {
149+ // Start the timer.
150+ m_start_time = std::chrono::steady_clock::now ();
151+ debugger = debugger;
152+ }
153+
154+
155+ template typename <T>
156+ T GetIfEnable (llvm::unique_function<T(TelemetryManager*)> callable,
157+ T default_value) {
158+ TelemetryManager *manager = TelemetryManager::GetInstanceIfEnabled ();
159+ if (!manager)
160+ return default_value;
161+ return callable (manager);
162+ }
163+
164+ void SetDebugger (Debugger *debugger) { debugger = debugger; }
165+
166+ void SetFinalCallback (llvm::unique_function<void (Info *info)> final_callback) {
167+ m_final_callback (std::move (final_callback));
168+ }
169+
170+ void DispatchIfEnable (llvm::unique_function<void (Info *info)> populate_fields_cb) {
171+ TelemetryManager *manager = TelemetryManager::GetInstanceIfEnabled ();
172+ if (!manager)
173+ return ;
174+ Info info;
175+ // Populate the common fields we know aboutl
176+ info.start_time = m_start_time;
177+ info.end_time = std::chrono::steady_clock::now ();
178+ info.debugger = debugger;
179+ // The callback will set the rest.
180+ populate_fields_cb (&info);
181+ // And then we dispatch.
182+ if (llvm::Error er = manager->dispatch (&info)) {
183+ LLDB_LOG_ERROR (GetLog (LLDBLog::Object), std::move (er),
184+ " Failed to dispatch entry of type: {0}" , m_info.getKind ());
185+ }
186+
187+ }
188+
189+ ~ScopedDispatcher () {
190+ // TODO: check if there's a cb to call?
191+ DispatchIfEnable (std::move (m_final_callback));
192+ }
193+
194+ private:
195+ SteadyTimePoint m_start_time;
196+ llvm::unique_function<void (Info *info)> m_final_callback;
197+ Debugger * debugger;
198+ };
199+
79200} // namespace telemetry
80201} // namespace lldb_private
81202#endif // LLDB_CORE_TELEMETRY_H
0 commit comments