Hoist UUID generation into the UUID class and add a trivial unit test. This also changes the telemetry code to drop the double underscore if we failed to generate a UUID and subsequently logs to the Host instead of Object log channel.
159 lines
5.4 KiB
C++
159 lines
5.4 KiB
C++
//===-- Telemetry.cpp -----------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "lldb/Core/Telemetry.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/Telemetry.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
#include "lldb/Utility/UUID.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
#include "lldb/lldb-forward.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/RandomNumberGenerator.h"
|
|
#include "llvm/Telemetry/Telemetry.h"
|
|
#include <chrono>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
namespace lldb_private {
|
|
namespace telemetry {
|
|
|
|
using namespace llvm::telemetry;
|
|
|
|
static uint64_t ToNanosec(const SteadyTimePoint Point) {
|
|
return std::chrono::nanoseconds(Point.time_since_epoch()).count();
|
|
}
|
|
|
|
// Generate a unique string. This should be unique across different runs.
|
|
// We build such string by combining three parts:
|
|
// <16 random bytes>_<timestamp>
|
|
// This reduces the chances of getting the same UUID, even when the same
|
|
// user runs the two copies of binary at the same time.
|
|
static std::string MakeUUID() {
|
|
auto timestmap = std::chrono::steady_clock::now().time_since_epoch().count();
|
|
UUID uuid = UUID::Generate();
|
|
return llvm::formatv("{0}_{1}", uuid.GetAsString(), timestmap);
|
|
}
|
|
|
|
void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const {
|
|
serializer.write("entry_kind", getKind());
|
|
serializer.write("session_id", SessionId);
|
|
serializer.write("start_time", ToNanosec(start_time));
|
|
if (end_time.has_value())
|
|
serializer.write("end_time", ToNanosec(end_time.value()));
|
|
}
|
|
|
|
void CommandInfo::serialize(Serializer &serializer) const {
|
|
LLDBBaseTelemetryInfo::serialize(serializer);
|
|
|
|
serializer.write("target_uuid", target_uuid.GetAsString());
|
|
serializer.write("command_id", command_id);
|
|
serializer.write("command_name", command_name);
|
|
if (original_command.has_value())
|
|
serializer.write("original_command", original_command.value());
|
|
if (args.has_value())
|
|
serializer.write("args", args.value());
|
|
if (ret_status.has_value())
|
|
serializer.write("ret_status", ret_status.value());
|
|
if (error_data.has_value())
|
|
serializer.write("error_data", error_data.value());
|
|
}
|
|
|
|
std::atomic<uint64_t> CommandInfo::g_command_id_seed = 1;
|
|
uint64_t CommandInfo::GetNextID() { return g_command_id_seed.fetch_add(1); }
|
|
|
|
void DebuggerInfo::serialize(Serializer &serializer) const {
|
|
LLDBBaseTelemetryInfo::serialize(serializer);
|
|
|
|
serializer.write("lldb_version", lldb_version);
|
|
serializer.write("is_exit_entry", is_exit_entry);
|
|
}
|
|
|
|
void ExecutableModuleInfo::serialize(Serializer &serializer) const {
|
|
LLDBBaseTelemetryInfo::serialize(serializer);
|
|
|
|
serializer.write("uuid", uuid.GetAsString());
|
|
serializer.write("pid", pid);
|
|
serializer.write("triple", triple);
|
|
serializer.write("is_start_entry", is_start_entry);
|
|
}
|
|
|
|
void ProcessExitInfo::serialize(Serializer &serializer) const {
|
|
LLDBBaseTelemetryInfo::serialize(serializer);
|
|
|
|
serializer.write("module_uuid", module_uuid.GetAsString());
|
|
serializer.write("pid", pid);
|
|
serializer.write("is_start_entry", is_start_entry);
|
|
if (exit_desc.has_value()) {
|
|
serializer.write("exit_code", exit_desc->exit_code);
|
|
serializer.write("exit_desc", exit_desc->description);
|
|
}
|
|
}
|
|
|
|
TelemetryManager::TelemetryManager(std::unique_ptr<LLDBConfig> config)
|
|
: m_config(std::move(config)), m_id(MakeUUID()) {}
|
|
|
|
llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) {
|
|
// Assign the manager_id, and debugger_id, if available, to this entry.
|
|
LLDBBaseTelemetryInfo *lldb_entry = llvm::cast<LLDBBaseTelemetryInfo>(entry);
|
|
lldb_entry->SessionId = m_id;
|
|
if (Debugger *debugger = lldb_entry->debugger)
|
|
lldb_entry->debugger_id = debugger->GetID();
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
class NoOpTelemetryManager : public TelemetryManager {
|
|
public:
|
|
llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override {
|
|
// Does nothing.
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
explicit NoOpTelemetryManager()
|
|
: TelemetryManager(std::make_unique<LLDBConfig>(
|
|
/*EnableTelemetry*/ false, /*DetailedCommand*/ false)) {}
|
|
|
|
virtual llvm::StringRef GetInstanceName() const override {
|
|
return "NoOpTelemetryManager";
|
|
}
|
|
|
|
llvm::Error dispatch(llvm::telemetry::TelemetryInfo *entry) override {
|
|
// Does nothing.
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
static NoOpTelemetryManager *GetInstance() {
|
|
static std::unique_ptr<NoOpTelemetryManager> g_ins =
|
|
std::make_unique<NoOpTelemetryManager>();
|
|
return g_ins.get();
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr;
|
|
TelemetryManager *TelemetryManager::GetInstance() {
|
|
// If Telemetry is disabled or if there is no default instance, then use the
|
|
// NoOp manager. We use a dummy instance to avoid having to do nullchecks in
|
|
// various places.
|
|
if (!Config::BuildTimeEnableTelemetry || !g_instance)
|
|
return NoOpTelemetryManager::GetInstance();
|
|
return g_instance.get();
|
|
}
|
|
|
|
void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) {
|
|
if (Config::BuildTimeEnableTelemetry)
|
|
g_instance = std::move(manager);
|
|
}
|
|
|
|
} // namespace telemetry
|
|
} // namespace lldb_private
|