1 //===-- Diagnostics.cpp ---------------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/Diagnostics.h"
10 #include "lldb/Utility/LLDBAssert.h"
12 #include "llvm/Support/Error.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/raw_ostream.h"
17 using namespace lldb_private
;
21 static constexpr size_t g_num_log_messages
= 100;
23 void Diagnostics::Initialize() {
24 lldbassert(!InstanceImpl() && "Already initialized.");
25 InstanceImpl().emplace();
28 void Diagnostics::Terminate() {
29 lldbassert(InstanceImpl() && "Already terminated.");
30 InstanceImpl().reset();
33 bool Diagnostics::Enabled() { return InstanceImpl().operator bool(); }
35 std::optional
<Diagnostics
> &Diagnostics::InstanceImpl() {
36 static std::optional
<Diagnostics
> g_diagnostics
;
40 Diagnostics
&Diagnostics::Instance() { return *InstanceImpl(); }
42 Diagnostics::Diagnostics() : m_log_handler(g_num_log_messages
) {}
44 Diagnostics::~Diagnostics() {}
46 Diagnostics::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
);
53 void 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
; });
59 bool 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';
67 return Dump(stream
, *diagnostics_dir
);
70 bool 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";
74 if (Error error
= Create(dir
)) {
75 stream
<< toString(std::move(error
)) << '\n';
82 llvm::Expected
<FileSpec
> Diagnostics::CreateUniqueDirectory() {
83 SmallString
<128> diagnostics_dir
;
85 sys::fs::createUniqueDirectory("diagnostics", diagnostics_dir
);
87 return errorCodeToError(ec
);
88 return FileSpec(diagnostics_dir
.str());
91 Error
Diagnostics::Create(const FileSpec
&dir
) {
92 if (Error err
= DumpDiangosticsLog(dir
))
95 for (CallbackEntry e
: m_callbacks
) {
96 if (Error err
= e
.callback(dir
))
100 return Error::success();
103 llvm::Error
Diagnostics::DumpDiangosticsLog(const FileSpec
&dir
) const {
104 FileSpec log_file
= dir
.CopyByAppendingPathComponent("diagnostics.log");
106 llvm::raw_fd_ostream
stream(log_file
.GetPath(), ec
, llvm::sys::fs::OF_None
);
108 return errorCodeToError(ec
);
109 m_log_handler
.Dump(stream
);
110 return Error::success();
113 void Diagnostics::Report(llvm::StringRef message
) {
114 m_log_handler
.Emit(message
);