brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · 2f2e1c1 Raw
231 lines · cpp
1//===-- Telemetry.cpp -----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#include "lldb/Core/Telemetry.h"9#include "lldb/Core/Debugger.h"10#include "lldb/Utility/LLDBLog.h"11#include "lldb/Utility/Log.h"12#include "lldb/Utility/UUID.h"13#include "lldb/lldb-enumerations.h"14#include "lldb/lldb-forward.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/Format.h"18#include "llvm/Support/RandomNumberGenerator.h"19#include "llvm/Telemetry/Telemetry.h"20#include <chrono>21#include <cstdlib>22#include <ctime>23#include <memory>24#include <string>25#include <utility>26 27namespace lldb_private {28namespace telemetry {29 30using namespace llvm::telemetry;31 32static uint64_t ToNanosec(const SteadyTimePoint Point) {33  return std::chrono::nanoseconds(Point.time_since_epoch()).count();34}35 36// Generate a unique string. This should be unique across different runs.37// We build such string by combining three parts:38// <16 random bytes>_<timestamp>39// This reduces the chances of getting the same UUID, even when the same40// user runs the two copies of binary at the same time.41static std::string MakeUUID() {42  auto timestmap = std::chrono::steady_clock::now().time_since_epoch().count();43  UUID uuid = UUID::Generate();44  return llvm::formatv("{0}_{1}", uuid.GetAsString(), timestmap);45}46 47void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const {48  serializer.write("entry_kind", getKind());49  serializer.write("session_id", SessionId);50  serializer.write("start_time", ToNanosec(start_time));51  if (end_time.has_value())52    serializer.write("end_time", ToNanosec(end_time.value()));53}54 55void ClientInfo::serialize(Serializer &serializer) const {56  LLDBBaseTelemetryInfo::serialize(serializer);57  serializer.write("client_data", client_data);58  serializer.write("client_name", client_name);59  if (error_msg.has_value())60    serializer.write("error_msg", error_msg.value());61}62 63void CommandInfo::serialize(Serializer &serializer) const {64  LLDBBaseTelemetryInfo::serialize(serializer);65 66  serializer.write("target_uuid", target_uuid.GetAsString());67  serializer.write("command_id", command_id);68  serializer.write("command_name", command_name);69  if (original_command.has_value())70    serializer.write("original_command", original_command.value());71  if (args.has_value())72    serializer.write("args", args.value());73  if (ret_status.has_value())74    serializer.write("ret_status", ret_status.value());75  if (error_data.has_value())76    serializer.write("error_data", error_data.value());77}78 79std::atomic<uint64_t> CommandInfo::g_command_id_seed = 1;80uint64_t CommandInfo::GetNextID() { return g_command_id_seed.fetch_add(1); }81 82void DebuggerInfo::serialize(Serializer &serializer) const {83  LLDBBaseTelemetryInfo::serialize(serializer);84 85  serializer.write("lldb_version", lldb_version);86  serializer.write("is_exit_entry", is_exit_entry);87}88 89void ExecutableModuleInfo::serialize(Serializer &serializer) const {90  LLDBBaseTelemetryInfo::serialize(serializer);91 92  serializer.write("uuid", uuid.GetAsString());93  serializer.write("pid", pid);94  serializer.write("triple", triple);95  serializer.write("is_start_entry", is_start_entry);96}97 98void ProcessExitInfo::serialize(Serializer &serializer) const {99  LLDBBaseTelemetryInfo::serialize(serializer);100 101  serializer.write("module_uuid", module_uuid.GetAsString());102  serializer.write("pid", pid);103  serializer.write("is_start_entry", is_start_entry);104  if (exit_desc.has_value()) {105    serializer.write("exit_code", exit_desc->exit_code);106    serializer.write("exit_desc", exit_desc->description);107  }108}109 110TelemetryManager::TelemetryManager(std::unique_ptr<LLDBConfig> config)111    : m_config(std::move(config)), m_id(MakeUUID()) {}112 113llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) {114  // Assign the manager_id, and debugger_id, if available, to this entry.115  LLDBBaseTelemetryInfo *lldb_entry = llvm::cast<LLDBBaseTelemetryInfo>(entry);116  lldb_entry->SessionId = m_id;117  if (Debugger *debugger = lldb_entry->debugger)118    lldb_entry->debugger_id = debugger->GetID();119  return llvm::Error::success();120}121 122// Helper for extracting time field from a Dictionary.123static std::optional<std::chrono::nanoseconds>124GetAsNanosec(StructuredData::Dictionary *dict, llvm::StringRef key) {125  auto value = dict->GetValueForKey(key);126  if (!value->IsValid()) {127    LLDB_LOG(GetLog(LLDBLog::Object),128             "Cannot determine {0} from client-telemetry entry", key);129    return std::nullopt;130  }131 132  return std::chrono::nanoseconds(value->GetUnsignedIntegerValue(0));133}134 135void TelemetryManager::DispatchClientTelemetry(136    const lldb_private::StructuredDataImpl &entry, Debugger *debugger) {137  if (!m_config->enable_client_telemetry)138    return;139 140  ClientInfo client_info;141  client_info.debugger = debugger;142  if (entry.GetObjectSP()->GetType() != lldb::eStructuredDataTypeDictionary) {143    LLDB_LOG(GetLog(LLDBLog::Object), "Expected Dictionary type but got {0}.",144             entry.GetObjectSP()->GetType());145    return;146  }147 148  auto *dict = entry.GetObjectSP()->GetAsDictionary();149 150  llvm::StringRef client_name;151  if (dict->GetValueForKeyAsString("client_name", client_name))152    client_info.client_name = client_name.str();153  else154    LLDB_LOG(GetLog(LLDBLog::Object),155             "Cannot determine client_name from client-telemetry entry");156 157  llvm::StringRef client_data;158  if (dict->GetValueForKeyAsString("client_data", client_data))159    client_info.client_data = client_data.str();160  else161    LLDB_LOG(GetLog(LLDBLog::Object),162             "Cannot determine client_data from client-telemetry entry");163 164  if (auto maybe_start_time = GetAsNanosec(dict, "start_time"))165    client_info.start_time += *maybe_start_time;166 167  if (auto maybe_end_time = GetAsNanosec(dict, "end_time")) {168    SteadyTimePoint epoch;169    client_info.end_time = epoch + *maybe_end_time;170  }171 172  llvm::StringRef error_msg;173  if (dict->GetValueForKeyAsString("error", error_msg))174    client_info.error_msg = error_msg.str();175 176  if (llvm::Error er = dispatch(&client_info))177    LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er),178                   "Failed to dispatch client telemetry");179}180 181class NoOpTelemetryManager : public TelemetryManager {182public:183  llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override {184    // Does nothing.185    return llvm::Error::success();186  }187 188  explicit NoOpTelemetryManager()189      : TelemetryManager(std::make_unique<LLDBConfig>(190            /*EnableTelemetry=*/false, /*DetailedCommand=*/false,191            /*ClientTelemery=*/false)) {}192 193  virtual llvm::StringRef GetInstanceName() const override {194    return "NoOpTelemetryManager";195  }196 197  void DispatchClientTelemetry(const lldb_private::StructuredDataImpl &entry,198                               Debugger *debugger) override {199    // Does nothing.200  }201 202  llvm::Error dispatch(llvm::telemetry::TelemetryInfo *entry) override {203    // Does nothing.204    return llvm::Error::success();205  }206 207  static NoOpTelemetryManager *GetInstance() {208    static std::unique_ptr<NoOpTelemetryManager> g_ins =209        std::make_unique<NoOpTelemetryManager>();210    return g_ins.get();211  }212};213 214std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr;215TelemetryManager *TelemetryManager::GetInstance() {216  // If Telemetry is disabled or if there is no default instance, then use the217  // NoOp manager. We use a dummy instance to avoid having to do nullchecks in218  // various places.219  if (!Config::BuildTimeEnableTelemetry || !g_instance)220    return NoOpTelemetryManager::GetInstance();221  return g_instance.get();222}223 224void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) {225  if (Config::BuildTimeEnableTelemetry)226    g_instance = std::move(manager);227}228 229} // namespace telemetry230} // namespace lldb_private231