Loggers, Appenders and Layouts
Log4cxx has three main components: loggers, appenders and layouts. These three types of components work together to enable developers to log messages according to message type and level, and to control at runtime how these messages are formatted and where they are reported.
Log4cxx有三个主要部分:loggers, appenders, layouts。这三个类型的组件一起工作,使得开发者根据消息的type和level记录日志。再运行时能够控制消息的格式和where they are reported.
Logger hierarchy
The first and foremost advantage of any logging API over plain std::cout resides in its ability to disable certain log statements while allowing others to print unhindered. This capability assumes that the logging space, that is, the space of all possible logging statements, is categorized according to some developer-chosen criteria.
相比普通的std::cout,所有logging API最大的优势在于可以屏蔽某一部分的log语句,而允许输出其他的消息。
Loggers are named entities. Logger names are case-sensitive and they follow the hierarchical naming rule:
Loggers 被命名为实体。logger名大小写敏感,且遵循分层命名规则(hierarchical naming rule).
Named Hierarchy A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger. 命名层次 一个logger的名字后面跟一个点作为后代logger的前缀,那么他就叫做后代logger的祖先。 如果没有祖先介于两个logger之间,那么一个logger称为一个child logger的parent。 这段翻译太烂了。 |
For example, the logger named "com.foo" is a parent of the logger named "com.foo.Bar". Similarly, "java" is a parent of "java.util" and an ancestor of "java.util.Vector". This naming scheme should be familiar to most developers.
例如:名字是”com.foo”的logger,是名为”com.foo.Bar”logger的parent。同样,”java”是”java.util”的parent,是”java.util.Vector”的ancestor。应该很多开发者都不会对这样的命名模式感到陌生吧。
The root logger resides at the top of the logger hierarchy. It is exceptional in two ways:
root logger处于logger层次的最顶层。有两点最为特殊:
it always exists,
it cannot be retrieved by name.
1.总是存在
2.不能根据名字来得到
Invoking the class static log4cxx::Logger::getRootLogger method retrieves it. All other loggers are instantiated and retrieved with the class staticlog4cxx::Logger::getLogger method. This method takes the name of the desired logger as a parameter. Some of the basic methods in the Logger class are listed below.
调用这个类的静态方法 log4cxx::Logger::getRootLogger来获取。其他的logger由静态方法log4cxx::Logger::getLogger来实例化和获取。这个方法的参数是想要获取的logger的名称。下面是logger class的一些基本方法。
namespace log4cxx { class Logger { public: // Creation & retrieval methods: static LoggerPtr getRootLogger(); static LoggerPtr getLogger(const std::string& name); static LoggerPtr getLogger(const std::wstring& name); } } // // Use these macros instead of calling Logger methods directly. // Macros will handle char or wchar_t pointers or strings // or most right-hand side expressions of an // std::basic_string::operator<<. // #define LOG4CXX_TRACE(logger, expression) ... #define LOG4CXX_DEBUG(logger, expression) ... #define LOG4CXX_INFO(logger, expression) ... #define LOG4CXX_WARN(logger, expression) ... #define LOG4CXX_ERROR(logger, expression) ... #define LOG4CXX_FATAL(logger, expression) ... |
//
// Use these macros instead of calling Logger methods directly.使用这些宏而不是直接调用Logger方法
// Macros will handle char or wchar_t pointers or strings宏会处理char, wchar_t pointers, strings,
// or most right-hand side expressions of an 和大多数<<的右表达式
// std::basic_string::operator<<.
//
Loggers may be assigned levels. The pre-defined levels: TRACE, DEBUG, INFO, WARN, ERROR and FATAL are defined in the log4cxx::Level class which provides accessor functions.
loggers可以分配levels。预定义的levels包括在 log4cxx::Level class中定义的有访问函数的level:TRACE, DEBUG, INFO, WARN, ERROR 和 FATAL
If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level. More formally:
如果某logger没有分配一个level,那么他继承离他最近的分配了level的ancestor。
Level Inheritance The inherited level for a given logger C, is equal to the first non-null level in the logger hierarchy, starting at C and proceeding upwards in the hierarchy towards the root logger. 给定一个logger C,他继承的level等于logger 层级中第一个non-null的level。从c开始到root logger,向上递推。 |
To ensure that all loggers can eventually inherit a level, the root logger always has an assigned level.
为了确保所有loggers最终有一个level,root logger永远要有一个level分配。
Below are four tables with various assigned level values and the resulting inherited levels according to the above rule.
Example 1
Logger name |
Assigned level |
Inherited level |
root |
Proot |
Proot |
X |
none |
Proot |
X.Y |
none |
Proot |
X.Y.Z |
none |
Proot |
In example 1 above, only the root logger is assigned a level. This level value, Proot, is inherited by the other loggers X, X.Y and X.Y.Z.
Example 2
Logger name |
Assigned level |
Inherited level |
root |
Proot |
Proot |
X |
Px |
Px |
X.Y |
Pxy |
Pxy |
X.Y.Z |
Pxyz |
Pxyz |
In example 2, all loggers have an assigned level value. There is no need for level inheritence.
Example 3
Logger name |
Assigned level |
Inherited level |
root |
Proot |
Proot |
X |
Px |
Px |
X.Y |
none |
Px |
X.Y.Z |
Pxyz |
Pxyz |
In example 3, the loggers root, X and X.Y.Z are assigned the levels Proot, Px and Pxyz respectively. The logger X.Y inherits its level value from its parent X.
Example 4
Logger name |
Assigned level |
Inherited level |
root |
Proot |
Proot |
X |
Px |
Px |
X.Y |
none |
Px |
X.Y.Z |
none |
Px |
In example 4, the loggers root and X and are assigned the levels Proot and Px respectively. The loggers X.Y and X.Y.Z inherits their level value from their nearest parent X having an assigned level.
Logging requests are made by invoking a method of a logger instance, preferrably through the use of LOG4CXX_INFO or similar macros which support short-circuiting if the threshold is not satisfied and use of the insertion operator (<<) in the message parameter.
日志需要调用一个logger实例的方法,通常使用LOG4CXX_INFO以及类似的宏,如果一个阈值没有满足,这些宏支持短路(short-circuiting),在消息中使用insertion operator (<<)参数。
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("com.foo")); const char* region = "World"; LOG4CXX_INFO(logger, "Simple message text.") LOG4CXX_INFO(logger, "Hello, " << region) LOG4CXX_DEBUG(logger, L"Iteration " << i) LOG4CXX_DEBUG(logger, "e^10 = " << std::scientific << exp(10.0)) // // Use a wchar_t first operand to force use of wchar_t based stream. // LOG4CXX_WARN(logger, L"" << i << L" is the number of the iteration.") |
A logging request is said to be enabled if its level is higher than or equal to the level of its logger. Otherwise, the request is said to be disabled. A logger without an assigned level will inherit one from the hierarchy. This rule is summarized below.
如果一个logger的日志请求的level高于等于此logger的level,那么就是有效的。否则,这个请求就是无效的。没有设定level的Logger则继承上层。下面总结了这个规则。
Basic Selection Rule A log request of level p in a logger with (either assigned or inherited, whichever is appropriate) level q, is enabled if p >= q. |
This rule is at the heart of log4cxx. It assumes that levels are ordered. For the standard levels, we have TRACE < DEBUG < INFO < WARN < ERROR < FATAL.
Here is an example of this rule.
// get a logger instance named "com.foo" log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("com.foo")); // Now set its level. Normally you do not need to set the // level of a logger programmatically. This is usually done // in configuration files. logger->setLevel(log4cxx::Level::getInfo()); log4cxx::LoggerPtr barlogger(log4cxx::Logger::getLogger("com.foo.Bar"); // This request is enabled, because WARN >= INFO. LOG4CXX_WARN(logger, "Low fuel level.") // This request is disabled, because DEBUG < INFO. LOG4CXX_DEBUG(logger, "Starting search for nearest gas station.") // The logger instance barlogger, named "com.foo.Bar", // will inherit its level from the logger named // "com.foo" Thus, the following request is enabled // because INFO >= INFO. LOG4CXX_INFO(barlogger. "Located nearest gas station.") // This request is disabled, because DEBUG < INFO. LOG4CXX_DEBUG(barlogger, "Exiting gas station search") |
Calling the getLogger method with the same name will always return a reference to the exact same logger object.
调用getLogger方法时,相同的名字返回相同的logger object的引用。
For example, in
log4cxx::LoggerPtr x = log4cxx::Logger::getLogger("wombat"); log4cxx::LoggerPtr y = log4cxx::Logger::getLogger("wombat"); |
x and y refer to exactly the same logger object.
x, y 指向同一个logger object。
Thus, it is possible to configure a logger and then to retrieve the same instance somewhere else in the code without passing around references. In fundamental contradiction to biological parenthood, where parents always preceed their children, log4cxx loggers can be created and configured in any order. In particular, a "parent" logger will find and link to its descendants even if it is instantiated after them.
因此,配置一个logger,然后不用在代码中传递引用就可以获取相同的实例。在基本的关于biological parenthood矛盾,parent永远先于其children,log4cxx logger可以以任何顺序被创建和配置。尤其是,一个后面才被实例化的”parent” logger也可以查找和连接他的后代。
Configuration of the log4cxx environment is typically done at application initialization. The preferred way is by reading a configuration file. This approach will be discussed shortly.
log4cxx的环境配置一般在应用初始化时完成。较好的做法是读取一个配置文件。这个做法后面就会介绍。
Log4cxx makes it easy to name loggers by software component. This can be accomplished by statically instantiating a logger in each class, with the logger name equal to the fully qualified name of the class. This is a useful and straightforward method of defining loggers. As the log output bears the name of the generating logger, this naming strategy makes it easy to identify the origin of a log message. However, this is only one possible, albeit common, strategy for naming loggers. Log4cxx does not restrict the possible set of loggers. The developer is free to name the loggers as desired.
log4cxx使得software component可以轻松name loggers。只需要在每个类中静态的实例化一个logger,而且logger name与类的全名(fully qualified name of the class)相同。这个非常有用、简单的定义logger的方法。因为log输出承担了生成logger的名字,这个命名策略使得容易识别log消息的的源。however,尽管平常,这是唯一的可能的,命名loggers策略。Log4cxx并不限制loggers的集合。开发者可以自由命名。 cated seems to be the best strategy known so far.
而且以其所在的类名命名也是目前所知的最好的命名策略。