diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 6971bfea5c128..58c9922214583 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -122,7 +122,7 @@ static std::string capitalize(llvm::StringRef str) { llvm::StringRef DAP::debug_adapter_path = ""; -DAP::DAP(Log *log, const ReplMode default_repl_mode, +DAP::DAP(Log &log, const ReplMode default_repl_mode, std::vector pre_init_commands, bool no_lldbinit, llvm::StringRef client_name, DAPTransport &transport, MainLoop &loop) : log(log), transport(transport), broadcaster("lldb-dap"), @@ -134,8 +134,6 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, RegisterRequests(); } -DAP::~DAP() = default; - void DAP::PopulateExceptionBreakpoints() { if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) { exception_breakpoints.emplace_back(*this, "cpp_catch", "C++ Catch", @@ -263,8 +261,7 @@ void DAP::SendJSON(const llvm::json::Value &json) { Message message; llvm::json::Path::Root root; if (!fromJSON(json, message, root)) { - DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}", - m_client_name); + DAP_LOG_ERROR(log, root.getError(), "encoding failed: {0}"); return; } Send(message); @@ -285,15 +282,13 @@ Id DAP::Send(const Message &message) { if (const protocol::Event *event = std::get_if(&msg)) { if (llvm::Error err = transport.Send(*event)) - DAP_LOG_ERROR(log, std::move(err), "({0}) sending event failed", - m_client_name); + DAP_LOG_ERROR(log, std::move(err), "sending event failed: {0}"); return event->seq; } if (const Request *req = std::get_if(&msg)) { if (llvm::Error err = transport.Send(*req)) - DAP_LOG_ERROR(log, std::move(err), "({0}) sending request failed", - m_client_name); + DAP_LOG_ERROR(log, std::move(err), "sending request failed: {0}"); return req->seq; } @@ -313,8 +308,7 @@ Id DAP::Send(const Message &message) { }) : transport.Send(*resp); if (err) - DAP_LOG_ERROR(log, std::move(err), "({0}) sending response failed", - m_client_name); + DAP_LOG_ERROR(log, std::move(err), "sending response failed: {0}"); return resp->seq; } @@ -857,8 +851,7 @@ bool DAP::HandleObject(const Message &M) { dispatcher.Set("error", llvm::Twine("unhandled-command:" + req->command).str()); - DAP_LOG(log, "({0}) error: unhandled command '{1}'", m_client_name, - req->command); + DAP_LOG(log, "error: unhandled command '{0}'", req->command); return false; // Fail } @@ -1004,35 +997,33 @@ void DAP::Received(const protocol::Request &request) { // effort attempt to interrupt. std::lock_guard guard(m_active_request_mutex); if (m_active_request && cancel_args->requestId == m_active_request->seq) { - DAP_LOG(log, "({0}) interrupting inflight request (command={1} seq={2})", - m_client_name, m_active_request->command, m_active_request->seq); + DAP_LOG(log, "interrupting inflight request (command={0} seq={1})", + m_active_request->command, m_active_request->seq); debugger.RequestInterrupt(); } } std::lock_guard guard(m_queue_mutex); - DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, - request.command, request.seq); + DAP_LOG(log, "queued (command={0} seq={1})", request.command, request.seq); m_queue.push_back(request); m_queue_cv.notify_one(); } void DAP::Received(const protocol::Response &response) { std::lock_guard guard(m_queue_mutex); - DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, - response.command, response.request_seq); + DAP_LOG(log, "queued (command={0} seq={1})", response.command, + response.request_seq); m_queue.push_back(response); m_queue_cv.notify_one(); } void DAP::OnError(llvm::Error error) { - DAP_LOG_ERROR(log, std::move(error), "({1}) received error: {0}", - m_client_name); + DAP_LOG_ERROR(log, std::move(error), "transport error: {0}"); TerminateLoop(/*failed=*/true); } void DAP::OnClosed() { - DAP_LOG(log, "({0}) received EOF", m_client_name); + DAP_LOG(log, "transport closed"); TerminateLoop(); } @@ -1058,16 +1049,14 @@ void DAP::TransportHandler() { auto handle = transport.RegisterMessageHandler(m_loop, *this); if (!handle) { DAP_LOG_ERROR(log, handle.takeError(), - "({1}) registering message handler failed: {0}", - m_client_name); + "registering message handler failed: {0}"); std::lock_guard guard(m_queue_mutex); m_error_occurred = true; return; } if (Status status = m_loop.Run(); status.Fail()) { - DAP_LOG_ERROR(log, status.takeError(), "({1}) MainLoop run failed: {0}", - m_client_name); + DAP_LOG_ERROR(log, status.takeError(), "MainLoop run failed: {0}"); std::lock_guard guard(m_queue_mutex); m_error_occurred = true; return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b5f2a57d9dc5f..01139221ea37f 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -33,11 +33,9 @@ #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/Host/MainLoop.h" -#include "lldb/Utility/Status.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -88,7 +86,7 @@ struct DAP final : public DAPTransport::MessageHandler { /// Path to the lldb-dap binary itself. static llvm::StringRef debug_adapter_path; - Log *log; + Log &log; DAPTransport &transport; lldb::SBFile in; OutputRedirector out; @@ -194,12 +192,12 @@ struct DAP final : public DAPTransport::MessageHandler { /// Transport for this debug session. /// \param[in] loop /// Main loop associated with this instance. - DAP(Log *log, const ReplMode default_repl_mode, + DAP(Log &log, const ReplMode default_repl_mode, std::vector pre_init_commands, bool no_lldbinit, llvm::StringRef client_name, DAPTransport &transport, lldb_private::MainLoop &loop); - ~DAP(); + ~DAP() override = default; /// DAP is not copyable. /// @{ diff --git a/lldb/tools/lldb-dap/DAPLog.cpp b/lldb/tools/lldb-dap/DAPLog.cpp index 34d26128efd3f..f3c804008e4b5 100644 --- a/lldb/tools/lldb-dap/DAPLog.cpp +++ b/lldb/tools/lldb-dap/DAPLog.cpp @@ -9,21 +9,26 @@ #include "DAPLog.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Chrono.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include #include -#include using namespace llvm; namespace lldb_dap { -Log::Log(StringRef filename, std::error_code &EC) : m_stream(filename, EC) {} +void Log::Emit(StringRef message) { Emit(message, "", 0); } -void Log::WriteMessage(StringRef message) { - std::lock_guard lock(m_mutex); +void Log::Emit(StringRef message, StringRef file, size_t line) { + std::lock_guard lock(m_mutex); const llvm::sys::TimePoint<> time = std::chrono::system_clock::now(); - m_stream << formatv("[{0:%H:%M:%S.%L}] ", time) << message << '\n'; + m_stream << formatv("[{0:%H:%M:%S.%L}]", time) << " "; + if (!file.empty()) + m_stream << sys::path::filename(file) << ":" << line << " "; + if (!m_prefix.empty()) + m_stream << m_prefix; + m_stream << message << "\n"; m_stream.flush(); } diff --git a/lldb/tools/lldb-dap/DAPLog.h b/lldb/tools/lldb-dap/DAPLog.h index 484001a9b1628..2170e6621d691 100644 --- a/lldb/tools/lldb-dap/DAPLog.h +++ b/lldb/tools/lldb-dap/DAPLog.h @@ -11,33 +11,28 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include #include -#include // Write a message to log, if logging is enabled. #define DAP_LOG(log, ...) \ do { \ - ::lldb_dap::Log *log_private = (log); \ - if (log_private) { \ - log_private->WriteMessage(::llvm::formatv(__VA_ARGS__).str()); \ - } \ + ::lldb_dap::Log &log_private = (log); \ + log_private.Emit(::llvm::formatv(__VA_ARGS__).str(), __FILE__, __LINE__); \ } while (0) // Write message to log, if error is set. In the log message refer to the error // with {0}. Error is cleared regardless of whether logging is enabled. #define DAP_LOG_ERROR(log, error, ...) \ do { \ - ::lldb_dap::Log *log_private = (log); \ + ::lldb_dap::Log &log_private = (log); \ ::llvm::Error error_private = (error); \ - if (log_private && error_private) { \ - log_private->WriteMessage( \ - ::lldb_dap::FormatError(::std::move(error_private), __VA_ARGS__)); \ - } else \ - ::llvm::consumeError(::std::move(error_private)); \ + if (error_private) \ + log_private.Emit( \ + ::lldb_dap::FormatError(::std::move(error_private), __VA_ARGS__), \ + __FILE__, __LINE__); \ } while (0) namespace lldb_dap { @@ -46,14 +41,32 @@ namespace lldb_dap { /// `DAP_LOG_ERROR` helpers. class Log final { public: - /// Creates a log file with the given filename. - Log(llvm::StringRef filename, std::error_code &EC); + using Mutex = std::mutex; - void WriteMessage(llvm::StringRef message); + Log(llvm::raw_ostream &stream, Mutex &mutex) + : m_stream(stream), m_mutex(mutex) {} + Log(llvm::StringRef prefix, const Log &log) + : m_prefix(prefix), m_stream(log.m_stream), m_mutex(log.m_mutex) {} + + /// Retuns a new Log instance with the associated prefix for all messages. + inline Log WithPrefix(llvm::StringRef prefix) const { + std::string full_prefix = + m_prefix.empty() ? prefix.str() : m_prefix + prefix.str(); + full_prefix += " "; + return Log(full_prefix, *this); + } + + /// Emit writes a message to the underlying stream. + void Emit(llvm::StringRef message); + + /// Emit writes a message to the underlying stream, including the file and + /// line the message originated from. + void Emit(llvm::StringRef message, llvm::StringRef file, size_t line); private: - std::mutex m_mutex; - llvm::raw_fd_ostream m_stream; + std::string m_prefix; + llvm::raw_ostream &m_stream; + Mutex &m_mutex; }; template diff --git a/lldb/tools/lldb-dap/DAPSessionManager.cpp b/lldb/tools/lldb-dap/DAPSessionManager.cpp index d5440ffd64597..3fbdc26fc4cda 100644 --- a/lldb/tools/lldb-dap/DAPSessionManager.cpp +++ b/lldb/tools/lldb-dap/DAPSessionManager.cpp @@ -110,7 +110,8 @@ DAPSessionManager::GetEventThreadForDebugger(lldb::SBDebugger debugger, auto new_thread_sp = std::make_shared( requesting_dap->broadcaster, std::thread(EventThread, debugger, requesting_dap->broadcaster, - requesting_dap->m_client_name, requesting_dap->log)); + requesting_dap->m_client_name, + std::ref(requesting_dap->log))); m_debugger_event_threads[debugger_id] = new_thread_sp; return new_thread_sp; } diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index bdb6bb55fe168..01d4547e2d228 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -324,8 +324,8 @@ void SendMemoryEvent(DAP &dap, lldb::SBValue variable) { // the original DAP::Handle*Event pattern while supporting multi-session // debugging. -void HandleProcessEvent(const lldb::SBEvent &event, bool &process_exited, - Log *log) { +static void HandleProcessEvent(const lldb::SBEvent &event, bool &process_exited, + Log &log) { lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event); // Find the DAP instance that owns this process's target. @@ -393,7 +393,7 @@ void HandleProcessEvent(const lldb::SBEvent &event, bool &process_exited, } } -void HandleTargetEvent(const lldb::SBEvent &event, Log *log) { +static void HandleTargetEvent(const lldb::SBEvent &event, Log &log) { lldb::SBTarget target = lldb::SBTarget::GetTargetFromEvent(event); // Find the DAP instance that owns this target. @@ -480,7 +480,7 @@ void HandleTargetEvent(const lldb::SBEvent &event, Log *log) { } } -void HandleBreakpointEvent(const lldb::SBEvent &event, Log *log) { +static void HandleBreakpointEvent(const lldb::SBEvent &event, Log &log) { const uint32_t event_mask = event.GetType(); if (!(event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged)) return; @@ -529,7 +529,7 @@ void HandleBreakpointEvent(const lldb::SBEvent &event, Log *log) { } } -void HandleThreadEvent(const lldb::SBEvent &event, Log *log) { +static void HandleThreadEvent(const lldb::SBEvent &event, Log &log) { uint32_t event_type = event.GetType(); if (!(event_type & lldb::SBThread::eBroadcastBitStackChanged)) @@ -550,7 +550,7 @@ void HandleThreadEvent(const lldb::SBEvent &event, Log *log) { thread.GetThreadID()); } -void HandleDiagnosticEvent(const lldb::SBEvent &event, Log *log) { +static void HandleDiagnosticEvent(const lldb::SBEvent &event, Log &log) { // Global debugger events - send to all DAP instances. std::vector active_instances = DAPSessionManager::GetInstance().GetActiveSessions(); @@ -588,7 +588,7 @@ void HandleDiagnosticEvent(const lldb::SBEvent &event, Log *log) { // them prevent multiple threads from writing simultaneously so no locking // is required. void EventThread(lldb::SBDebugger debugger, lldb::SBBroadcaster broadcaster, - llvm::StringRef client_name, Log *log) { + llvm::StringRef client_name, Log &log) { llvm::set_thread_name("lldb.DAP.client." + client_name + ".event_handler"); lldb::SBListener listener = debugger.GetListener(); broadcaster.AddListener(listener, eBroadcastBitStopEventThread); diff --git a/lldb/tools/lldb-dap/EventHelper.h b/lldb/tools/lldb-dap/EventHelper.h index 3beba2629b2e3..b46d5aef3581f 100644 --- a/lldb/tools/lldb-dap/EventHelper.h +++ b/lldb/tools/lldb-dap/EventHelper.h @@ -51,16 +51,7 @@ void SendMemoryEvent(DAP &dap, lldb::SBValue variable); /// \param client_name The client name for thread naming/logging purposes. /// \param log The log instance for logging. void EventThread(lldb::SBDebugger debugger, lldb::SBBroadcaster broadcaster, - llvm::StringRef client_name, Log *log); - -/// Event handler functions called by EventThread. -/// These handlers extract the necessary objects from events and find the -/// appropriate DAP instance to handle them. -void HandleProcessEvent(const lldb::SBEvent &event, bool &done, Log *log); -void HandleTargetEvent(const lldb::SBEvent &event, Log *log); -void HandleBreakpointEvent(const lldb::SBEvent &event, Log *log); -void HandleThreadEvent(const lldb::SBEvent &event, Log *log); -void HandleDiagnosticEvent(const lldb::SBEvent &event, Log *log); + llvm::StringRef client_name, Log &log); } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Transport.cpp b/lldb/tools/lldb-dap/Transport.cpp index 8f71f88cae1f7..b3512385d6579 100644 --- a/lldb/tools/lldb-dap/Transport.cpp +++ b/lldb/tools/lldb-dap/Transport.cpp @@ -17,13 +17,13 @@ using namespace lldb_private; namespace lldb_dap { -Transport::Transport(llvm::StringRef client_name, lldb_dap::Log *log, - lldb::IOObjectSP input, lldb::IOObjectSP output) - : HTTPDelimitedJSONTransport(input, output), m_client_name(client_name), - m_log(log) {} +Transport::Transport(lldb_dap::Log &log, lldb::IOObjectSP input, + lldb::IOObjectSP output) + : HTTPDelimitedJSONTransport(input, output), m_log(log) {} void Transport::Log(llvm::StringRef message) { - DAP_LOG(m_log, "({0}) {1}", m_client_name, message); + // Emit the message directly, since this log was forwarded. + m_log.Emit(message); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Transport.h b/lldb/tools/lldb-dap/Transport.h index 58c48c133f9cb..b20a93475d2dd 100644 --- a/lldb/tools/lldb-dap/Transport.h +++ b/lldb/tools/lldb-dap/Transport.h @@ -35,15 +35,14 @@ class Transport final : public lldb_private::transport::HTTPDelimitedJSONTransport< ProtocolDescriptor> { public: - Transport(llvm::StringRef client_name, lldb_dap::Log *log, - lldb::IOObjectSP input, lldb::IOObjectSP output); + Transport(lldb_dap::Log &log, lldb::IOObjectSP input, + lldb::IOObjectSP output); virtual ~Transport() = default; void Log(llvm::StringRef message) override; private: - llvm::StringRef m_client_name; - lldb_dap::Log *m_log; + lldb_dap::Log &m_log; }; } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp index 27516b2a25678..6d4eaf18de7ea 100644 --- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp @@ -11,6 +11,7 @@ #include "DAPLog.h" #include "EventHelper.h" #include "Handler/RequestHandler.h" +#include "Handler/ResponseHandler.h" #include "RunInTerminal.h" #include "Transport.h" #include "lldb/API/SBDebugger.h" @@ -50,9 +51,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -410,7 +409,7 @@ validateConnection(llvm::StringRef conn) { } static llvm::Error serveConnection( - const Socket::SocketProtocol &protocol, const std::string &name, Log *log, + const Socket::SocketProtocol &protocol, llvm::StringRef name, Log &log, const ReplMode default_repl_mode, const std::vector &pre_init_commands, bool no_lldbinit, std::optional connection_timeout_seconds) { @@ -446,7 +445,7 @@ static llvm::Error serveConnection( connection_timeout_seconds.value()); std::condition_variable dap_sessions_condition; unsigned int clientCount = 0; - auto handle = listener->Accept(g_loop, [=, &clientCount]( + auto handle = listener->Accept(g_loop, [=, &log, &clientCount]( std::unique_ptr sock) { // Reset the keep alive timer, because we won't be killing the server // while this connection is being served. @@ -454,17 +453,19 @@ static llvm::Error serveConnection( ResetConnectionTimeout(g_connection_timeout_mutex, g_connection_timeout_time_point); std::string client_name = llvm::formatv("client_{0}", clientCount++).str(); - DAP_LOG(log, "({0}) client connected", client_name); - lldb::IOObjectSP io(std::move(sock)); // Move the client into a background thread to unblock accepting the next // client. - std::thread client([=]() { + std::thread client([=, &log]() { llvm::set_thread_name(client_name + ".runloop"); + + Log client_log = log.WithPrefix("(" + client_name + ")"); + DAP_LOG(client_log, "client connected"); + MainLoop loop; - Transport transport(client_name, log, io, io); - DAP dap(log, default_repl_mode, pre_init_commands, no_lldbinit, + Transport transport(client_log, io, io); + DAP dap(client_log, default_repl_mode, pre_init_commands, no_lldbinit, client_name, transport, loop); if (auto Err = dap.ConfigureIO()) { @@ -482,7 +483,7 @@ static llvm::Error serveConnection( ") error: "); } - DAP_LOG(log, "({0}) client disconnected", client_name); + DAP_LOG(client_log, "client disconnected"); // Unregister the DAP session from the global manager. DAPSessionManager::GetInstance().UnregisterSession(&loop); // Start the countdown to kill the server at the end of each connection. @@ -503,9 +504,7 @@ static llvm::Error serveConnection( return status.takeError(); } - DAP_LOG( - log, - "lldb-dap server shutdown requested, disconnecting remaining clients..."); + DAP_LOG(log, "server shutting down, disconnecting remaining clients"); // Disconnect all active sessions using the global manager. DAPSessionManager::GetInstance().DisconnectAllSessions(); @@ -642,17 +641,19 @@ int main(int argc, char *argv[]) { } #endif - std::unique_ptr log = nullptr; - const char *log_file_path = getenv("LLDBDAP_LOG"); - if (log_file_path) { - std::error_code EC; - log = std::make_unique(log_file_path, EC); - if (EC) { - llvm::logAllUnhandledErrors(llvm::errorCodeToError(EC), llvm::errs(), - "Failed to create log file: "); + std::unique_ptr log_os; + if (const char *log_file_path = getenv("LLDBDAP_LOG"); log_file_path) { + int FD; + if (std::error_code EC = + llvm::sys::fs::openFileForWrite(log_file_path, FD)) { + llvm::errs() << "Failed to open log file: " << log_file_path << ": " + << EC.message() << "\n"; return EXIT_FAILURE; } + log_os = std::make_unique(FD, /*shouldClose=*/true); } + Log::Mutex mutex; + Log log(log_os ? *log_os : llvm::nulls(), mutex); // Initialize LLDB first before we do anything. lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling(); @@ -666,7 +667,7 @@ int main(int argc, char *argv[]) { // Create a memory monitor. This can return nullptr if the host platform is // not supported. std::unique_ptr memory_monitor = - lldb_private::MemoryMonitor::Create([log = log.get()]() { + lldb_private::MemoryMonitor::Create([&log]() { DAP_LOG(log, "memory pressure detected"); lldb::SBDebugger::MemoryPressureDetected(); }); @@ -700,7 +701,7 @@ int main(int argc, char *argv[]) { Socket::SocketProtocol protocol; std::string name; std::tie(protocol, name) = *maybeProtoclAndName; - if (auto Err = serveConnection(protocol, name, log.get(), default_repl_mode, + if (auto Err = serveConnection(protocol, name, log, default_repl_mode, pre_init_commands, no_lldbinit, connection_timeout_seconds)) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), @@ -737,8 +738,9 @@ int main(int argc, char *argv[]) { constexpr llvm::StringLiteral client_name = "stdio"; MainLoop loop; - Transport transport(client_name, log.get(), input, output); - DAP dap(log.get(), default_repl_mode, pre_init_commands, no_lldbinit, + Log client_log = log.WithPrefix("(stdio)"); + Transport transport(client_log, input, output); + DAP dap(client_log, default_repl_mode, pre_init_commands, no_lldbinit, client_name, transport, loop); // stdout/stderr redirection to the IDE's console @@ -757,7 +759,7 @@ int main(int argc, char *argv[]) { redirection_test(); if (auto Err = dap.Loop()) { - DAP_LOG(log.get(), "({0}) DAP session error: {1}", client_name, + DAP_LOG(client_log, "DAP session error: {0}", llvm::toStringWithoutConsuming(Err)); llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "DAP session error: "); diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt index 0f8e9db2fab31..9fef37e00ed5d 100644 --- a/lldb/unittests/DAP/CMakeLists.txt +++ b/lldb/unittests/DAP/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(DAPTests ClientLauncherTest.cpp DAPErrorTest.cpp + DAPLogTest.cpp DAPSessionManagerTest.cpp DAPTest.cpp DAPTypesTest.cpp diff --git a/lldb/unittests/DAP/DAPLogTest.cpp b/lldb/unittests/DAP/DAPLogTest.cpp new file mode 100644 index 0000000000000..2756e77fbcbaa --- /dev/null +++ b/lldb/unittests/DAP/DAPLogTest.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 "DAPLog.h" +#include "llvm/Support/raw_ostream.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb_dap; +using namespace llvm; +using namespace testing; + +static llvm::StringRef last_line(llvm::StringRef str) { + size_t index = str.find_last_of('\n', str.size() - 1); + if (index == llvm::StringRef::npos) + return str; + return str.substr(index + 1); +} + +#define TIMESTAMP_PATTERN "\\[[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}\\] " + +TEST(DAPLog, Emit) { + Log::Mutex mux; + std::string outs; + raw_string_ostream os(outs); + Log log(os, mux); + Log inner_log = log.WithPrefix("my_prefix:"); + + log.Emit("Hi"); + EXPECT_THAT(last_line(outs), MatchesRegex(TIMESTAMP_PATTERN "Hi\n")); + + inner_log.Emit("foobar"); + EXPECT_THAT(last_line(outs), + MatchesRegex(TIMESTAMP_PATTERN "my_prefix: foobar\n")); + + log.Emit("Hello from a file/line.", "file.cpp", 42); + EXPECT_THAT( + last_line(outs), + MatchesRegex(TIMESTAMP_PATTERN "file.cpp:42 Hello from a file/line.\n")); + + inner_log.Emit("Hello from a file/line.", "file.cpp", 42); + EXPECT_THAT(last_line(outs), + MatchesRegex(TIMESTAMP_PATTERN + "file.cpp:42 my_prefix: Hello from a file/line.\n")); + + log.WithPrefix("a").WithPrefix("b").WithPrefix("c").Emit("msg"); + EXPECT_THAT(last_line(outs), MatchesRegex(TIMESTAMP_PATTERN "a b c msg\n")); +} diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp index f4dde9559e9d3..e57963e37f68a 100644 --- a/lldb/unittests/DAP/TestBase.cpp +++ b/lldb/unittests/DAP/TestBase.cpp @@ -7,7 +7,10 @@ //===----------------------------------------------------------------------===// #include "TestBase.h" +#include "DAP.h" #include "DAPLog.h" +#include "Handler/RequestHandler.h" +#include "Handler/ResponseHandler.h" #include "TestingSupport/TestUtilities.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBStructuredData.h" @@ -19,7 +22,6 @@ #include "gtest/gtest.h" #include #include -#include using namespace llvm; using namespace lldb; @@ -35,10 +37,9 @@ using lldb_private::Pipe; void TransportBase::SetUp() { std::tie(to_client, to_server) = TestDAPTransport::createPair(); - std::error_code EC; - log = std::make_unique("-", EC); + log = std::make_unique(llvm::outs(), log_mutex); dap = std::make_unique( - /*log=*/log.get(), + /*log=*/*log, /*default_repl_mode=*/ReplMode::Auto, /*pre_init_commands=*/std::vector(), /*no_lldbinit=*/false, diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h index c32f3a769c737..f1c7e6b989729 100644 --- a/lldb/unittests/DAP/TestBase.h +++ b/lldb/unittests/DAP/TestBase.h @@ -8,6 +8,8 @@ #include "DAP.h" #include "DAPLog.h" +#include "Handler/RequestHandler.h" +#include "Handler/ResponseHandler.h" #include "Protocol/ProtocolBase.h" #include "TestingSupport/Host/JSONTransportTestUtilities.h" #include "TestingSupport/SubsystemRAII.h" @@ -60,6 +62,7 @@ class TransportBase : public testing::Test { lldb_private::MainLoop::ReadHandleUP handles[2]; std::unique_ptr log; + lldb_dap::Log::Mutex log_mutex; std::unique_ptr to_client; MockMessageHandler client;