|
- Author:
- kris (IP: 17.228.23.90)
- Timestamp:
- 05/09/09 02:19:51 (15 years ago)
- Comment:
updated to recent changes
Legend:
- Unmodified
- Added
- Removed
- Modified
-
TutLogging
v10 |
v11 |
|
25 | 25 | import tango.util.log.Log; |
---|
26 | 26 | |
---|
27 | | Logger mymoduleLogger = Log.getLogger("mypackage.mymodule"); |
---|
| 27 | auto mymoduleLogger = Log.lookup("mypackage.mymodule"); |
---|
28 | 28 | }}} |
---|
29 | 29 | |
---|
30 | | There are a few items of note in the above example. First, the tango.util.log.Log module publicly imports tango.util.log.Logger, so it need not be imported separately. Second, Logger instances are never instantiated directly. When Log.getLogger is called, it attempts to find the Logger instance associated with the given name. If no Logger is found, it creates and returns a new instance. Finally, the name of the new Logger is "mypackage.mymodule". In terms of the hierarchy, if another Logger named "mypackage" has been configured, the new Logger will inherit its properties. |
---|
| 30 | There are a few items of note in the above example. First, the tango.util.log.Log module publicly imports tango.util.log.Logger, so it need not be imported separately. Second, Logger instances are never instantiated directly. When Log.lookup is called, it attempts to find the Logger instance associated with the given name. If no Logger is found, it creates and returns a new instance. Finally, the name of the new Logger is "mypackage.mymodule". In terms of the hierarchy, if another Logger named "mypackage" has been configured, the new Logger will inherit its properties. |
---|
31 | 31 | |
---|
32 | 32 | When new Loggers are created and no Logger has been created above them in the hierarchy, they are attached to a special Logger called "root". The root Logger is the parent of every Logger in the hierarchy. In the above example, if no Logger named "mypackage" had yet been created, then the "mypackage.mymodule" Logger would have inherited the properties of the root Logger. |
---|
33 | 33 | |
---|
34 | | The root Logger can be accessed directly in the special Log.getRootLogger method: |
---|
| 34 | The root Logger can be accessed directly in the special Log.root method: |
---|
35 | 35 | |
---|
36 | 36 | {{{ |
---|
38 | 38 | import tango.util.log.Log; |
---|
39 | 39 | |
---|
40 | | Logger root = Log.getRootLogger(); |
---|
| 40 | auto root = Log.root; |
---|
41 | 41 | }}} |
---|
42 | 42 | |
---|
62 | 62 | The intent behind each level, with the exclusion of None, is a guideline for tango.util.log users. What each level means in practice is entirely up to the programmer, though it is a good idea to follow the general guidelines above for consistency. |
---|
63 | 63 | |
---|
64 | | To set the level of a Logger, the Logger.setLevel method is used. To determine the level of a Logger, either Logger.getLevel or Logger.isEnabled can be used. Passing any level value to a Logger means that logging will be enabled for all messages matching that level's rank and lower. So enabling the Trace level means that all levels are enabled, while enabling the Error level means only the Error and Fatal levels are enabled. |
---|
| 64 | To set the level of a Logger, the Logger.level method is used. To determine the level of a Logger, either Logger.level or Logger.enabled can be used. Passing any level value to a Logger means that logging will be enabled for all messages matching that level's rank and lower. So enabling the Trace level means that all levels are enabled, while enabling the Error level means only the Error and Fatal levels are enabled. |
---|
65 | 65 | |
---|
66 | 66 | The level of a message can be specified in two ways, either via the Logger.append method, or by using one of the shorthand methods named for each level. The following code illustrates how to manipulate logging levels. |
---|
74 | 74 | void testLogger() |
---|
75 | 75 | { |
---|
76 | | Logger logger = Log.getLogger("mylogger"); |
---|
| 76 | auto logger = Log.lookup("mylogger"); |
---|
77 | 77 | |
---|
78 | 78 | // Enable Info, Warn, Error, and Fatal levels |
---|
79 | | logger.setLevel(Logger.Level.Info); |
---|
| 79 | logger.level = logger.Info; |
---|
80 | 80 | |
---|
81 | | logger.append(Logger.Level.Info, "This is an info message."); |
---|
| 81 | logger.append(logger.Info, "This is an info message."); |
---|
82 | 82 | logger.info("This is an info message, too."); |
---|
83 | 83 | |
---|
84 | 84 | logger.trace("This is a trace message and won't be printed."); |
---|
85 | | logger.append(Logger.Level.Trace, "This is a trace message, too, and also won't be printed."); |
---|
| 85 | logger.append(logger.Trace, "This is a trace message, too, and also won't be printed."); |
---|
86 | 86 | |
---|
87 | | logger.setLevel(Logger.Level.Error); // enable logging only for Error and Fatal levels |
---|
| 87 | logger.level = logger.Error; // enable logging only for Error and Fatal levels |
---|
88 | 88 | |
---|
89 | 89 | logger.trace("This message won't be printed."); |
---|
94 | 94 | |
---|
95 | 95 | // This turns logging off completely for logger |
---|
96 | | logger.setLevel(Logger.Level.None); |
---|
| 96 | logger.level = logger.None; |
---|
97 | 97 | } |
---|
98 | 98 | }}} |
---|
102 | 102 | Every Logger needs to know where to send its output. In tango.util.log, Appenders handle the task of sending the output to its final destination. No Appenders are configured by default. If the above example were to be used as-is in an actual program, it wouldn't print any output since no Appender is configured. tango.util.log includes a handful of useful Appenders that are ready for use. |
---|
103 | 103 | |
---|
104 | | '''!ConsoleAppender''' - prints output to the system console. |
---|
| 104 | '''!AppendConsole''' - prints output to the system console. |
---|
105 | 105 | |
---|
106 | | '''!FileAppender''' - prints output to a file. |
---|
| 106 | '''!AppendFile''' - prints output to a file. |
---|
107 | 107 | |
---|
108 | | '''!RollingFileAppender''' - prints output to one of a group of files, moving on to the next file in the group when the current one reaches a maximum size. |
---|
| 108 | '''!AppendFiles''' - prints output to one of a group of files, moving on to the next file in the group when the current one reaches a maximum size. |
---|
109 | 109 | |
---|
110 | | '''!SocketAppender''' - prints output to a network socket. |
---|
| 110 | '''!AppendSocket''' - prints output to a network socket. |
---|
111 | 111 | |
---|
112 | | '''!MailAppender''' - sends output to an email server. |
---|
| 112 | '''!AppendMail''' - sends output to an email server. |
---|
113 | 113 | |
---|
114 | | '''!NullAppender''' - sends output nowhere. Useful as a placeholder or for benchmarking. |
---|
| 114 | '''!AppendNull''' - sends output nowhere. Useful as a placeholder or for benchmarking. |
---|
115 | 115 | |
---|
116 | | !ConsoleAppender is the only Appender we will consider, as the others rely on packages other than tango.util.log and are beyond the scope of this basic tutorial. |
---|
| 116 | !AppendConsole is the only Appender we will consider, as the others rely on packages other than tango.util.log and are beyond the scope of this basic tutorial. |
---|
117 | 117 | |
---|
118 | | To assign an Appender to a Logger, the Logger.addAppender method should be used. As the name suggests, this method does not replace any existing Appenders already assigned to the Logger, meaning multiple Appenders can be assigned to one Logger. By default, the Logger will output to all Appenders assigned to it. It will also pass output to the Logger above it in hierarchy. This latter behavior can be changed by a call to Logger.setAdditive. Calling Logger.isAdditive will give the current state, returning false if the Logger is configured to not pass output up the hierarchy. |
---|
| 118 | To assign an Appender to a Logger, the Logger.add method should be used. As the name suggests, this method does not replace any existing Appenders already assigned to the Logger, meaning multiple Appenders can be assigned to one Logger. By default, the Logger will output to all Appenders assigned to it. It will also pass output to the Logger above it in hierarchy. This latter behavior can be changed by a call to Logger.additive. Calling Logger.additive will give the current state, returning false if the Logger is configured to not pass output up the hierarchy. |
---|
119 | 119 | |
---|
120 | 120 | The following example demonstrates how to configure an Appender and print text using a Logger. It is a working program that can be compiled and executed. |
---|
125 | 125 | |
---|
126 | 126 | import tango.util.log.Log; |
---|
127 | | import tango.util.log.ConsoleAppender; |
---|
| 127 | import tango.util.log.AppendConsole; |
---|
128 | 128 | |
---|
129 | 129 | void main() |
---|
130 | 130 | { |
---|
131 | | Logger logger = Log.getLogger("mylogger"); |
---|
132 | | logger.addAppender(new ConsoleAppender()); |
---|
| 131 | auto logger = Log.lookup("mylogger"); |
---|
| 132 | logger.add(new AppendConsole); |
---|
133 | 133 | logger.info("Hello Tango.Log!"); |
---|
134 | 134 | } |
---|
142 | 142 | {{{ |
---|
143 | 143 | #!d |
---|
144 | | if(logger.isEnabled(Logger.Level.Trace)) |
---|
| 144 | if(logger.trace) |
---|
145 | 145 | { |
---|
146 | 146 | char[] output = doExpensiveOutputConstruction(); |
---|
148 | 148 | } |
---|
149 | 149 | }}} |
---|
150 | | ==== The Configurator ==== |
---|
| 150 | ==== The Config ==== |
---|
151 | 151 | |
---|
152 | | tango.util.log includes a special class that will automatically configure the root Logger to append to the system console. Doing so means that every Logger object created will have the ability to log to the system console by default. The class is called Configurator and can be found in tango.util.log.Configurator. |
---|
| 152 | tango.util.log includes a special nodule that will automatically configure the root Logger to append to the system console. Doing so means that every Logger object created will have the ability to log to the system console by default. Just import it to make it operate. |
---|
153 | 153 | |
---|
154 | 154 | {{{ |
---|
155 | 155 | #!d |
---|
156 | 156 | import tango.util.log.Log; |
---|
157 | | import tango.util.log.Configurator; |
---|
| 157 | import tango.util.log.Config; |
---|
158 | 158 | |
---|
159 | 159 | void main() |
---|
160 | 160 | { |
---|
161 | | // configure the root Logger for console output |
---|
162 | | Configurator.configure(); |
---|
163 | | |
---|
164 | 161 | // test it |
---|
165 | | Log.getRootLogger().info("Hello Root Logger!"); |
---|
166 | | } |
---|
167 | | }}} |
---|
168 | | |
---|
169 | | Additionally, Configurator takes advantage of D's opCall override and allows the call to Configurator.configure to be condensed: |
---|
170 | | |
---|
171 | | {{{ |
---|
172 | | #!d |
---|
173 | | import tango.util.log.Log; |
---|
174 | | import tango.util.log.Configurator; |
---|
175 | | |
---|
176 | | void main() |
---|
177 | | { |
---|
178 | | // configure the root Logger for console output |
---|
179 | | Configurator(); |
---|
180 | | |
---|
181 | | // test it |
---|
182 | | Log.getRootLogger().info("Hello Root Logger!"); |
---|
| 162 | Log.root.info("Hello Root Logger!"); |
---|
183 | 163 | } |
---|
184 | 164 | }}} |
---|
186 | 166 | ==== Layouts ==== |
---|
187 | 167 | |
---|
188 | | Anyone running the logtest example from the Appenders section of this tutorial and comparing its output to that of the Configurator examples just above will notice that the output is different -- the latter examples have output a number just before the Logger name. That is because the Configurator uses an advanced feature of the tango.util.log called Layouts. In tango.util.log, the final format of the output text is configured independently of the Appenders. Configurator uses a special Layout called !SimpleTimeLayout. This and two other Layout implementations, !SpartanLayout and !SimpleLayout, can be found in tango.util.log.Layout. Additionally, tango.util.log.!DateLayout and tango.util.log.!XmlLayout define two layouts that are more complex. |
---|
| 168 | Anyone running the logtest example from the Appenders section of this tutorial and comparing its output to that of the Config examples just above will notice that the output is different -- the latter examples have output a number just before the Logger name. That is because the Config uses an advanced feature of the tango.util.log called Layouts. In tango.util.log, the final format of the output text is configured independently of the Appenders. Config uses a special Layout called !LayoutTimer, which can be found in tango.util.log.Log. Additionally, tango.util.log.!LayoutDate and tango.util.log.!LayoutChainsaw define two layouts that are more complex. |
---|
189 | 169 | |
---|
190 | 170 | Layouts are a powerful feature and are mentioned here for completeness, though the details are beyond the scope of this basic tutorial. |
|
|