1bdd1243dSDimitry Andric //===-- Diagnostics.cpp ---------------------------------------------------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric 9bdd1243dSDimitry Andric #include "lldb/Utility/Diagnostics.h" 10bdd1243dSDimitry Andric #include "lldb/Utility/LLDBAssert.h" 11bdd1243dSDimitry Andric 12bdd1243dSDimitry Andric #include "llvm/Support/Error.h" 13bdd1243dSDimitry Andric #include "llvm/Support/FileSystem.h" 14bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 15bdd1243dSDimitry Andric #include <optional> 16bdd1243dSDimitry Andric 17bdd1243dSDimitry Andric using namespace lldb_private; 18bdd1243dSDimitry Andric using namespace lldb; 19bdd1243dSDimitry Andric using namespace llvm; 20bdd1243dSDimitry Andric 21bdd1243dSDimitry Andric static constexpr size_t g_num_log_messages = 100; 22bdd1243dSDimitry Andric Initialize()23bdd1243dSDimitry Andricvoid Diagnostics::Initialize() { 24bdd1243dSDimitry Andric lldbassert(!InstanceImpl() && "Already initialized."); 25bdd1243dSDimitry Andric InstanceImpl().emplace(); 26bdd1243dSDimitry Andric } 27bdd1243dSDimitry Andric Terminate()28bdd1243dSDimitry Andricvoid Diagnostics::Terminate() { 29bdd1243dSDimitry Andric lldbassert(InstanceImpl() && "Already terminated."); 30bdd1243dSDimitry Andric InstanceImpl().reset(); 31bdd1243dSDimitry Andric } 32bdd1243dSDimitry Andric Enabled()33bdd1243dSDimitry Andricbool Diagnostics::Enabled() { return InstanceImpl().operator bool(); } 34bdd1243dSDimitry Andric InstanceImpl()35bdd1243dSDimitry Andricstd::optional<Diagnostics> &Diagnostics::InstanceImpl() { 36bdd1243dSDimitry Andric static std::optional<Diagnostics> g_diagnostics; 37bdd1243dSDimitry Andric return g_diagnostics; 38bdd1243dSDimitry Andric } 39bdd1243dSDimitry Andric Instance()40bdd1243dSDimitry AndricDiagnostics &Diagnostics::Instance() { return *InstanceImpl(); } 41bdd1243dSDimitry Andric Diagnostics()42bdd1243dSDimitry AndricDiagnostics::Diagnostics() : m_log_handler(g_num_log_messages) {} 43bdd1243dSDimitry Andric ~Diagnostics()44bdd1243dSDimitry AndricDiagnostics::~Diagnostics() {} 45bdd1243dSDimitry Andric AddCallback(Callback callback)4606c3fb27SDimitry AndricDiagnostics::CallbackID Diagnostics::AddCallback(Callback callback) { 47bdd1243dSDimitry Andric std::lock_guard<std::mutex> guard(m_callbacks_mutex); 4806c3fb27SDimitry Andric CallbackID id = m_callback_id++; 4906c3fb27SDimitry Andric m_callbacks.emplace_back(id, callback); 5006c3fb27SDimitry Andric return id; 5106c3fb27SDimitry Andric } 5206c3fb27SDimitry Andric RemoveCallback(CallbackID id)5306c3fb27SDimitry Andricvoid Diagnostics::RemoveCallback(CallbackID id) { 5406c3fb27SDimitry Andric std::lock_guard<std::mutex> guard(m_callbacks_mutex); 55*5f757f3fSDimitry Andric llvm::erase_if(m_callbacks, 56*5f757f3fSDimitry Andric [id](const CallbackEntry &e) { return e.id == id; }); 57bdd1243dSDimitry Andric } 58bdd1243dSDimitry Andric Dump(raw_ostream & stream)59bdd1243dSDimitry Andricbool Diagnostics::Dump(raw_ostream &stream) { 60bdd1243dSDimitry Andric Expected<FileSpec> diagnostics_dir = CreateUniqueDirectory(); 61bdd1243dSDimitry Andric if (!diagnostics_dir) { 62bdd1243dSDimitry Andric stream << "unable to create diagnostic dir: " 63bdd1243dSDimitry Andric << toString(diagnostics_dir.takeError()) << '\n'; 64bdd1243dSDimitry Andric return false; 65bdd1243dSDimitry Andric } 66bdd1243dSDimitry Andric 67bdd1243dSDimitry Andric return Dump(stream, *diagnostics_dir); 68bdd1243dSDimitry Andric } 69bdd1243dSDimitry Andric Dump(raw_ostream & stream,const FileSpec & dir)70bdd1243dSDimitry Andricbool Diagnostics::Dump(raw_ostream &stream, const FileSpec &dir) { 71bdd1243dSDimitry Andric stream << "LLDB diagnostics will be written to " << dir.GetPath() << "\n"; 72bdd1243dSDimitry Andric stream << "Please include the directory content when filing a bug report\n"; 73bdd1243dSDimitry Andric 74bdd1243dSDimitry Andric if (Error error = Create(dir)) { 75bdd1243dSDimitry Andric stream << toString(std::move(error)) << '\n'; 76bdd1243dSDimitry Andric return false; 77bdd1243dSDimitry Andric } 78bdd1243dSDimitry Andric 79bdd1243dSDimitry Andric return true; 80bdd1243dSDimitry Andric } 81bdd1243dSDimitry Andric CreateUniqueDirectory()82bdd1243dSDimitry Andricllvm::Expected<FileSpec> Diagnostics::CreateUniqueDirectory() { 83bdd1243dSDimitry Andric SmallString<128> diagnostics_dir; 84bdd1243dSDimitry Andric std::error_code ec = 85bdd1243dSDimitry Andric sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir); 86bdd1243dSDimitry Andric if (ec) 87bdd1243dSDimitry Andric return errorCodeToError(ec); 88bdd1243dSDimitry Andric return FileSpec(diagnostics_dir.str()); 89bdd1243dSDimitry Andric } 90bdd1243dSDimitry Andric Create(const FileSpec & dir)91bdd1243dSDimitry AndricError Diagnostics::Create(const FileSpec &dir) { 92bdd1243dSDimitry Andric if (Error err = DumpDiangosticsLog(dir)) 93bdd1243dSDimitry Andric return err; 94bdd1243dSDimitry Andric 9506c3fb27SDimitry Andric for (CallbackEntry e : m_callbacks) { 9606c3fb27SDimitry Andric if (Error err = e.callback(dir)) 97bdd1243dSDimitry Andric return err; 98bdd1243dSDimitry Andric } 99bdd1243dSDimitry Andric 100bdd1243dSDimitry Andric return Error::success(); 101bdd1243dSDimitry Andric } 102bdd1243dSDimitry Andric DumpDiangosticsLog(const FileSpec & dir) const103bdd1243dSDimitry Andricllvm::Error Diagnostics::DumpDiangosticsLog(const FileSpec &dir) const { 104bdd1243dSDimitry Andric FileSpec log_file = dir.CopyByAppendingPathComponent("diagnostics.log"); 105bdd1243dSDimitry Andric std::error_code ec; 106bdd1243dSDimitry Andric llvm::raw_fd_ostream stream(log_file.GetPath(), ec, llvm::sys::fs::OF_None); 107bdd1243dSDimitry Andric if (ec) 108bdd1243dSDimitry Andric return errorCodeToError(ec); 109bdd1243dSDimitry Andric m_log_handler.Dump(stream); 110bdd1243dSDimitry Andric return Error::success(); 111bdd1243dSDimitry Andric } 112bdd1243dSDimitry Andric Report(llvm::StringRef message)113bdd1243dSDimitry Andricvoid Diagnostics::Report(llvm::StringRef message) { 114bdd1243dSDimitry Andric m_log_handler.Emit(message); 115bdd1243dSDimitry Andric } 116