1 //===-- LLDBServerUtilities.cpp ---------------------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "LLDBServerUtilities.h" 10 11 #include "lldb/Utility/Args.h" 12 #include "lldb/Utility/Log.h" 13 #include "lldb/Utility/StreamString.h" 14 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Support/FileSystem.h" 18 19 using namespace lldb; 20 using namespace lldb_private::lldb_server; 21 using namespace lldb_private; 22 using namespace llvm; 23 24 class TestLogHandler : public LogHandler { 25 public: 26 TestLogHandler(std::shared_ptr<llvm::raw_ostream> stream_sp) 27 : m_stream_sp(stream_sp) {} 28 29 void Emit(llvm::StringRef message) override { 30 std::lock_guard<std::mutex> guard(m_mutex); 31 (*m_stream_sp) << message; 32 m_stream_sp->flush(); 33 } 34 35 private: 36 std::mutex m_mutex; 37 std::shared_ptr<raw_ostream> m_stream_sp; 38 }; 39 40 static std::shared_ptr<TestLogHandler> GetLogStream(StringRef log_file) { 41 if (!log_file.empty()) { 42 std::error_code EC; 43 auto stream_sp = std::make_shared<raw_fd_ostream>( 44 log_file, EC, sys::fs::OF_TextWithCRLF | sys::fs::OF_Append); 45 if (!EC) 46 return std::make_shared<TestLogHandler>(stream_sp); 47 errs() << llvm::formatv( 48 "Failed to open log file `{0}`: {1}\nWill log to stderr instead.\n", 49 log_file, EC.message()); 50 } 51 // No need to delete the stderr stream. 52 return std::make_shared<TestLogHandler>( 53 std::shared_ptr<raw_ostream>(&errs(), [](raw_ostream *) {})); 54 } 55 56 bool LLDBServerUtilities::SetupLogging(const std::string &log_file, 57 const StringRef &log_channels, 58 uint32_t log_options) { 59 60 auto log_stream_sp = GetLogStream(log_file); 61 62 SmallVector<StringRef, 32> channel_array; 63 log_channels.split(channel_array, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false); 64 for (auto channel_with_categories : channel_array) { 65 std::string error; 66 llvm::raw_string_ostream error_stream(error); 67 Args channel_then_categories(channel_with_categories); 68 std::string channel(channel_then_categories.GetArgumentAtIndex(0)); 69 channel_then_categories.Shift(); // Shift off the channel 70 71 bool success = Log::EnableLogChannel( 72 log_stream_sp, log_options, channel, 73 channel_then_categories.GetArgumentArrayRef(), error_stream); 74 if (!success) { 75 errs() << formatv("Unable to setup logging for channel \"{0}\": {1}", 76 channel, error); 77 return false; 78 } 79 } 80 return true; 81 } 82