class Foundation_API Message { public: enum Priority { PRIO_FATAL = 1, /// A fatal error. The application will most likely terminate. This is the highest priority. PRIO_CRITICAL, /// A critical error. The application might not be able to continue running successfully. PRIO_ERROR, /// An error. An operation did not complete successfully, but the application as a whole is not affected. PRIO_WARNING, /// A warning. An operation completed with an unexpected result. PRIO_NOTICE, /// A notice, which is an information with just a higher priority. PRIO_INFORMATION, /// An informational message, usually denoting the successful completion of an operation. PRIO_DEBUG, /// A debugging message. PRIO_TRACE /// A tracing message. This is the lowest priority. }; Message(); Message(const std::string& source, const std::string& text, Priority prio); Message(const std::string& source, const std::string& text, Priority prio, const char* file, int line); Message(const Message& msg); Message(const Message& msg, const std::string& text); ~Message(); Message& operator = (const Message& msg); void swap(Message& msg); void setSource(const std::string& src); const std::string& getSource() const; void setText(const std::string& text); const std::string& getText() const; void setPriority(Priority prio); Priority getPriority() const; void setTime(const Timestamp& time); const Timestamp& getTime() const; void setThread(const std::string& thread); const std::string& getThread() const; void setTid(long pid); long getTid() const; void setPid(long pid); long getPid() const; void setSourceFile(const char* file); const char* getSourceFile() const; void setSourceLine(int line); int getSourceLine() const; const std::string& operator [] (const std::string& param) const; std::string& operator [] (const std::string& param); protected: void init(); typedef std::map<std::string, std::string> StringMap; private: std::string _source; // 产生日志的源 std::string _text; // 日志主内容 Priority _prio; // 日志的优先级(某种程度上表明了日志本身的信息含量) Timestamp _time; // 日志产生的时间 int _tid; // 日志产生的线程 std::string _thread; // 日志产生的线程名 long _pid; // 日志产生的进程名 const char* _file; // 日志产生的代码文件 int _line; // 日志产生的代码文件行号 StringMap* _pMap; // 供用户存储其他信息的map容器 };
Message::Message(): _prio(PRIO_FATAL), _tid(0), _pid(0), _file(0), _line(0), _pMap(0) { init(); } void Message::init() { #if !defined(POCO_VXWORKS) _pid = Process::id(); #endif Thread* pThread = Thread::current(); if (pThread) { _tid = pThread->id(); _thread = pThread->name(); } }
class Foundation_API Configurable { public: Configurable(); virtual ~Configurable(); virtual void setProperty(const std::string& name, const std::string& value) = 0; virtual std::string getProperty(const std::string& name) const = 0; };
#if defined(POCO_OS_FAMILY_WINDOWS) && defined(POCO_WIN32_UTF8) #include "Poco/LogFile_WIN32U.h" #elif defined(POCO_OS_FAMILY_WINDOWS) #include "Poco/LogFile_WIN32.h" #elif defined(POCO_OS_FAMILY_VMS) #include "Poco/LogFile_VMS.h" #else #include "Poco/LogFile_STD.h" #endif namespace Poco { class Foundation_API LogFile: public LogFileImpl { public: LogFile(const std::string& path); ~LogFile(); void write(const std::string& text); UInt64 size() const; Timestamp creationDate() const; const std::string& path() const; };
void PurgeByAgeStrategy::purge(const std::string& path) { std::vector<File> files; list(path, files); for (std::vector<File>::iterator it = files.begin(); it != files.end(); ++it) { if (it->getLastModified().isElapsed(_age.totalMicroseconds())) { it->remove(); } } } void PurgeStrategy::list(const std::string& path, std::vector<File>& files) { Path p(path); p.makeAbsolute(); Path parent = p.parent(); std::string baseName = p.getFileName(); baseName.append("."); DirectoryIterator it(parent); DirectoryIterator end; while (it != end) { if (it.name().compare(0, baseName.size(), baseName) == 0) { files.push_back(*it); } ++it; } }
class Foundation_API PatternFormatter: public Formatter /// This Formatter allows for custom formatting of /// log messages based on format patterns. /// /// The format pattern is used as a template to format the message and /// is copied character by character except for the following special characters, /// which are replaced by the corresponding value. /// /// * %s - message source /// * %t - message text /// * %l - message priority level (1 .. 7) /// * %p - message priority (Fatal, Critical, Error, Warning, Notice, Information, Debug, Trace) /// * %q - abbreviated message priority (F, C, E, W, N, I, D, T) /// * %P - message process identifier /// * %T - message thread name /// * %I - message thread identifier (numeric) /// * %N - node or host name /// * %U - message source file path (empty string if not set) /// * %u - message source line number (0 if not set) /// * %w - message date/time abbreviated weekday (Mon, Tue, ...) /// * %W - message date/time full weekday (Monday, Tuesday, ...) /// * %b - message date/time abbreviated month (Jan, Feb, ...) /// * %B - message date/time full month (January, February, ...) /// * %d - message date/time zero-padded day of month (01 .. 31) /// * %e - message date/time day of month (1 .. 31) /// * %f - message date/time space-padded day of month ( 1 .. 31) /// * %m - message date/time zero-padded month (01 .. 12) /// * %n - message date/time month (1 .. 12) /// * %o - message date/time space-padded month ( 1 .. 12) /// * %y - message date/time year without century (70) /// * %Y - message date/time year with century (1970) /// * %H - message date/time hour (00 .. 23) /// * %h - message date/time hour (00 .. 12) /// * %a - message date/time am/pm /// * %A - message date/time AM/PM /// * %M - message date/time minute (00 .. 59) /// * %S - message date/time second (00 .. 59) /// * %i - message date/time millisecond (000 .. 999) /// * %c - message date/time centisecond (0 .. 9) /// * %F - message date/time fractional seconds/microseconds (000000 - 999999) /// * %z - time zone differential in ISO 8601 format (Z or +NN.NN) /// * %Z - time zone differential in RFC format (GMT or +NNNN) /// * %E - epoch time (UTC, seconds since midnight, January 1, 1970) /// * %[name] - the value of the message parameter with the given name /// * %% - percent sign { public: PatternFormatter(); /// Creates a PatternFormatter. /// The format pattern must be specified with /// a call to setProperty. PatternFormatter(const std::string& format); /// Creates a PatternFormatter that uses the /// given format pattern. ~PatternFormatter(); /// Destroys the PatternFormatter. void format(const Message& msg, std::string& text); /// Formats the message according to the specified /// format pattern and places the result in text. void setProperty(const std::string& name, const std::string& value); /// Sets the property with the given name to the given value. /// /// The following properties are supported: /// /// * pattern: The format pattern. See the PatternFormatter class /// for details. /// * times: Specifies whether times are adjusted for local time /// or taken as they are in UTC. Supported values are "local" and "UTC". /// /// If any other property name is given, a PropertyNotSupported /// exception is thrown. std::string getProperty(const std::string& name) const; /// Returns the value of the property with the given name or /// throws a PropertyNotSupported exception if the given /// name is not recognized. static const std::string PROP_PATTERN; static const std::string PROP_TIMES; protected: static const std::string& getPriorityName(int); /// Returns a string for the given priority value. private: bool _localTime; std::string _pattern; };
当然如果用户对已有的格式不满意,可以自己扩展。
class Foundation_API Channel: public Configurable, public RefCountedObject { public: Channel(); virtual void open(); virtual void close(); virtual void log(const Message& msg) = 0; void setProperty(const std::string& name, const std::string& value); std::string getProperty(const std::string& name) const; protected: virtual ~Channel(); private: Channel(const Channel&); Channel& operator = (const Channel&); };
class Foundation_API SplitterChannel: public Channel /// This channel sends a message to multiple /// channels simultaneously. { public: SplitterChannel(); /// Creates the SplitterChannel. void addChannel(Channel* pChannel); /// Attaches a channel, which may not be null. void removeChannel(Channel* pChannel); /// Removes a channel. void log(const Message& msg); /// Sends the given Message to all /// attaches channels. void setProperty(const std::string& name, const std::string& value); /// Sets or changes a configuration property. /// /// Only the "channel" property is supported, which allows /// adding a comma-separated list of channels via the LoggingRegistry. /// The "channel" property is set-only. /// To simplify file-based configuration, all property /// names starting with "channel" are treated as "channel". void close(); /// Removes all channels. int count() const; /// Returns the number of channels in the SplitterChannel. protected: ~SplitterChannel(); private: typedef std::vector<Channel*> ChannelVec; ChannelVec _channels; mutable FastMutex _mutex; };
void SplitterChannel::log(const Message& msg) { FastMutex::ScopedLock lock(_mutex); for (ChannelVec::iterator it = _channels.begin(); it != _channels.end(); ++it) { (*it)->log(msg); } }
static std::map<std::string, Logger*>* _pLoggerMap;这个静态变量管理了所有的日志对象。
void Logger::log(const Message& msg) { if (_level >= msg.getPriority() && _pChannel) { _pChannel->log(msg); } }
应该说Poco库的日志功能实现的非常强大,同专门的日志库Logcpp相比也并不逊色。大家都知道,在Logcpp库中,category 、appender 和layout具有重要地位。做个对应比较的话:
Logcpp中layout类控制输出信息的格式和样式,相当于Poco中的Formater。
Logcpp中appender类用来输出信息到设备上,相当于Poco中的Channel。
Logcpp中category类为用户接口,可以附加任意appender,这相当于Poco中的Logger类。
在Poco库中,Logger和Channel的关系为包含关系,在Logcpp库中,category与appender同样也是,并且在两个库的实现上,其内部都使用了引用计数技术。对于这一点,大家想一想就明白,引用计数的开销最小。
如果说不同,同Logcpp相比,Poco库把消息单独抽象成Message类,在增加消息内容和扩展性的同时,也使Logger的输出接口变得稍复杂。
(版权所有,转载时请注明作者和出处 http://blog.csdn.net/arau_sh/article/details/8809799)