UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

278 lines (271 loc) 40 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>The Logging API</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="The Logging API"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-11-SECT-7"/>The Logging API</h1></div></div></div><p>The <a id="I_indexterm11_id748722" class="indexterm"/><code class="literal">java.util.logging</code> package provides a highly flexible and easy-to-use logging framework for system information, error messages, and fine-grained tracing (debugging) output. With the logging package, you can apply filters to select log messages, direct their output to one or more destinations (including files and network services), and format the messages appropriately for their consumers.</p><p>Most importantly, much of this basic logging configuration can be set up externally at runtime through the use of a logging setup properties file or an external program. For example, by setting the right properties at runtime, you can specify that log messages are to be sent both to a designated file in XML format and also logged to the system console in a digested, human-readable form. Furthermore, for each of those destinations, you can specify the level or priority of messages to be logged, discarding those below a certain threshold of significance. By following the correct source conventions in your code, you can even make it possible to adjust the logging levels for specific parts of your application, allowing you to target individual packages and classes for detailed logging without being overwhelmed by too much output. The Logging API can even be controlled remotely via Java Management Extensions MBean APIs.</p><div class="sect2" title="Overview"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.1"/>Overview</h2></div></div></div><p><a id="idx10627" class="indexterm"/> <a id="idx10656" class="indexterm"/>Any good logging API must have at least two guiding principles. First, performance should not inhibit the developer from using log messages freely. As with Java language assertions (discussed in <a class="xref" href="ch04.html" title="Chapter 4. The Java Language">Chapter 4</a>), when log messages are turned off, they should not consume any significant amount of processing time. This means that there’s no performance penalty for including logging statements as long as they’re turned off. Second, although some users may want advanced features and configuration, a logging API must have some simple mode of usage that is convenient enough for time-starved developers to use in lieu of the old standby <code class="literal">System.out.println()</code>. Java’s Logging API provides a simple model and many convenience methods that make it very tempting.</p><div class="sect3" title="Loggers"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-11-SECT-7.1.1"/>Loggers</h3></div></div></div><p><a id="I_indexterm11_id748814" class="indexterm"/> <a id="I_indexterm11_id748824" class="indexterm"/>The heart of the logging framework is the <span class="emphasis"><em>logger</em></span>, an instance of <a id="I_indexterm11_id748836" class="indexterm"/><code class="literal">java.util.logging.Logger</code>. In most cases, this is the only class your code will ever have to deal with. A logger is constructed from the static <a id="I_indexterm11_id748848" class="indexterm"/><code class="literal">Logger.getLogger()</code> method, with a logger name as its argument. Logger names place loggers into a hierarchy with a global, root logger at the top and a tree and children below. This hierarchy allows the configuration to be inherited by parts of the tree so that logging can be automatically configured for different parts of your application. The convention is to use a separate logger instance in each major class or package and to use the dot-separated package and/or class name as the logger name. For example:</p><a id="I_11_tt745"/><pre class="programlisting"> <code class="kn">package</code> <code class="n">com</code><code class="o">.</code><code class="na">oreilly</code><code class="o">.</code><code class="na">learnjava</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">Book</code> <code class="o">{</code> <code class="kd">static</code> <code class="n">Logger</code> <code class="n">log</code> <code class="o">=</code> <code class="n">Logger</code><code class="o">.</code><code class="na">getLogger</code><code class="o">(</code><code class="s">"com.oreilly.learnjava.Book"</code><code class="o">);</code></pre><p>The logger provides a wide range of methods to log messages; some take very detailed information, and some convenience methods take only a string for ease of use. For example:</p><a id="I_11_tt746"/><pre class="programlisting"> <code class="n">log</code><code class="o">.</code><code class="na">warning</code><code class="o">(</code><code class="s">"Disk 90% full."</code><code class="o">);</code> <code class="n">log</code><code class="o">.</code><code class="na">info</code><code class="o">(</code><code class="s">"New user joined chat room."</code><code class="o">);</code></pre><p>We cover methods of the logger class in detail a bit later. The names <code class="literal">warning</code> and <code class="literal">info</code> are two examples of logging levels; there are seven levels ranging from SEVERE at the top to FINEST at the bottom. Distinguishing log messages in this way allows us to select the level of information that we want to see at runtime. Rather than simply logging everything and sorting through it later (with negative performance impact) we can tweak which messages are generated. We’ll talk more about logging levels in the next section.</p><p>We should also mention that for convenience in very simple applications or experiments, a logger for the name “global” is provided in the static field <a id="I_indexterm11_id748913" class="indexterm"/><code class="literal">Logger.global</code>. You can use it as an alternative to the old standby <code class="literal">System.out.println()</code> for those cases where that is still a temptation:</p><a id="I_11_tt747"/><pre class="programlisting"> <code class="n">Logger</code><code class="o">.</code><code class="na">global</code><code class="o">.</code><code class="na">info</code><code class="o">(</code><code class="s">"Doing foo..."</code><code class="o">)</code></pre></div><div class="sect3" title="Handlers"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-11-SECT-7.1.2"/>Handlers</h3></div></div></div><p><a id="I_indexterm11_id748946" class="indexterm"/> <a id="idx10652" class="indexterm"/>Loggers represent the client interface to the logging system, but the actual work of publishing messages to destinations (such as files or the console) is done by <span class="emphasis"><em>handler</em></span> objects. Each logger may have one or more <code class="literal">Handler</code> objects associated with it, which includes several predefined handlers supplied with the Logging API: <a id="I_indexterm11_id748981" class="indexterm"/><code class="literal">ConsoleHandler</code>, <a id="I_indexterm11_id748991" class="indexterm"/><code class="literal">FileHandler</code>, <a id="I_indexterm11_id749002" class="indexterm"/><code class="literal">StreamHandler</code>, and <a id="I_indexterm11_id749013" class="indexterm"/><code class="literal">SocketHandler</code>. Each handler knows how to deliver messages to its respective destination. <code class="literal">ConsoleHandler</code> is used by the default configuration to print messages on the command line or system console. <code class="literal">FileHandler</code> can direct output to files using a supplied naming convention and automatically rotate the files as they become full. The others send messages to streams and sockets, respectively. There is one additional handler, <a id="I_indexterm11_id749038" class="indexterm"/><code class="literal">MemoryHandler</code>, that can hold a number of log messages in memory. <code class="literal">MemoryHandler</code> has a circular buffer, which maintains a certain number of messages until it is triggered to publish them to another designated handler.</p><p>As we said, loggers can be set to use one or more handlers. Loggers also send messages up the tree to each of their parent logger’s handlers. In the simplest configuration, this means that all messages end up distributed by the root logger’s handlers. We’ll soon see how to set up output using the standard handlers for the console, files, etc.<a id="I_indexterm11_id749065" class="indexterm"/></p></div><div class="sect3" title="Filters"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-11-SECT-7.1.3"/>Filters</h3></div></div></div><p><a id="I_indexterm11_id749078" class="indexterm"/> <a id="I_indexterm11_id749089" class="indexterm"/>Before a logger hands off a message to its handlers or its parent’s handlers, it first checks whether the logging level is sufficient to proceed. If the message doesn’t meet the required level, it is discarded at the source. In addition to level, you can implement arbitrary filtering of messages by creating <a id="I_indexterm11_id749103" class="indexterm"/><code class="literal">Filter</code> classes that examine the log message before it is processed. A <code class="literal">Filter</code> class can be applied to a logger externally at runtime in the same way that the logging level, handlers, and formatters, which are discussed next, can be. A <code class="literal">Filter</code> may also be attached to an individual <code class="literal">Handler</code> to filter records at the output stage (as opposed to the source).</p></div><div class="sect3" title="Formatters"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-11-SECT-7.1.4"/>Formatters</h3></div></div></div><p><a id="I_indexterm11_id749140" class="indexterm"/> <a id="I_indexterm11_id749150" class="indexterm"/>Internally, messages are carried in a neutral format, including all the source information provided. It is not until they are processed by a handler that they are formatted for output by an instance of a <code class="literal">Formatter</code> object. The logging package comes with two basic formatters: <a id="I_indexterm11_id749167" class="indexterm"/><code class="literal">SimpleFormatter</code> and <a id="I_indexterm11_id749177" class="indexterm"/><code class="literal">XMLFormatter</code>. The <code class="literal">SimpleFormatter</code> is the default used for console output. It produces short, human-readable summaries of log messages. <code class="literal">XMLFormatter</code> encodes all the log message details into an XML record format. The DTD for the format can be found at <a class="ulink" href="http://java.sun.com/dtd/">http://java.sun.com/dtd/</a>.<a id="I_indexterm11_id749210" class="indexterm"/><a id="I_indexterm11_id749217" class="indexterm"/></p></div></div><div class="sect2" title="Logging Levels"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.2"/>Logging Levels</h2></div></div></div><p><a id="idx10624" class="indexterm"/> <a id="idx10653" class="indexterm"/> <a class="xref" href="ch11s07.html#learnjava3-CHP-11-TABLE-9" title="Table 11-9. Logging API logging levels">Table 11-9</a> lists the logging levels from most to least significant.</p><div class="table"><a id="learnjava3-CHP-11-TABLE-9"/><p class="title">Table 11-9. Logging API logging levels</p><div class="table-contents"><table summary="Logging API logging levels" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col/><col/></colgroup><thead><tr><th style="text-align: left" valign="top"><p>Level</p></th><th style="text-align: left"><p>Meaning</p></th></tr></thead><tbody><tr><td style="text-align: left" valign="top"><p> <a id="I_indexterm11_id749312" class="indexterm"/> <code class="literal">SEVERE</code> </p></td><td style="text-align: left"><p>Application failure</p></td></tr><tr><td style="text-align: left" valign="top"><p> <a id="I_indexterm11_id749338" class="indexterm"/> <code class="literal">WARNING</code> </p></td><td style="text-align: left"><p>Notification of potential problem</p></td></tr><tr><td style="text-align: left" valign="top"><p> <a id="I_indexterm11_id749363" class="indexterm"/> <code class="literal">INFO</code> </p></td><td style="text-align: left"><p>Messages of general interest to end users</p></td></tr><tr><td style="text-align: left" valign="top"><p> <a id="I_indexterm11_id749389" class="indexterm"/> <code class="literal">CONFIG</code> </p></td><td style="text-align: left"><p>Detailed system configuration information for administrators</p></td></tr><tr><td style="text-align: left" valign="top"><p> <a id="I_indexterm11_id749415" class="indexterm"/> <code class="literal">FINE</code>,</p><p> <a id="I_indexterm11_id749429" class="indexterm"/> <code class="literal">FINER</code>,</p><p> <a id="I_indexterm11_id749443" class="indexterm"/> <code class="literal">FINEST</code> </p></td><td style="text-align: left"><p>Successively more detailed application tracing information for developers</p></td></tr></tbody></table></div></div><p>These levels fall into three camps: end user, administrator, and developer. Applications often default to logging only messages of the <code class="literal">INFO</code> level and above (<code class="literal">INFO</code>, <code class="literal">WARNING</code>, and <code class="literal">SEVERE</code>). These levels are generally seen by end users and messages logged to them should be suitable for general consumption. In other words, they should be written clearly so they make sense to an average user of the application. Often these kinds of messages are presented to the end user on a system console or in a pop-up message dialog.</p><p>The <code class="literal">CONFIG</code> level should be used for relatively static but detailed system information that could assist an administrator or installer. This might include information about the installed software modules, host system characteristics, and configuration parameters. These details are important, but probably not as meaningful to an end user.</p><p>The <code class="literal">FINE</code>, <code class="literal">FINER</code>, and <code class="literal">FINEST</code> levels are for developers or others with knowledge of the internals of the application. These should be used for tracing the application at successive levels of detail. You can define your own meanings for these. We’ll suggest a rough outline in our example, coming up next.<a id="I_indexterm11_id749522" class="indexterm"/><a id="I_indexterm11_id749529" class="indexterm"/></p></div><div class="sect2" title="A Simple Example"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.3"/>A Simple Example</h2></div></div></div><p><a id="idx10623" class="indexterm"/> <a id="idx10651" class="indexterm"/>In the following (admittedly very contrived) example, we use all the logging levels so that we can experiment with logging configuration. Although the sequence of messages is nonsensical, the text is representative of messages of that type.</p><a id="I_11_tt748"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.util.logging.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">LogTest</code> <code class="o">{</code> <code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code> <code class="n">argv</code><code class="o">[])</code> <code class="o">{</code> <code class="n">Logger</code> <code class="n">logger</code> <code class="o">=</code> <code class="n">Logger</code><code class="o">.</code><code class="na">getLogger</code><code class="o">(</code><code class="s">"com.oreilly.LogTest"</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">severe</code><code class="o">(</code><code class="s">"Power lost - running on backup!"</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">warning</code><code class="o">(</code><code class="s">"Database connection lost, retrying..."</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">info</code><code class="o">(</code><code class="s">"Startup complete."</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">config</code><code class="o">(</code><code class="s">"Server configuration: standalone, JVM version 1.5"</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">fine</code><code class="o">(</code><code class="s">"Loading graphing package."</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">finer</code><code class="o">(</code><code class="s">"Doing pie chart"</code><code class="o">);</code> <code class="n">logger</code><code class="o">.</code><code class="na">finest</code><code class="o">(</code><code class="s">"Starting bubble sort: value ="</code><code class="o">+</code><code class="mi">42</code><code class="o">);</code> <code class="o">}</code> <code class="o">}</code></pre><p>There’s not much to this example. We ask for a <code class="literal">logger</code> instance for our class using the static <code class="literal">Logger.getLogger()</code> method, specifying a class name. The convention is to use the fully qualified class name, so we’ll pretend that our class is in a <code class="literal">com.oreilly</code> package.</p><p>Now, run <code class="literal">LogTest</code>. You should see output like the following on the system console:</p><a id="I_11_tt749"/><pre class="programlisting"> <code class="n">Jan</code> <code class="mi">6</code><code class="o">,</code> <code class="mi">2002</code> <code class="mi">3</code><code class="o">:</code><code class="mi">24</code><code class="o">:</code><code class="mi">36</code> <code class="n">PM</code> <code class="n">LogTest</code> <code class="n">main</code> <code class="nl">SEVERE:</code> <code class="n">Power</code> <code class="n">lost</code> <code class="o">-</code> <code class="n">running</code> <code class="n">on</code> <code class="n">backup</code><code class="o">!</code> <code class="n">Jan</code> <code class="mi">6</code><code class="o">,</code> <code class="mi">2002</code> <code class="mi">3</code><code class="o">:</code><code class="mi">24</code><code class="o">:</code><code class="mi">37</code> <code class="n">PM</code> <code class="n">LogTest</code> <code class="n">main</code> <code class="nl">WARNING:</code> <code class="n">Database</code> <code class="n">connection</code> <code class="n">lost</code><code class="o">,</code> <code class="n">retrying</code><code class="o">...</code> <code class="n">Jan</code> <code class="mi">6</code><code class="o">,</code> <code class="mi">2002</code> <code class="mi">3</code><code class="o">:</code><code class="mi">24</code><code class="o">:</code><code class="mi">37</code> <code class="n">PM</code> <code class="n">LogTest</code> <code class="n">main</code> <code class="nl">INFO:</code> <code class="n">Startup</code> <code class="n">complete</code><code class="o">.</code></pre><p>We see the <code class="literal">INFO</code>, <code class="literal">WARNING</code>, and <code class="literal">SEVERE</code> messages, each identified with a date and timestamp and the name of the class and method (<code class="literal">LogTest main</code>) from which they came. Notice that the lower-level messages did not appear. This is because the default logging level is normally set to <code class="literal">INFO</code>, meaning that only messages of severity <code class="literal">INFO</code> and above are logged. Also note that the output went to the system console and not to a logfile somewhere; that’s also the default. Now we’ll describe where these defaults are set and how to override them at runtime.<a id="I_indexterm11_id749666" class="indexterm"/><a id="I_indexterm11_id749673" class="indexterm"/></p></div><div class="sect2" title="Logging Setup Properties"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.4"/>Logging Setup Properties</h2></div></div></div><p><a id="idx10625" class="indexterm"/> <a id="idx10654" class="indexterm"/>As we said in the introduction, probably the most important feature of the Logging API is the ability to configure so much of it at runtime through the use of external properties or applications. The default logging configuration is stored in the file <span class="emphasis"><em>jre/lib/logging.properties</em></span> in the directory where Java is installed. It’s a standard Java properties file (of the kind we described earlier in this chapter).</p><p>The format of this file is simple. You can make changes to it, but you don’t have to. Instead, you can specify your own logging setup properties file on a case-by-case basis using a system property at runtime, as follows:</p><a id="I_11_tt750"/><pre class="programlisting"> <code class="o">%</code> <strong class="userinput"><code><code class="n">java</code> <code class="o">-</code><code class="n">Djava</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">config</code><code class="o">.</code><code class="na">file</code><code class="o">=</code><code class="n">myfile</code><code class="o">.</code><code class="na">properties</code></code></strong></pre><p>In this command line, <span class="emphasis"><em>myfile</em></span> is your properties file that contains the directive, which we’ll describe next. If you want to make this file designation more permanent, you can do so by setting the filename in the corresponding entry using the Java Preferences API described earlier in this chapter. You can go even further and instead of specifying a setup file, supply a class that is responsible for setting up all logging configuration, but we won’t get into that here.</p><p>A very simple logging properties file might look like this:</p><a id="I_11_tt751"/><pre class="programlisting"> <code class="err">#</code> <code class="n">Set</code> <code class="n">the</code> <code class="k">default</code> <code class="n">logging</code> <code class="n">level</code> <code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">FINEST</code> <code class="err">#</code> <code class="n">Direct</code> <code class="n">output</code> <code class="n">to</code> <code class="n">the</code> <code class="n">console</code> <code class="n">handlers</code> <code class="o">=</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">ConsoleHandler</code></pre><p>Here, we have set the default logging level for the entire application using the <code class="literal">.level</code> (that’s dot-level) property. We have also used the <a id="I_indexterm11_id749776" class="indexterm"/><code class="literal">handlers</code> property to specify that an instance of the <code class="literal">ConsoleHandler</code> should be used (just like the default setup) to show messages on the console. If you run our application again, specifying this properties file as the logging setup, you will now see all our log messages.</p><p>But we’re just getting warmed up. Next, let’s look at a more complex configuration:</p><a id="I_11_tt752"/><pre class="programlisting"> <code class="err">#</code> <code class="n">Set</code> <code class="n">the</code> <code class="k">default</code> <code class="n">logging</code> <code class="n">level</code> <code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">INFO</code> <code class="err">#</code> <code class="n">Ouput</code> <code class="n">to</code> <code class="n">file</code> <code class="n">and</code> <code class="n">console</code> <code class="n">handlers</code> <code class="o">=</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">,</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">ConsoleHandler</code> <code class="err">#</code> <code class="n">Configure</code> <code class="n">the</code> <code class="n">file</code> <code class="n">output</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">FINEST</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">.</code><code class="na">pattern</code> <code class="o">=</code> <code class="o">%</code><code class="n">h</code><code class="o">/</code><code class="n">Test</code><code class="o">.</code><code class="na">log</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">.</code><code class="na">limit</code> <code class="o">=</code> <code class="mi">25000</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">.</code><code class="na">count</code> <code class="o">=</code> <code class="mi">4</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">FileHandler</code><code class="o">.</code><code class="na">formatter</code> <code class="o">=</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">XMLFormatter</code> <code class="err">#</code> <code class="n">Configure</code> <code class="n">the</code> <code class="n">console</code> <code class="n">output</code> <code class="n">java</code><code class="o">.</code><code class="na">util</code><code class="o">.</code><code class="na">logging</code><code class="o">.</code><code class="na">ConsoleHandler</code><code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">WARNING</code> <code class="err">#</code> <code class="n">Levels</code> <code class="k">for</code> <code class="n">specific</code> <code class="n">classes</code> <code class="n">com</code><code class="o">.</code><code class="na">oreilly</code><code class="o">.</code><code class="na">LogTest</code><code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">FINEST</code></pre><p>In this example, we have configured two log handlers: a <a id="I_indexterm11_id749815" class="indexterm"/><code class="literal">ConsoleHandler</code> with the logging level set to <a id="I_indexterm11_id749825" class="indexterm"/><code class="literal">WARNING</code> and also an instance of <a id="I_indexterm11_id749836" class="indexterm"/><code class="literal">FileHandler</code> that sends the output to an <a id="I_indexterm11_id749848" class="indexterm"/>XML file. The file handler is configured to log messages at the <a id="I_indexterm11_id749857" class="indexterm"/><code class="literal">FINEST</code> level (all messages) and to rotate logfiles every 25,000 lines, keeping a maximum of four files.</p><p>The filename is controlled by the <code class="literal">pattern</code> property. Forward slashes in the filename are automatically localized to backslash (\) if necessary. The special symbol <a id="I_indexterm11_id749878" class="indexterm"/><code class="literal">%h</code> refers to the user home. You can use <a id="I_indexterm11_id749889" class="indexterm"/><code class="literal">%t</code> to refer to the system temporary directory. If filenames conflict, a number is appended automatically after a dot (starting at zero). Alternatively, you can use <a id="I_indexterm11_id749901" class="indexterm"/><code class="literal">%u</code> to indicate where a unique number should be inserted into the name. Similarly, when files rotate, a number is appended after a dot at the end. You can take control of where the rotation number is placed with the <a id="I_indexterm11_id749913" class="indexterm"/><code class="literal">%g</code> identifier.</p><p>In our example, we specified the <code class="literal">XMLFormatter</code> class. We could also have used the <code class="literal">SimpleFormatter</code> class to send the same kind of simple output to the console. The <code class="literal">ConsoleHandler</code> also allows us to specify any formatter we wish, using the <code class="literal">formatter</code> property.</p><p>Finally, we promised earlier that you could control logging levels for parts of your applications. To do this, set properties on your application loggers using their hierarchical names:</p><a id="I_11_tt753"/><pre class="programlisting"> <code class="err">#</code> <code class="n">Levels</code> <code class="k">for</code> <code class="n">specific</code> <code class="n">logger</code> <code class="o">(</code><code class="n">class</code><code class="o">)</code> <code class="n">names</code> <code class="n">com</code><code class="o">.</code><code class="na">oreilly</code><code class="o">.</code><code class="na">LogTest</code><code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">FINEST</code></pre><p>Here, we’ve set the logging level for just our test logger, by name. The log properties follow the hierarchy, so we could set the logging level for all classes in the <code class="literal">oreilly</code> package with:</p><a id="I_11_tt754"/><pre class="programlisting"> <code class="n">com</code><code class="o">.</code><code class="na">oreilly</code><code class="o">.</code><code class="na">level</code> <code class="o">=</code> <code class="n">FINEST</code></pre><p>Logging levels are set in the order in which they are read in the properties file, so set the general ones first. Also note that the levels set on the handlers allow the file handler to filter only the messages being supplied by the loggers. So setting the file handler to <a id="I_indexterm11_id749986" class="indexterm"/><code class="literal">FINEST</code> won’t revive messages squelched by a logger set to <a id="I_indexterm11_id749998" class="indexterm"/><code class="literal">SEVERE</code> (only the <code class="literal">SEVERE</code> messages will make it to the handler from that logger).<a id="I_indexterm11_id750014" class="indexterm"/><a id="I_indexterm11_id750021" class="indexterm"/></p></div><div class="sect2" title="The Logger"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.5"/>The Logger</h2></div></div></div><p><a id="idx10626" class="indexterm"/> <a id="idx10655" class="indexterm"/>In our example, we used the seven convenience methods named for the various logging levels. There are also three groups of general methods that can be used to provide more detailed information. The most general are:</p><a id="I_11_tt755"/><pre class="programlisting"> <code class="n">log</code><code class="o">(</code><code class="n">Level</code> <code class="n">level</code><code class="o">,</code> <code class="n">String</code> <code class="n">msg</code><code class="o">)</code> <code class="n">log</code><code class="o">(</code><code class="n">Level</code> <code class="n">level</code><code class="o">,</code> <code class="n">String</code> <code class="n">msg</code><code class="o">,</code> <code class="n">Object</code> <code class="n">param1</code><code class="o">)</code> <code class="n">log</code><code class="o">(</code><code class="n">Level</code> <code class="n">level</code><code class="o">,</code> <code class="n">String</code> <code class="n">msg</code><code class="o">,</code> <code class="n">Object</code> <code class="n">params</code><code class="o">[])</code> <code class="n">log</code><code class="o">(</code><code class="n">Level</code> <code class="n">level</code><code class="o">,</code> <code class="n">String</code> <code class="n">msg</code><code class="o">,</code> <code class="n">Throwable</code> <code class="n">thrown</code><code class="o">)</code></pre><p>These methods accept as their first argument a static logging level identifier from the <a id="I_indexterm11_id750077" class="indexterm"/><code class="literal">Level</code> class, followed by a parameter, array, or exception type. The level identifier is one of <code class="literal">Level.SEVERE</code>, <code class="literal">Level.WARNING</code>, <code class="literal">Level.INFO</code>, and so on.</p><p>In addition to these four methods, there are four corresponding methods named <a id="I_indexterm11_id750107" class="indexterm"/><code class="literal">logp()</code> that also take a source class and method name as the second and third arguments. In our example, we saw Java automatically determine that information, so why would we want to supply it? The answer is that Java may not always be able to determine the exact method name because of runtime dynamic optimization. The <code class="literal">p</code> in <code class="literal">logp</code> stands for “precise” and allows you to control this yourself.</p><p>There is yet another set of methods named <a id="I_indexterm11_id750135" class="indexterm"/><code class="literal">logrb()</code>—which probably should have been named <code class="literal">logprb()</code>—that take both the class and method names and a resource bundle name. The resource bundle localizes the messages (see the section <a class="xref" href="ch10s03.html#learnjava3-CHP-10-SECT-3.2" title="Resource Bundles">Resource Bundles</a> in <a class="xref" href="ch10.html" title="Chapter 10. Working with Text">Chapter 10</a>). More generally, a logger may have a resource bundle associated with it when it is created, using another form of the <code class="literal">getLogger</code> method:</p><a id="I_11_tt756"/><pre class="programlisting"> <code class="n">Logger</code><code class="o">.</code><code class="na">getLogger</code><code class="o">(</code><code class="s">"com.oreilly.LogTest"</code><code class="o">,</code> <code class="s">"logMessages"</code><code class="o">);</code></pre><p>In either case, the resource bundle name is passed along with the log message and can be used by the formatter. If a resource bundle is specified, the standard formatters treat the message text as a key and try to look up a localized message. Localized messages may include parameters using the standard message format notation and the form of <code class="literal">log()</code>, which accepts an argument array.</p><p>Finally, there are convenience methods called <a id="I_indexterm11_id750190" class="indexterm"/><code class="literal">entering()</code>, <a id="I_indexterm11_id750201" class="indexterm"/><code class="literal">exiting()</code>, and <a id="I_indexterm11_id750211" class="indexterm"/><code class="literal">throwing()</code> that developers can use to log detailed trace information.<a id="I_indexterm11_id750223" class="indexterm"/><a id="I_indexterm11_id750230" class="indexterm"/></p></div><div class="sect2" title="Performance"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-7.6"/>Performance</h2></div></div></div><p><a id="I_indexterm11_id750244" class="indexterm"/> <a id="idx10657" class="indexterm"/>In the introduction, we said that performance is a priority of the Logging API. To that end we’ve described that log messages are filtered at the source, using logging levels to cut off processing of messages early. This saves much of the expense of handling them. However, it cannot prevent certain kinds of setup work that you might do before the logging call. Specifically, because we’re passing things into the log methods, it’s common to construct detailed messages or render objects to strings as arguments. Often this kind of operation is costly. To avoid unnecessary string construction, you should wrap expensive log operations in a conditional test using the <code class="literal">Logger isLoggable()</code> method to test whether you should carry out the operation:<a id="I_indexterm11_id750279" class="indexterm"/></p><a id="I_11_tt757"/><pre class="programlisting"> <code class="k">if</code> <code class="o">(</code> <code class="n">log</code><code class="o">.</code><code class="na">isLoggable</code><code class="o">(</code> <code class="n">Level</code><code class="o">.</code><code class="na">CONFIG</code> <code class="o">)</code> <code class="o">)</code> <code class="o">{</code> <code class="n">log</code><code class="o">.</code><code class="na">config</code><code class="o">(</code><code class="s">"Configuration: "</code><code class="o">+</code> <code class="n">loadExpensiveConfigInfo</code><code class="o">()</code> <code class="o">);</code> <code class="o">}</code></pre></div></div></body></html>