diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -245,7 +245,7 @@ bool EnableLog(llvm::StringRef channel, llvm::ArrayRef categories, llvm::StringRef log_file, uint32_t log_options, - llvm::raw_ostream &error_stream); + size_t buffer_size, llvm::raw_ostream &error_stream); void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); diff --git a/lldb/include/lldb/Utility/Log.h b/lldb/include/lldb/Utility/Log.h --- a/lldb/include/lldb/Utility/Log.h +++ b/lldb/include/lldb/Utility/Log.h @@ -58,9 +58,11 @@ class StreamLogHandler : public LogHandler { public: - StreamLogHandler(int fd, bool should_close, bool unbuffered = true); + StreamLogHandler(int fd, bool should_close, size_t buffer_size = 0); + ~StreamLogHandler() override; void Emit(llvm::StringRef message) override; + void Flush(); private: llvm::raw_fd_ostream m_stream; diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -1621,7 +1621,7 @@ std::string error; llvm::raw_string_ostream error_stream(error); return m_opaque_sp->EnableLog(channel, GetCategoryArray(categories), "", - log_options, error_stream); + log_options, /*buffer_size=*/0, error_stream); } else return false; } diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp --- a/lldb/source/Commands/CommandObjectLog.cpp +++ b/lldb/source/Commands/CommandObjectLog.cpp @@ -11,6 +11,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/FileSpec.h" @@ -21,7 +22,7 @@ using namespace lldb; using namespace lldb_private; -#define LLDB_OPTIONS_log +#define LLDB_OPTIONS_log_enable #include "CommandOptions.inc" /// Common completion logic for log enable/disable. @@ -89,6 +90,10 @@ log_file.SetFile(option_arg, FileSpec::Style::native); FileSystem::Instance().Resolve(log_file); break; + case 'b': + error = + buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign); + break; case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break; @@ -125,16 +130,16 @@ void OptionParsingStarting(ExecutionContext *execution_context) override { log_file.Clear(); + buffer_size.Clear(); log_options = 0; } llvm::ArrayRef GetDefinitions() override { - return llvm::makeArrayRef(g_log_options); + return llvm::makeArrayRef(g_log_enable_options); } - // Instance variables to hold the values for command options. - FileSpec log_file; + OptionValueUInt64 buffer_size; uint32_t log_options = 0; }; @@ -164,9 +169,9 @@ std::string error; llvm::raw_string_ostream error_stream(error); - bool success = - GetDebugger().EnableLog(channel, args.GetArgumentArrayRef(), log_file, - m_options.log_options, error_stream); + bool success = GetDebugger().EnableLog( + channel, args.GetArgumentArrayRef(), log_file, m_options.log_options, + m_options.buffer_size.GetCurrentValue(), error_stream); result.GetErrorStream() << error_stream.str(); if (success) diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -428,9 +428,11 @@ Desc<"Clears the current command history.">; } -let Command = "log" in { +let Command = "log enable" in { def log_file : Option<"file", "f">, Group<1>, Arg<"Filename">, Desc<"Set the destination file to log to.">; + def log_buffer_size : Option<"buffer", "b">, Group<1>, Arg<"UnsignedInteger">, + Desc<"Set the log to be buffered, using the specified buffer size.">; def log_threadsafe : Option<"threadsafe", "t">, Group<1>, Desc<"Enable thread safe logging to avoid interweaved log lines.">; def log_verbose : Option<"verbose", "v">, Group<1>, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1409,7 +1409,7 @@ bool Debugger::EnableLog(llvm::StringRef channel, llvm::ArrayRef categories, llvm::StringRef log_file, uint32_t log_options, - llvm::raw_ostream &error_stream) { + size_t buffer_size, llvm::raw_ostream &error_stream) { const bool should_close = true; std::shared_ptr log_handler_sp; @@ -1420,7 +1420,7 @@ LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; } else if (log_file.empty()) { log_handler_sp = std::make_shared( - GetOutputFile().GetDescriptor(), !should_close); + GetOutputFile().GetDescriptor(), !should_close, buffer_size); } else { auto pos = m_stream_handlers.find(log_file); if (pos != m_stream_handlers.end()) @@ -1441,7 +1441,7 @@ } log_handler_sp = std::make_shared( - (*file)->GetDescriptor(), should_close); + (*file)->GetDescriptor(), should_close, buffer_size); m_stream_handlers[log_file] = log_handler_sp; } } diff --git a/lldb/source/Utility/Log.cpp b/lldb/source/Utility/Log.cpp --- a/lldb/source/Utility/Log.cpp +++ b/lldb/source/Utility/Log.cpp @@ -339,14 +339,19 @@ Emit(message); } -StreamLogHandler::StreamLogHandler(int fd, bool should_close, bool unbuffered) - : m_stream(fd, should_close, unbuffered) {} - -void StreamLogHandler::Emit(llvm::StringRef message) { - m_stream << message; - m_stream.flush(); +StreamLogHandler::StreamLogHandler(int fd, bool should_close, + size_t buffer_size) + : m_stream(fd, should_close, buffer_size == 0) { + if (buffer_size > 0) + m_stream.SetBufferSize(buffer_size); } +StreamLogHandler::~StreamLogHandler() { Flush(); } + +void StreamLogHandler::Flush() { m_stream.flush(); } + +void StreamLogHandler::Emit(llvm::StringRef message) { m_stream << message; } + CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback, void *baton) : m_callback(callback), m_baton(baton) {} diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -1120,7 +1120,7 @@ /*add_to_history*/ eLazyBoolNo, Result); if (!opts::Log.empty()) - Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs()); + Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, 0, errs()); if (opts::BreakpointSubcommand) return opts::breakpoint::evaluateBreakpoints(*Dbg);