简介
对于 经常使用 printf or cout 的人来说 如果有这个日志系统的话,对于每次程序中的发生的错误可以了如职掌。 没必要 每次遇到问题 了解大致的逻辑然后 添加打印。后面章节中还提到一些技巧jconsole 的使用之类的。
java 日志代码
package cn;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class LoggingImageViewer {
public static void main(String[] args){
if(System.getProperty("java.util.logging.config.class") == null && System.getProperty("java.util.logging.config.file") == null){
try{
Logger.getLogger("com.horstmann.corejava").setLevel(Level.ALL);
final int LOG_ROTATION_COUNT = 10;
Handler handler = new FileHandler("%h/LoggingImageViewer.log", 0, LOG_ROTATION_COUNT);
Logger.getLogger("com.horstmann.corejava").addHandler(handler);
}
catch (IOException e){
Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE, "Can't create log file handler", e);
}
}
EventQueue.invokeLater(()->{
Handler windowHandler = new WindowHandler();
windowHandler.setLevel(Level.ALL);
Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler);
JFrame frame = new ImageViewerFrame();
frame.setTitle("LoggingImageViewer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Logger.getLogger("com.horstmann.corejava").fine("Showing frame");
frame.setVisible(true);
});
}
}
class ImageViewerFrame extends JFrame{
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 400;
private JLabel label;
private static Logger logger = Logger.getLogger("com.horstmann.corejava");
public ImageViewerFrame(){
logger.entering("ImageViewerFrame", "<int>");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
// set up menu bar
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu menu = new JMenu("File");
menuBar.add(menu);
JMenuItem openItem = new JMenuItem("Open");
menu.add(openItem);
openItem.addActionListener(new FileOpenListener());
JMenuItem exitItem = new JMenuItem("Exit");
menu.add(exitItem);
exitItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
logger.fine("Exiting.");
System.exit(0);
}
});
// use a label to display the images
label = new JLabel();
add(label);
logger.exiting("ImageViewerFrame", "<int>");
}
private class FileOpenListener implements ActionListener{
public void actionPerformed(ActionEvent event){
logger.entering("ImageViewerFrame.FileOpenListener", "actionPerformed", event);
// set up file chooser
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setFileFilter(new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
return f.getName().toLowerCase().endsWith(".gif") || f.isDirectory();
}
public String getDescription(){
return "GIF Images";
}
});
// show file chooser dialog
int r = chooser.showOpenDialog(ImageViewerFrame.this);
// if image file accepted, set it as icon of the label
if(r == JFileChooser.APPROVE_OPTION){
String name = chooser.getSelectedFile().getPath();
logger.log(Level.FINE, "Reading file {0}", name);
label.setIcon(new ImageIcon(name));
}
else logger.fine("File open dialog canceled.");
logger.exiting("ImageViewerFrame.FileOpenListener", "actionPerformed");
}
}
}
class WindowHandler extends StreamHandler{
private JFrame frame;
public WindowHandler(){
frame = new JFrame();
final JTextArea output = new JTextArea();
output.setEditable(false);
frame.setSize(200, 200);
frame.add(new JScrollPane(output));
frame.setFocusableWindowState(false);
frame.setVisible(true);
setOutputStream(new OutputStream(){
public void write(int b){}
public void write(byte[] b, int off, int len){
output.append(new String(b, off, len));
}
});
}
public void publish(LogRecord record){
if(!frame.isVisible()) return;
super.publish(record);
flush();
}
}
Q&A
Q: 为什么要重写 publish 函数
publish 函数是因为数据流有缓冲区,当有数据过来的时候直接输出,而不是将其缓冲起来等待一定的时间再输出
public void publish(LogRecord record){
if(!frame.isVisible()) return;
super.publish(record);
flush();
}
Q: "%h/LoggingImageViewer.log" 是什么意思
%h 表示在用户主目录 user.home 在windows 中是 C:\Users\lee 目录下面 生成文件 LoggingImageViewer.log.0
Logger.getLogger("com.horstmann.corejava").addHandler(handler); // logger 都是要在某个处理器下工作的。
简单介绍 ImageViewerFrame 类的功能
就是现实图片,但是异常处理主要通过另外一个类来实现 FileOpenListener 。所有的关于读取文件的异常通过这个文件的接口实现。
---------------------------我的天空里没有太阳,总是黑夜,但并不暗,因为有东西代替了太阳。虽然没有太阳那么明亮,但对我来说已经足够。凭借着这份光,我便能把黑夜当成白天。我从来就没有太阳,所以不怕失去。
--------《白夜行》