================
@@ -0,0 +1,237 @@
+#ifndef LLDB_CORE_TELEMETRY_H
+#define LLDB_CORE_TELEMETRY_H
+
+#include <chrono>
+#include <ctime>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+using SteadyTimePoint = std::chrono::time_point<std::chrono::steady_clock>;
+
+struct TelemetryEventStats {
+  // REQUIRED: Start time of event
+  SteadyTimePoint m_start;
+  // OPTIONAL: End time of event - may be empty if not meaningful.
+  std::optional<SteadyTimePoint> m_end;
+
+  // TBD: could add some memory stats here too?
+
+  TelemetryEventStats() = default;
+  TelemetryEventStats(SteadyTimePoint start) : m_start(start) {}
+  TelemetryEventStats(SteadyTimePoint start, SteadyTimePoint end)
+      : m_start(start), m_end(end) {}
+
+  std::optional<std::chrono::nanoseconds> Duration() const {
+    if (m_end.has_value())
+      return *m_end - m_start;
+    else
+      return std::nullopt;
+  }
+};
+
+struct LoggerConfig {
+  // If true, loggings will be enabled.
+  bool enable_logging;
+
+  // Additional destinations to send the logged entries.
+  // Could be stdout, stderr, or some local paths.
+  // Note: these are destinations are __in addition to__ whatever the default
+  // destination(s) are, as implemented by vendors.
+  std::vector<std::string> additional_destinations;
+};
+
+// The base class contains the basic set of data.
+// Downstream implementations can add more fields as needed.
+struct BaseTelemetryEntry {
+  // A "session" corresponds to every time lldb starts.
+  // All entries emitted for the same session will have
+  // the same session_uuid
+  std::string session_uuid;
+
+  TelemetryEventStats stats;
+
+  // Counting number of entries.
+  // (For each set of entries with the same session_uuid, this value should
+  // be unique for each entry)
+  size_t counter;
+
+  virtual ~BaseTelemetryEntry() = default;
+  virtual std::string ToString() const;
+};
+
+struct ExitDescription {
+  int exit_code;
+  std::string description;
+};
+
+struct DebuggerInfoEntry : public BaseTelemetryEntry {
+  std::string username;
+  std::string lldb_git_sha;
+  std::string lldb_path;
+  std::string cwd;
+
+  // The debugger exit info. Not populated if this entry was emitted for 
startup
+  // event.
+  std::optional<ExitDescription> lldb_exit;
+
+  std::string ToString() const override;
+};
+
+struct TargetInfoEntry : public BaseTelemetryEntry {
+  // All entries emitted for the same SBTarget will have the same
+  // target_uuid.
+  std::string target_uuid;
+  std::string file_format;
+
+  std::string binary_path;
+  size_t binary_size;
+
+  // The process(target) exit info. Not populated of this entry was emitted for
+  // startup event.
+  std::optional<ExitDescription> process_exit;
+
+  std::string ToString() const override;
+};
+
+// Entry from client (eg., SB-API)
+struct ClientTelemetryEntry : public BaseTelemetryEntry {
+  std::string request_name;
+  std::string error_msg;
+  std::string ToString() const override;
+};
+
+struct CommandInfoEntry : public BaseTelemetryEntry {
+  // If the command is/can be associated with a target entry,
+  // this field contains that target's UUID.
+  // <EMPTY> otherwise.
+  std::string target_uuid;
+  std::string command_uuid;
+
+  // Eg., "breakpoint set"
+  std::string command_name;
+
+  // !!NOTE!!: The following fields may be omitted due to PII risk.
+  // (Configurable via the LoggerConfig struct)
+  std::string original_command;
+  std::string args;
+
+  ExitDescription exit_description;
+
+  std::string ToString() const override;
+};
+
+// The "catch-all" entry to store a set of custom/non-standard
+// data.
+struct MiscInfoEntry : public BaseTelemetryEntry {
+  // If the event is/can be associated with a target entry,
+  // this field contains that target's UUID.
+  // <EMPTY> otherwise.
+  std::string target_uuid;
+
+  // Set of key-value pairs for any optional (or impl-specific) data
+  std::unordered_map<std::string, std::string> meta_data;
+
+  std::string ToString() const override;
+};
+
+// Where/how to send the logged entries.
+class TelemetryDestination {
+public:
+  virtual ~TelemetryDestination() = default;
+  virtual Status EmitEntry(const BaseTelemetryEntry *entry) = 0;
+  virtual std::string name() const = 0;
+};
+
+// The logger itself!
+class TelemetryLogger {
+public:
+  static std::shared_ptr<TelemetryLogger> CreateInstance(Debugger *);
+
+  virtual ~TelemetryLogger() = default;
+
+  // Invoked upon lldb startup
+  virtual void LogStartup(llvm::StringRef lldb_path,
+                          TelemetryEventStats stats) = 0;
+
+  // Invoked upon lldb exit.
+  virtual void LogExit(llvm::StringRef lldb_path,
----------------
JDevlieghere wrote:

Instead of having separate methods for the different events, which all take a 
`TelemetryEventStats`, it seems like it would be simpler to have a generic 
`Emit` method and then the individual events know how to emit themselves? 

https://github.com/llvm/llvm-project/pull/87815
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to