13
13
#include " lldb/Interpreter/CommandReturnObject.h"
14
14
#include " lldb/Utility/LLDBLog.h"
15
15
#include " lldb/Utility/StructuredData.h"
16
+ #include " lldb/Utility/UUID.h"
16
17
#include " lldb/lldb-forward.h"
17
18
#include " llvm/ADT/FunctionExtras.h"
18
19
#include " llvm/ADT/StringExtras.h"
19
20
#include " llvm/ADT/StringRef.h"
20
21
#include " llvm/Support/JSON.h"
21
22
#include " llvm/Telemetry/Telemetry.h"
23
+ #include < atomic>
22
24
#include < chrono>
23
25
#include < ctime>
24
26
#include < memory>
28
30
namespace lldb_private {
29
31
namespace telemetry {
30
32
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
+
31
44
// We expect each (direct) subclass of LLDBTelemetryInfo to
32
45
// have an LLDBEntryKind in the form 0b11xxxxxxxx
33
46
// Specifically:
@@ -37,6 +50,7 @@ namespace telemetry {
37
50
// must have their LLDBEntryKind in the similar form (ie., share common prefix)
38
51
struct LLDBEntryKind : public ::llvm::telemetry::EntryKind {
39
52
static const llvm::telemetry::KindType BaseInfo = 0b11000000 ;
53
+ static const llvm::telemetry::KindType CommandInfo = 0b11010000 ;
40
54
static const llvm::telemetry::KindType DebuggerInfo = 0b11000100 ;
41
55
};
42
56
@@ -66,6 +80,52 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo {
66
80
void serialize (llvm::telemetry::Serializer &serializer) const override ;
67
81
};
68
82
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
+
69
129
struct DebuggerInfo : public LLDBBaseTelemetryInfo {
70
130
std::string lldb_version;
71
131
@@ -93,64 +153,76 @@ class TelemetryManager : public llvm::telemetry::Manager {
93
153
public:
94
154
llvm::Error preDispatch (llvm::telemetry::TelemetryInfo *entry) override ;
95
155
96
- const llvm::telemetry::Config *GetConfig ();
156
+ const LLDBConfig *GetConfig () { return m_config. get (); }
97
157
98
158
virtual llvm::StringRef GetInstanceName () const = 0;
99
159
100
160
static TelemetryManager *GetInstance ();
101
161
102
- static TelemetryManager *GetInstanceIfEnabled ();
103
-
104
162
protected:
105
- TelemetryManager (std::unique_ptr<llvm::telemetry::Config > config);
163
+ TelemetryManager (std::unique_ptr<LLDBConfig > config);
106
164
107
165
static void SetInstance (std::unique_ptr<TelemetryManager> manger);
108
166
109
167
private:
110
- std::unique_ptr<llvm::telemetry::Config > m_config;
168
+ std::unique_ptr<LLDBConfig > m_config;
111
169
// Each instance of a TelemetryManager is assigned a unique ID.
112
170
const std::string m_id;
113
-
114
171
static std::unique_ptr<TelemetryManager> g_instance;
115
172
};
116
173
117
174
// / Helper RAII class for collecting telemetry.
118
175
template <typename Info> struct ScopedDispatcher {
119
176
// The debugger pointer is optional because we may not have a debugger yet.
120
177
// 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,
122
184
Debugger *debugger = nullptr )
123
- : m_callback (std::move(callback )) {
185
+ : m_final_callback (std::move(final_callback )) {
124
186
// Start the timer.
125
187
m_start_time = std::chrono::steady_clock::now ();
126
- m_info. debugger = debugger;
188
+ this -> debugger = debugger;
127
189
}
128
190
129
- void SetDebugger (Debugger *debugger) { m_info. debugger = debugger; }
191
+ void SetDebugger (Debugger *debugger) { this -> debugger = debugger; }
130
192
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
+ }
137
198
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);
143
210
// And then we dispatch.
144
- if (llvm::Error er = manager->dispatch (&m_info )) {
211
+ if (llvm::Error er = manager->dispatch (&info )) {
145
212
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 ());
147
214
}
148
215
}
149
216
217
+ ~ScopedDispatcher () {
218
+ if (m_final_callback)
219
+ DispatchNow (std::move (m_final_callback));
220
+ }
221
+
150
222
private:
151
223
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 ;
154
226
};
155
227
156
228
} // namespace telemetry
0 commit comments