Index: lldb/trunk/include/lldb/Core/Log.h =================================================================== --- lldb/trunk/include/lldb/Core/Log.h +++ lldb/trunk/include/lldb/Core/Log.h @@ -47,6 +47,7 @@ #define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD (1u << 5) #define LLDB_LOG_OPTION_PREPEND_THREAD_NAME (1U << 6) #define LLDB_LOG_OPTION_BACKTRACE (1U << 7) +#define LLDB_LOG_OPTION_APPEND (1U << 8) //---------------------------------------------------------------------- // Logging Functions Index: lldb/trunk/include/lldb/Core/StreamFile.h =================================================================== --- lldb/trunk/include/lldb/Core/StreamFile.h +++ lldb/trunk/include/lldb/Core/StreamFile.h @@ -37,6 +37,10 @@ StreamFile (const char *path); + StreamFile (const char *path, + uint32_t options, + uint32_t permissions = lldb::eFilePermissionsFileDefault); + StreamFile (FILE *fh, bool transfer_ownership); virtual Index: lldb/trunk/source/Commands/CommandObjectLog.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectLog.cpp +++ lldb/trunk/source/Commands/CommandObjectLog.cpp @@ -146,6 +146,7 @@ case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break; + case 'a': log_options |= LLDB_LOG_OPTION_APPEND; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -223,6 +224,7 @@ { LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." }, { LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." }, { LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." }, +{ LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append to the log file instead of overwriting." }, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; Index: lldb/trunk/source/Core/Debugger.cpp =================================================================== --- lldb/trunk/source/Core/Debugger.cpp +++ lldb/trunk/source/Core/Debugger.cpp @@ -1331,7 +1331,12 @@ log_stream_sp = pos->second.lock(); if (!log_stream_sp) { - log_stream_sp.reset (new StreamFile (log_file)); + uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate + | File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; + if (! (log_options & LLDB_LOG_OPTION_APPEND)) + options |= File::eOpenOptionTruncate; + + log_stream_sp.reset (new StreamFile (log_file, options)); m_log_streams[log_file] = log_stream_sp; } } Index: lldb/trunk/source/Core/StreamFile.cpp =================================================================== --- lldb/trunk/source/Core/StreamFile.cpp +++ lldb/trunk/source/Core/StreamFile.cpp @@ -54,6 +54,13 @@ { } +StreamFile::StreamFile (const char *path, + uint32_t options, + uint32_t permissions) : + Stream(), + m_file(path, options, permissions) +{ +} StreamFile::~StreamFile() { Index: lldb/trunk/test/logging/TestLogging.py =================================================================== --- lldb/trunk/test/logging/TestLogging.py +++ lldb/trunk/test/logging/TestLogging.py @@ -2,7 +2,7 @@ Test lldb logging. This test just makes sure logging doesn't crash, and produces some output. """ -import os, time +import os, time, string import unittest2 import lldb from lldbtest import * @@ -10,6 +10,15 @@ class LogTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + append_log_file = "lldb-commands-log-append.txt" + truncate_log_file = "lldb-commands-log-truncate.txt" + + + @classmethod + def classCleanup(cls): + """Cleanup the test byproducts.""" + cls.RemoveTempFile(cls.truncate_log_file) + cls.RemoveTempFile(cls.append_log_file) @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @dsym_test @@ -56,6 +65,48 @@ self.assertTrue(log_lines > 0, "Something was written to the log file.") + # Check that lldb truncates its log files + def test_log_truncate (self): + if (os.path.exists (self.truncate_log_file)): + os.remove (self.truncate_log_file) + + # put something in our log file + with open(self.truncate_log_file, "w") as f: + for i in range(1, 1000): + f.write("bacon\n") + + self.runCmd ("log enable -t -f '%s' lldb commands" % (self.truncate_log_file)) + self.runCmd ("help log") + self.runCmd ("log disable lldb") + + self.assertTrue (os.path.isfile (self.truncate_log_file)) + with open(self.truncate_log_file, "r") as f: + contents = f.read () + + # check that it got removed + self.assertTrue(string.find(contents, "bacon") == -1) + + # Check that lldb can append to a log file + def test_log_append (self): + if (os.path.exists (self.append_log_file)): + os.remove (self.append_log_file) + + # put something in our log file + with open(self.append_log_file, "w") as f: + f.write("bacon\n") + + self.runCmd ("log enable -t -a -f '%s' lldb commands" % (self.append_log_file)) + self.runCmd ("help log") + self.runCmd ("log disable lldb") + + self.assertTrue (os.path.isfile (self.append_log_file)) + with open(self.append_log_file, "r") as f: + contents = f.read () + + # check that it is still there + self.assertTrue(string.find(contents, "bacon") == 0) + + if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize()