116 lines · cpp
1//===-- Diagnostics.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 9#include "lldb/Utility/Diagnostics.h"10#include "lldb/Utility/LLDBAssert.h"11 12#include "llvm/Support/Error.h"13#include "llvm/Support/FileSystem.h"14#include "llvm/Support/raw_ostream.h"15#include <optional>16 17using namespace lldb_private;18using namespace lldb;19using namespace llvm;20 21static constexpr size_t g_num_log_messages = 100;22 23void Diagnostics::Initialize() {24 lldbassert(!InstanceImpl() && "Already initialized.");25 InstanceImpl().emplace();26}27 28void Diagnostics::Terminate() {29 lldbassert(InstanceImpl() && "Already terminated.");30 InstanceImpl().reset();31}32 33bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }34 35std::optional<Diagnostics> &Diagnostics::InstanceImpl() {36 static std::optional<Diagnostics> g_diagnostics;37 return g_diagnostics;38}39 40Diagnostics &Diagnostics::Instance() { return *InstanceImpl(); }41 42Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {}43 44Diagnostics::~Diagnostics() {}45 46Diagnostics::CallbackID Diagnostics::AddCallback(Callback callback) {47 std::lock_guard<std::mutex> guard(m_callbacks_mutex);48 CallbackID id = m_callback_id++;49 m_callbacks.emplace_back(id, callback);50 return id;51}52 53void Diagnostics::RemoveCallback(CallbackID id) {54 std::lock_guard<std::mutex> guard(m_callbacks_mutex);55 llvm::erase_if(m_callbacks,56 [id](const CallbackEntry &e) { return e.id == id; });57}58 59bool Diagnostics::Dump(raw_ostream &stream) {60 Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory();61 if (!diagnostics_dir) {62 stream << "unable to create diagnostic dir: "63 << toString(diagnostics_dir.takeError()) << '\n';64 return false;65 }66 67 return Dump(stream, *diagnostics_dir);68}69 70bool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) {71 stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n";72 stream << "Please include the directory content when filing a bug report\n";73 74 if (Error error = Create(dir)) {75 stream << toString(std::move(error)) << '\n';76 return false;77 }78 79 return true;80}81 82llvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() {83 SmallString<128> diagnostics_dir;84 std::error_code ec =85 sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir);86 if (ec)87 return errorCodeToError(ec);88 return FileSpec(diagnostics_dir.str());89}90 91Error Diagnostics::Create(const FileSpec &dir) {92 if (Error err = DumpDiangosticsLog(dir))93 return err;94 95 for (CallbackEntry e : m_callbacks) {96 if (Error err = e.callback(dir))97 return err;98 }99 100 return Error::success();101}102 103llvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const {104 FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log");105 std::error_code ec;106 llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None);107 if (ec)108 return errorCodeToError(ec);109 m_log_handler.Dump(stream);110 return Error::success();111}112 113void Diagnostics::Report(llvm::StringRef message) {114 m_log_handler.Emit(message);115}116