Why Logging?

Transcrição

Why Logging?
Software Construction
Documentation and Logging
Jürg Luthiger
University of Applied Sciences Northwestern Switzerland
Institute for Mobile and Distributed Systems
Learning Target
You
ƒ can use Mock Objects as an efficient alternative
for Unit Testing
ƒ know how to setup log4j
ƒ can use log4j
Institut für Mobile und Verteilte Systeme
J. Luthiger
2
Documentation
ƒ IMPORTANT
‹
All documentation is a mirror of the code
Build Documentation In, Don't Bolt It On
Tip 68 (The Pragmatic Programmer)
Institut für Mobile und Verteilte Systeme
J. Luthiger
3
Internal Documentation
ƒ Includes source code, comments, design and
test documents, …
ƒ Documenting the source code
Use Naming Convention
‹ Integrate comments into source code
‹ Use tool to generate appropriate docs out of the
source code
‹ Try to keep source and code in sync!
‹
Institut für Mobile und Verteilte Systeme
J. Luthiger
4
Java Naming Conventions
ƒ Naming conventions make programs more
understandable by making them
easier to read
‹ easier to understand
‹ easier to improve
‹ easier to detect bugs
‹
ƒ Use coding guidelines
‹
e.g. from SUN "Code Conventions for the JavaTM
Programming Language" (see Resources)
Institut für Mobile und Verteilte Systeme
J. Luthiger
5
Tool JavaDoc
ƒ Purpose
‹
Instead of writing and maintaining separate
documentation, the programmer writes speciallyformatted comments in the Java code itself. JavaDoc
takes these comments and transforms them into
documentation in HTML (web page) format.
Institut für Mobile und Verteilte Systeme
J. Luthiger
6
General Format
ƒ Start with the normal beginning of comment
delimiter (/*) followed by another (*). All
following lines start with an asterisk lined up
under the first asterisk in the first line. The last
line contains just the normal end of comment
delimiter (*/).
/**
* The number of students in the class.
* This variable must not be negative or greater than 200.
*/
public int numStudents;
Institut für Mobile und Verteilte Systeme
J. Luthiger
7
JavaDoc Tags
ƒ Tags for Classes
‹
@author
ƒ Tags for Methods
@param
‹ @return
‹ @exception
‹
ƒ Tags for Variables
‹
needs no tags, just normal JavaDoc comment
Institut für Mobile und Verteilte Systeme
J. Luthiger
8
Package Level Comments
ƒ Each package can have its own package-level
doc comment source file
ƒ The Javadoc tool will merge them into the final
documentation
ƒ This file is named package.html
ƒ This file is kept in the source directory
Institut für Mobile und Verteilte Systeme
J. Luthiger
9
Integrate JavaDoc into the Build Process
ƒ Use the javadoc Ant Task
‹
Core Task (see Ant's Website)
Institut für Mobile und Verteilte Systeme
J. Luthiger
10
External Documentation
ƒ Includes everything which is published to the
outside world like user manual, …
ƒ Use a markup language to produce the final
documentation
‹
e.g. DocBook, Latex, …
ƒ DocBook
XML based
‹ text-oriented => easily to integrate into a VCS
‹ supports different output formats:
‹
z
‹
HTML, PDF, Tex, …
supports automation => Ant integration
Institut für Mobile und Verteilte Systeme
J. Luthiger
11
Resources
ƒ Sun Reference:
"How to Write Doc Comments for the Javadoc Tool"
http://java.sun.com/j2se/javadoc/writingdoccomments
ƒ Code Conventions for the Java Language
http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html
ƒ DocBook Home
http://www.docbook.org
Institut für Mobile und Verteilte Systeme
J. Luthiger
12
Why Logging?
ƒ Debuggers focus on the state of a program NOW
‹
‹
A stack trace can you tell only how got here directly
It is not possible to detect what was before this actual call
ƒ Logging can provide information about the state of a
program or a data structure over time
‹
Logging can reveal several classes of errors that debugger's
can't
ƒ Logging is invaluable in any system where time itself is a
factor
‹
‹
‹
‹
concurrent processes
real-time systems
event-based application
distributed environment
Institut für Mobile und Verteilte Systeme
J. Luthiger
13
Brian W. Kernighan says...
As personal choice, we tend not to use debuggers beyond getting a
stack trace or the value of a variable or two. One reason is that it is
easy to get lost in details of complicated data structures and control
flow; we find stepping through a program less productive than thinking
harder and adding output statements and self-checking code at critical
places. Clicking over statements takes longer than scanning the output
of judiciously-placed displays. It takes less time to decide where to put
print statements than to single-step to the critical section of code, even
assuming we know where that is. More important, debugging
statements stay with the program; debugging sessions are transient.
In "The Practice of Programming"
Institut für Mobile und Verteilte Systeme
J. Luthiger
14
Approaches to Logging
ƒ System.out.println
Poor performance
‹ All or none – Example below
Some people use a class like:
‹
Class foo{
public static final boolean debug = true;
public void test(){
if (debug) System.out.println(“I exist only in a test environmnet”);
}
}
ƒ Custom log api
‹
‹
More code to maintain
Classic build vs. buy (or use) decision
ƒ Open Source (like Log4j)
Institut für Mobile und Verteilte Systeme
J. Luthiger
15
Java Specification Request JSR 47
ƒ Enable/disable logging at runtime
ƒ Control logging at a fairly fine granularity
‹
Disable logging for specific functionality
ƒ Bridge services that connect the logging APIs to existing
logging services (Operating System Logs, Third party
logs)
Institut für Mobile und Verteilte Systeme
J. Luthiger
16
Requirements for a Logging Framework
ƒ Configuration of the logging features should be
externalized
ƒ Log messages should have priorities
ƒ Logging should support different message
formats
ƒ Logging should not slow down the program
speed, it must support message caching
Institut für Mobile und Verteilte Systeme
J. Luthiger
17
Logging Frameworks
ƒ Log4j:
Apache Open Source Project
http://jakarta.apache.org/log4j
ƒ Java1.4 Logging
Logging API by SUN
introduced with JDK1.4
http://java.sun.com/j2se/1.4.1/docs/guide/util/logging/
Institut für Mobile und Verteilte Systeme
J. Luthiger
18
log4j background
ƒ Originally developed by IBM at their Zurich
research lab. (www.zurich.ibm.com)
ƒ Currently maintained by Source Forge
ƒ Open source
ƒ Release 1.0+ documentation at
http://logging.apache.org/log4j/docs/
Institut für Mobile und Verteilte Systeme
J. Luthiger
19
Basic API
ƒ As of 1.0, printing messages are of the form:
debug(Object message, Throwable t)
debug(Object message)
If the 1st argument is a String object, it will be written in its present
form. Other objects rendered by a registered Object Renderer for its
class or using the Object.toString method.
Institut für Mobile und Verteilte Systeme
J. Luthiger
20
Basic Usage Example
ƒ Standard usage:
class Foo {
Logger logger = null;
public Foo(){
logger = Logger.getLogger(Foo.class);
logger.info(“Constructing foo”);
}
public String doStuff(Long x){
logger.debug(“doing stuff”);
}
}
Institut für Mobile und Verteilte Systeme
J. Luthiger
21
Priorities
ƒ Five recognized message priorities:
DEBUG,INFO,WARN,ERROR ,FATAL
ƒ Priority specific log methods following the the form:
‹ debug(Object message);
‹ debug(Object message, Throwable throwable);
‹
ƒ General log methods for wrappers and custom priorities:
‹
‹
log(Priority level, Object message);
log(Priority level, Object message,Throwable throwable);
ƒ Localized log methods supporting ResourceBundles:
‹
‹
‹
L7dlog(Priority level, String message, Throwable throwable)
L7dlog(Priority level, Object[] params, Throwable throwable)
setResourceBundle(ResourceBundle);
Institut für Mobile und Verteilte Systeme
J. Luthiger
22
Priorities Usage
ƒ DEBUG
‹
‹
Least Importance Level
Log requests that are relevant while debugging the application.
ƒ INFO
‹
Log requests that informs the user of the application about
something (e.g., informs him about application progress)
ƒ WARN
‹
Log requests to alert about harmful situations.
ƒ ERROR
‹
When an error is encountered (but you application can still run).
ƒ FATAL
‹
In case of very sever errors after which your application cannot
continue any more.
Institut für Mobile und Verteilte Systeme
J. Luthiger
23
Loggers
The notion of loggers lies at the heart of log4j.
ƒ Loggers define a hierarchy and give the programmer run-time
control on which statements are printed or not.
ƒ Loggers are assigned priorities. A log statement is printed
depending on its priority and its category.
ƒ Used to support output to multiple logs (Appenders) at the same
time.
logger = Logger.getLogger(User.class);
Institut für Mobile und Verteilte Systeme
J. Luthiger
24
Logger Names
ƒ Name loggers by locality.
‹
It turns out that instantiating a logger in each class, with the
logger name equal to the fully-qualified name of the class, is a
useful and straightforward approach of defining loggers.
ƒ However, this is not the only way for naming loggers. A
common alternative is to name loggers by functional
areas. For example, the "database" category, "RMI"
category, "security" category, or the "XML" category.
Institut für Mobile und Verteilte Systeme
J. Luthiger
25
Benefits of using fully qualified class names
ƒ It is very simple to implement.
ƒ It is very simple to explain to new developers.
ƒ It automatically mirrors the application's own
modular design.
ƒ It can be further refined at will.
ƒ Printing the logger automatically gives
information on the locality of the log statement.
Institut für Mobile und Verteilte Systeme
J. Luthiger
26
Root Logger
ƒ If no logger is defined via a configuration file or
programmatically, then all messages will be sent to the
root logger.
ƒ All loggers define
‹
‹
a priority level
an appender
# set log level of rental package to DEBUG
log4j.logger.ch.fhnw.edu.rental=DEBUG
# configuration of stdout appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
Institut für Mobile und Verteilte Systeme
J. Luthiger
27
Appenders
ƒ An Appender is a object that sends log messages to their final
destination.
‹
‹
‹
‹
‹
‹
‹
‹
‹
‹
ConsoleAppender - Write log to System.out or System.err
FileAppender – Write to a log file
SocketAppender – Dumps log output to a socket
SyslogAppender – Write to the syslog.
NTEventLogAppender – Write the logs to the NT Event Log system.
RollingFileAppender – After a certain size is reached it will rename the
old file and start with a new one.
SocketAppender – Dumps log output to a socket
SMTPAppender – Send Messages to email
JMSAppender – Sends messages using Java Messaging Service
…
ƒ … or create your own!
Institut für Mobile und Verteilte Systeme
J. Luthiger
28
PatternLayout – Customize your message
ƒ Used to customize the layout of a log entry. The format is closely related to
ƒ
conversion pattern of the printf function in ‘c’
see
http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html
ƒ The following options are available:
‹
‹
‹
‹
‹
‹
c - Used to output the Logger name of the logging event.
C - Used to output the fully qualified class name of the caller issuing the logging
request.
d - Used to output the date of the logging event.
The date conversion specifier may be followed by a date format specifier
enclosed between braces.
For example: %d{HH:mm:ss,SSS} or %d{dd MMM yyyy HH:mm:ss,SSS}.
If no date format specifier is given then ISO8601 format is assumed
F - Used to output the file name where the logging request was issued.
l - Used to output location information of the caller which generated the logging
event. (C+M+L)
L - Used to output the line number from where the logging request was issued.
Performance penalty!
Institut für Mobile und Verteilte Systeme
J. Luthiger
29
PatternLayout – Customize your message
‹
‹
‹
‹
‹
n - Outputs the platform dependent line separator character or characters.
M - Used to output the method name where the logging request was issued.
p - Used to output the priority of the logging event.
t - Used to output the name of the thread that generated the logging event.
x - Used to output the NDC (nested diagnostic context) associated with the
thread that generated the logging event.
Institut für Mobile und Verteilte Systeme
J. Luthiger
30
Sample log4j.xml
ƒ log4j.xml will be searched first
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.SimpleLayout"></layout>
</appender>
<root>
<priority value="debug"></priority>
<appender-ref ref="stdout"/>
</root>
</log4j:configuration>
Institut für Mobile und Verteilte Systeme
J. Luthiger
31
Sample log4j.properties
log4j.rootLogger=info, stdout
# set log level of rental package to DEBUG
log4j.logger.ch.fhnw.edu.rental=debug
# configuration of stdout appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
Institut für Mobile und Verteilte Systeme
J. Luthiger
32
Logging performance
ƒ Log4j claims to be fast and flexible:
speed first
‹ flexibility second
‹
ƒ Although log4j has a many features, its first
design goal was speed.
‹
Some log4j components have been rewritten many
times to improve performance.
Institut für Mobile und Verteilte Systeme
J. Luthiger
33
Cost of logging
ƒ When logging is turned off entirely or just for a set of
priorities, the cost of a log request consists of a method
invocation plus an integer comparison.
ƒ The typical cost of actually logging is about 100 to 300
microseconds. This is the cost of formatting the log
output and sending it to its target destination.
logger.debug("Entry number: " + i + " is " +
String.valueOf(entry[i]));
Example:
constructing the message parameter, i.e. converting both integer i and
entry[i] to a String, and concatenating intermediate strings, regardless of
whether the message will be logged or not
Institut für Mobile und Verteilte Systeme
J. Luthiger
34
Hidden costs of logging
ƒ Method invocation involves the "hidden" cost of
parameter construction.
ƒ To avoid the parameter construction cost write:
if (logger.isDebugEnabled() {
logger.debug("Entry number: " + i + " is " +
String.valueOf(entry[i]));
}
Institut für Mobile und Verteilte Systeme
J. Luthiger
35
Some best practices
ƒ Don't use e.printStackTrace()
use log.error("Exception message", e)
instead
ƒ Don't log exception and throw it again
ƒ Don't swallow the Stack Trace
} catch(SQLException e){
throw new RuntimeException("DB excpetion"+e.getMessage());
}
Institut für Mobile und Verteilte Systeme
J. Luthiger
36
Apache Commons Logging JCL
ƒ The Logging package is an ultra-thin bridge
between different logging implementations.
ƒ Commons Logging will guess (discover) the
preferred logging system and you won't need to
do any configuration of JCL at all!
ƒ There are two base abstractions used by JCL:
Log (the basic logger)
‹ LogFactory (which knows how to create Log
instances).
‹
Institut für Mobile und Verteilte Systeme
J. Luthiger
37
Using JCL
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
...
private Log log = LogFactory.getLog(this.getClass());
...
if (log.isDebugEnabled()) {
log.debug("Song '" + song.getTitle() + "' added to playlist");
}
Institut für Mobile und Verteilte Systeme
J. Luthiger
38