epubjs
Version:
Render ePub documents in the browser, across many devices
278 lines (271 loc) • 40 kB
HTML
<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>