diff --git a/Foundation/include/Poco/AsyncChannel.h b/Foundation/include/Poco/AsyncChannel.h index 937c9d098..700b7f3db 100644 --- a/Foundation/include/Poco/AsyncChannel.h +++ b/Foundation/include/Poco/AsyncChannel.h @@ -50,14 +50,14 @@ public: void setChannel(Channel::Ptr pChannel); /// Connects the AsyncChannel to the given target channel. /// All messages will be forwarded to this channel. - + Channel::Ptr getChannel() const; /// Returns the target channel. void open(); - /// Opens the channel and creates the + /// Opens the channel and creates the /// background logging thread. - + void close(); /// Closes the channel and stops the background /// logging thread. @@ -69,7 +69,7 @@ public: void setProperty(const std::string& name, const std::string& value); /// Sets or changes a configuration property. /// - /// The "channel" property allows setting the target + /// The "channel" property allows setting the target /// channel via the LoggingRegistry. /// The "channel" property is set-only. /// @@ -82,18 +82,34 @@ public: /// * highest /// /// The "priority" property is set-only. + /// + /// The "queueSize" property allows to limit the number + /// of messages in the queue. If the queue is full and + /// new messages are logged, these are dropped until the + /// queue has free capacity again. The number of dropped + /// messages is recorded, and a log message indicating the + /// number of dropped messages will be generated when the + /// queue has free capacity again. + /// In addition to an unsigned integer specifying the size, + /// this property can have the values "none" or "unlimited", + /// which disable the queue size limit. A size of 0 also + /// removes the limit. + /// + /// The "queueSize" property is set-only. protected: ~AsyncChannel(); void run(); void setPriority(const std::string& value); - + private: - Channel::Ptr _pChannel; + Channel::Ptr _pChannel; Thread _thread; FastMutex _threadMutex; FastMutex _channelMutex; NotificationQueue _queue; + std::size_t _queueSize = 0; + std::size_t _dropCount = 0; }; diff --git a/Foundation/src/AsyncChannel.cpp b/Foundation/src/AsyncChannel.cpp index b9be051bc..317eea6e4 100644 --- a/Foundation/src/AsyncChannel.cpp +++ b/Foundation/src/AsyncChannel.cpp @@ -18,7 +18,10 @@ #include "Poco/Formatter.h" #include "Poco/AutoPtr.h" #include "Poco/LoggingRegistry.h" +#include "Poco/NumberParser.h" #include "Poco/Exception.h" +#include "Poco/String.h" +#include "Poco/Format.h" namespace Poco { @@ -31,23 +34,23 @@ public: _msg(msg) { } - + ~MessageNotification() { } - + const Message& message() const { return _msg; } - + private: Message _msg; }; -AsyncChannel::AsyncChannel(Channel::Ptr pChannel, Thread::Priority prio): - _pChannel(pChannel), +AsyncChannel::AsyncChannel(Channel::Ptr pChannel, Thread::Priority prio): + _pChannel(pChannel), _thread("AsyncChannel") { _thread.setPriority(prio); @@ -70,7 +73,7 @@ AsyncChannel::~AsyncChannel() void AsyncChannel::setChannel(Channel::Ptr pChannel) { FastMutex::ScopedLock lock(_channelMutex); - + _pChannel = pChannel; } @@ -94,10 +97,10 @@ void AsyncChannel::close() if (_thread.isRunning()) { while (!_queue.empty()) Thread::sleep(100); - - do + + do { - _queue.wakeUpAll(); + _queue.wakeUpAll(); } while (!_thread.tryJoin(100)); } @@ -106,6 +109,18 @@ void AsyncChannel::close() void AsyncChannel::log(const Message& msg) { + if (_queueSize != 0 && _queue.size() >= _queueSize) + { + ++_dropCount; + return; + } + + if (_dropCount != 0) + { + _queue.enqueueNotification(new MessageNotification(Message(msg, Poco::format("Dropped %z messages.", _dropCount)))); + _dropCount = 0; + } + open(); _queue.enqueueNotification(new MessageNotification(msg)); @@ -115,11 +130,24 @@ void AsyncChannel::log(const Message& msg) void AsyncChannel::setProperty(const std::string& name, const std::string& value) { if (name == "channel") + { setChannel(LoggingRegistry::defaultRegistry().channelForName(value)); + } else if (name == "priority") + { setPriority(value); + } + else if (name == "queueSize") + { + if (Poco::icompare(value, "none") == 0 || Poco::icompare(value, "unlimited") == 0 || value.empty()) + _queueSize = 0; + else + _queueSize = Poco::NumberParser::parseUnsigned(value); + } else + { Channel::setProperty(name, value); + } } @@ -137,12 +165,12 @@ void AsyncChannel::run() nf = _queue.waitDequeueNotification(); } } - - + + void AsyncChannel::setPriority(const std::string& value) { Thread::Priority prio = Thread::PRIO_NORMAL; - + if (value == "lowest") prio = Thread::PRIO_LOWEST; else if (value == "low") @@ -155,7 +183,7 @@ void AsyncChannel::setPriority(const std::string& value) prio = Thread::PRIO_HIGHEST; else throw InvalidArgumentException("thread priority", value); - + _thread.setPriority(prio); }