From 318c5000ce58a07a279053f084a28faaef5c422d Mon Sep 17 00:00:00 2001 From: James Turner Date: Fri, 8 Feb 2013 19:37:29 +0000 Subject: [PATCH] Logging tweaks. More pieces to support logging to buffers in the GUI. --- simgear/debug/BufferedLogCallback.cxx | 28 ++++++++++++++-- simgear/debug/BufferedLogCallback.hxx | 15 ++++++++- simgear/debug/logstream.cxx | 47 ++++++++++++++++++++++----- simgear/debug/logstream.hxx | 5 ++- 4 files changed, 81 insertions(+), 14 deletions(-) diff --git a/simgear/debug/BufferedLogCallback.cxx b/simgear/debug/BufferedLogCallback.cxx index 72d437c6..6fbe6e99 100644 --- a/simgear/debug/BufferedLogCallback.cxx +++ b/simgear/debug/BufferedLogCallback.cxx @@ -37,6 +37,8 @@ public: sgDebugClass m_class; sgDebugPriority m_priority; vector_cstring m_buffer; + unsigned int m_stamp; + unsigned int m_maxLength; }; BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) : @@ -44,6 +46,8 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) : { d->m_class = c; d->m_priority = p; + d->m_stamp = 0; + d->m_maxLength = 0xffff; } BufferedLogCallback::~BufferedLogCallback() @@ -61,17 +65,37 @@ void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p, if ((c & d->m_class) == 0 || p < d->m_priority) return; - vector_cstring::value_type msg = (vector_cstring::value_type) strdup(aMessage.c_str()); + vector_cstring::value_type msg; + if (aMessage.size() >= d->m_maxLength) { + msg = (vector_cstring::value_type) malloc(d->m_maxLength); + strncpy((char*) msg, aMessage.c_str(), d->m_maxLength - 1); + msg[d->m_maxLength - 1] = 0; // add final NULL byte + } else { + msg = (vector_cstring::value_type) strdup(aMessage.c_str()); + } + SGGuard g(d->m_mutex); d->m_buffer.push_back(msg); + d->m_stamp++; +} + +unsigned int BufferedLogCallback::stamp() const +{ + return d->m_stamp; } -void BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput) +unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput) { SGGuard g(d->m_mutex); size_t sz = d->m_buffer.size(); aOutput.resize(sz); memcpy(aOutput.data(), d->m_buffer.data(), sz * sizeof(vector_cstring::value_type)); + return d->m_stamp; } +void BufferedLogCallback::truncateAt(unsigned int t) +{ + d->m_maxLength = t; +} + } // of namespace simgear diff --git a/simgear/debug/BufferedLogCallback.hxx b/simgear/debug/BufferedLogCallback.hxx index 21359fd9..f48ac3c0 100644 --- a/simgear/debug/BufferedLogCallback.hxx +++ b/simgear/debug/BufferedLogCallback.hxx @@ -37,9 +37,20 @@ public: BufferedLogCallback(sgDebugClass c, sgDebugPriority p); virtual ~BufferedLogCallback(); + /// truncate messages longer than a certain length. This is to work-around + /// for broken PUI behaviour, it can be removed once PUI is gone. + void truncateAt(unsigned int); + virtual void operator()(sgDebugClass c, sgDebugPriority p, const char* file, int line, const std::string& aMessage); + /** + * read the stamp value associated with the log buffer. This is + * incremented whenever the log contents change, so can be used + * to poll for changes. + */ + unsigned int stamp() const; + /** * copying a (large) vector of std::string would be very expensive. * once logged, this call retains storage of the underlying string data, @@ -53,8 +64,10 @@ public: * copy the buffered log data into the provided output list * (which will be cleared first). This method is safe to call from * any thread. + * + * returns the stamp value of the copied data */ - void threadsafeCopy(vector_cstring& aOutput); + unsigned int threadsafeCopy(vector_cstring& aOutput); private: class BufferedLogCallbackPrivate; std::auto_ptr d; diff --git a/simgear/debug/logstream.cxx b/simgear/debug/logstream.cxx index 589c4e67..f3bcc99d 100644 --- a/simgear/debug/logstream.cxx +++ b/simgear/debug/logstream.cxx @@ -157,6 +157,25 @@ private: int line; std::string message; }; + + class PauseThread + { + public: + PauseThread(LogStreamPrivate* parent) : m_parent(parent) + { + m_wasRunning = m_parent->stop(); + } + + ~PauseThread() + { + if (m_wasRunning) { + m_parent->startLog(); + } + } + private: + LogStreamPrivate* m_parent; + bool m_wasRunning; + }; public: LogStreamPrivate() : m_logClass(SG_ALL), @@ -169,7 +188,10 @@ public: SGMutex m_lock; SGBlockingQueue m_entries; - std::vector m_callbacks; + + typedef std::vector CallbackVec; + CallbackVec m_callbacks; + sgDebugClass m_logClass; sgDebugPriority m_logPriority; bool m_isRunning; @@ -219,22 +241,25 @@ public: void addCallback(simgear::LogCallback* cb) { - bool wasRunning = stop(); + PauseThread pause(this); m_callbacks.push_back(cb); - if (wasRunning) { - startLog(); + } + + void removeCallback(simgear::LogCallback* cb) + { + PauseThread pause(this); + CallbackVec::iterator it = std::find(m_callbacks.begin(), m_callbacks.end(), cb); + if (it != m_callbacks.end()) { + m_callbacks.erase(it); } } void setLogLevels( sgDebugClass c, sgDebugPriority p ) { - bool wasRunning = stop(); + PauseThread pause(this); m_logPriority = p; m_logClass = c; m_stderrCallback->setLogLevels(c, p); - if (wasRunning) { - startLog(); - } } bool would_log( sgDebugClass c, sgDebugPriority p ) const @@ -274,6 +299,12 @@ logstream::addCallback(simgear::LogCallback* cb) global_privateLogstream->addCallback(cb); } +void +logstream::removeCallback(simgear::LogCallback* cb) +{ + global_privateLogstream->removeCallback(cb); +} + void logstream::log( sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const std::string& msg) diff --git a/simgear/debug/logstream.hxx b/simgear/debug/logstream.hxx index 36816b63..0af98c6a 100644 --- a/simgear/debug/logstream.hxx +++ b/simgear/debug/logstream.hxx @@ -93,9 +93,8 @@ public: * must use appropriate locking. */ void addCallback(simgear::LogCallback* cb); - - // friend logstream& sglog(); -// static logstream *initGlobalLogstream(); + + void removeCallback(simgear::LogCallback* cb); private: // constructor -- 2.39.5