仿log4j定制自己的Log工具类

原由:

log4j是很强大,可每次使用还要加入log4j包,还要使用配置文件。对于一般的小工具或小项目感觉还是有点大动作了。而且在使用log4j时每次还要每取个实例再传个参数来记录,感觉有点麻烦。就自己仿log4j使用jdk logger定制了一个自己的记录工具类。

 

工具类特点:

  • 无配置文件,默认为info级别,控制台输出,无需改动即可满足一般开发需要。。
  • 直接打log,在java文件中直接使用 Log.info("test"); 即可,如果输出到文件,则自动按不同级别生成不同记录文件
  • 使用四个级别的log。分别为 Log.debug(""); Log.info(""); Log.warn(""); Log.error(""); 对于一般项目已经足够。
  • log输出方式有两种,控制台输出和文件输出。输出格式两者统一。文件输出时的文件路径可定制。默认为class文件夹下,名称格式为 等级_时间.log 如: INFO_2011-10-12.log

工具类的使用:
直接默认配置
   Log.debug("debug");
        Log.info("info");
        Log.info("info1");
        Log.warn("warn");
        Log.error("error");
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            Log.error(e);
        }
 结果:
2012-03-02 16:25:03 NewClass.java(Line:19): [INFO] info
2012-03-02 16:25:03 NewClass.java(Line:20): [INFO] info1
2012-03-02 16:25:03 NewClass.java(Line:21): [WARN] warn
2012-03-02 16:25:03 NewClass.java(Line:22): [ERROR] error
2012-03-02 16:25:03 NewClass.java(Line:26): 
java.lang.Exception: exception
at com.dfhstudio.thoughtfly.util.NewClass.main(NewClass.java:24)

要想使用文件记录,要改点代码变量,看javadoc注释



费话不说,直接上代码
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.logging.ConsoleHandler;
import java.util.logging.ErrorManager;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;

/**
 *  <b>自定义LOG工具,丁风华</b>
 * <ul>
 * <b>特点</b>
 * <li>无配置文件,默认为info级别,控制台输出,无需改动即可满足一般开发需要。。</li>
 * <li>直接打log,在java文件中直接使用 <code>Log.info("test");</code> 即可,如果输出到文件,则自动按不同级别生成不同记录文件</li>
 * <li>使用四个级别的log。分别为 <code>Log.debug(""); Log.info(""); Log.warn(""); Log.error("");</code> 对于一般项目已经足够。</li>
 * <li>log输出方式有两种,控制台输出和文件输出。输出格式两者统一。文件输出时的文件路径可定制。默认为class文件夹下,名称格式为 等级_时间.log 如: INFO_2011-10-12.log</li>
 * </ul>
 * <ul>
 * <b>输出到文件使用方法</b><br>
 * 更改构造器方法中的数据. private Log()<br>
 * 1.设置输出级别: setLogLevel("info");<br>
 * 2.设置输出到文件: HANDLER_FILE = true;<br>
 * 3.设置设置文件保存路径: LOG_FILE_PATH = "D:\\log\\";<br>
 * 4.设置每个文件的最大值: FILE_SIZE = 2000000; // *** 每个文件最大2M <br>
 * 5.设置每天最多生成多少个文件数量: FILE_MAX = 10; // *** 每天最多生成10个文件,最多不可超过100<br>
 * 6.设置log文件后缀名: LOG_FILE_LASTNAME = ".log";
 * </ul>
 * <ul>
 * <b>更改记录内容的格式</b><br>
 * 可更改 dealInfoFormat 方法中的 formatMessage 变量值即可。
 * </ul>
 * 
 * @author DingFengHua
 */
public class Log {

    private Log() {
        setLogLevel("INFO");

        HANDLER_CONSOLE = true; // *** 控制台输出
        HANDLER_FILE = false; // *** 文件输出

        // *** 如果不想使用文件打LOG,即 HANDLER_FILE = false;,则不用关心以下数据
        // *** 自动创建路径文件夹
        if (HANDLER_FILE) {

            // *** 1. LOG文件夹在class文件夹目录下
            // LOG_FILE_PATH = new File(Log.class.getClassLoader().getResource(".").getFile()).toString() + "/log/";
            // *** 2. 如果是web项目,LOG文件夹在项目根目录下
            LOG_FILE_PATH = new File(Log.class.getClassLoader().getResource("/").getFile()).toString() + "/../../log/";

            FILE_SIZE = 2000000; // *** 每个文件最大2M
            FILE_MAX = 10; // *** 每天最多生成10个文件,最多不可超过100

            LOG_FILE_LASTNAME = ".log"; // *** 文件后缀名
        }
    }

    /*
     * 以下内容不必更改**********************************************************************************************************
     */
    /* ************************************************************************************************************************* */
    private String getLogFileName(String level) {
        String firtFileName = LOG_FILE_PATH + level + "_" + getDateFormat("yyyy-MM-dd", new Date()) + LOG_FILE_LASTNAME;
        return firtFileName;
    }

    /**
     * 从字符串转换为JDKLOG的LEVEL等级
     * 
     * @param strLevel 自定义的等级字符串
     * @return JDKLOG的等级
     */
    private Level getLogLevelFromString(String strLevel) {
        Level l = Level.INFO;

        if (LEVEL_DEBUG.equalsIgnoreCase(strLevel)) {
            l = Level.FINE;
        }

        if (LEVEL_WARN.equalsIgnoreCase(strLevel)) {
            l = Level.WARNING;
        }

        if (LEVEL_ERROR.equalsIgnoreCase(strLevel)) {
            l = Level.SEVERE;
        }

        return l;
    }

    /**
     * 低等级记录
     * 
     * @param info 记录信息
     */
    public static void debug(String info) {
        INSTANCE.log(LEVEL_DEBUG, "[" + LEVEL_DEBUG + "] " + info, null);
    }

    /**
     * 普通信息记录
     * 
     * @param info 记录信息
     */
    public static void info(String info) {
        INSTANCE.log(LEVEL_INFO, "[" + LEVEL_INFO + "] " + info, null);
    }

    /**
     * 警告信息记录
     * 
     * @param info 记录信息
     */
    public static void warn(String info) {
        INSTANCE.log(LEVEL_WARN, "[" + LEVEL_WARN + "] " + info, null);
    }

    /**
     * 错误信息记录
     * 
     * @param info 记录信息
     */
    public static void error(String info) {
        INSTANCE.log(LEVEL_ERROR, "[" + LEVEL_ERROR + "] " + info, null);
    }

    /**
     * 错误信息记录
     * 
     * @param info 异常
     */
    public static void error(Throwable info) {
        INSTANCE.log(LEVEL_ERROR, "", info);
    }

    /**
     * 处理记录信息
     * 
     * @param level 信息等级
     * @param info  信息内容
     * @param exception  异常信息
     */
    private void log(String level, String info, Throwable exception) {
        checkFileDate(level);
        Logger logger = Logger.getLogger(level);
        if (!logList.contains(level)) {
            logList.add(level);
            dealHander(logger);
            dealInfoFormat(logger);
        }
        logger.setLevel(logOutPutLevel);
        logger.log(getLogLevelFromString(level), info, exception);

    }

    /**
     * 内容格式化,默认内容格式为 时间 文件名(行数):[等级] 内容
     * 
     * @param logger JDK Log
     */
    private void dealInfoFormat(Logger logger) {
        logger.setUseParentHandlers(false);

        StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();

        final StackTraceElement element = stackTraceElement[stackTraceElement.length - 1];

        for (Handler handler : logger.getHandlers()) {
            handler.setFormatter(new Formatter() {

                @Override
                public String format(LogRecord record) {
                    StringBuilder formatMessage = new StringBuilder();
                    formatMessage.append(getDateFormat("yyyy-MM-dd HH:mm:ss", new Date()));
                    formatMessage.append(" ").append(element.getFileName()).append("(Line:")
                                    .append(element.getLineNumber()).append("):").append(" ")
                                    .append(record.getMessage()).append("\n");

                    if (record.getThrown() != null) {
                        try {
                            StringWriter sw = new StringWriter();
                            PrintWriter pw = new PrintWriter(sw);
                            record.getThrown().printStackTrace(pw);
                            pw.close();
                            formatMessage.append(sw.toString());
                        } catch (Exception ex) {
                        }
                    }

                    return formatMessage.toString();
                }
            });
        }

    }

    /**
     * 输出处理,控制台和文件,文件输出的文件名格式为 等级_yyyy-MM-dd.log 如果有多个文件,会在文件名后递增数字
     * 
     * @param logger jdk log
     */
    private void dealHander(Logger logger) {
        boolean alreadyHasConsole = false, alreadyHasFile = false;
        Handler[] handlers = logger.getHandlers();
        for (int i = 0; i < handlers.length; i++) {
            if (handlers[i] instanceof ConsoleHandler) {
                alreadyHasConsole = true;
            } else if (handlers[i] instanceof MyFileHandler) {
                alreadyHasFile = true;
            }
        }

        if (HANDLER_CONSOLE && !alreadyHasConsole) {

            ConsoleHandler ch = new ConsoleHandler();
            ch.setLevel(logOutPutLevel);
            logger.addHandler(ch);
        }

        if (HANDLER_FILE && !alreadyHasFile) {

            String file = getLogFileName(logger.getName());

            File f = new File(LOG_FILE_PATH);
            if (!f.isDirectory()) {
                f.mkdirs();
                f.mkdir();
            }
            try {
                MyFileHandler fh = new MyFileHandler(file, FILE_SIZE, FILE_MAX, true);
                fh.setLevel(logOutPutLevel);
                logger.addHandler(fh);
            } catch (IOException ex) {
                Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(Log.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }

    /**
     * 格式化时间到字符串
     * 
     * @param pattern 格式
     * @param date 时间
     * @return 格式化的字符串
     */
    private String getDateFormat(String pattern, Date date) {
        format.applyPattern(pattern);
        return format.format(date);
    }

    /**
     * 设置输出等级
     * 
     * @param level 自定义等级,可使用 debug,info,warn,error 忽略大小写
     */
    public final void setLogLevel(String level) {
        logOutPutLevel = getLogLevelFromString(level);
    }

    private void checkFileDate(String level) {
        File f = new File(getLogFileName(level));
        if (!f.exists()) {
            for (Handler handler : Logger.getLogger(level).getHandlers()) {
                handler.close();
            }
            logList.remove(level);
        }
    }

    private static String LOG_FILE_PATH;
    private Level logOutPutLevel;
    private int FILE_SIZE;
    private int FILE_MAX;
    private boolean HANDLER_FILE = false;
    private boolean HANDLER_CONSOLE = false;
    private static ArrayList<String> logList = new ArrayList<String>();
    private String LOG_FILE_LASTNAME;
    private static String LEVEL_DEBUG = "DEBUG";
    private static String LEVEL_INFO = "INFO";
    private static String LEVEL_WARN = "WARN";
    private static String LEVEL_ERROR = "ERROR";
    private static Log INSTANCE = new Log();
    SimpleDateFormat format = new SimpleDateFormat();
}

/**
 * 自定义文件输出管理类,参考JDK FileHandler实现
 * 
 * @author DingFengHua
 */
class MyFileHandler extends StreamHandler {

    private MeteredStream meter;
    private boolean append;
    private int limit; // zero => no limit.
    private int count;
    private String pattern;
    private String lockFileName;
    private FileOutputStream lockStream;
    private File files[];
    private static final int MAX_LOCKS = 100;
    private static java.util.HashMap<String, String> locks = new java.util.HashMap<String, String>();

    private class MeteredStream extends OutputStream {

        OutputStream out;
        int written;

        MeteredStream(OutputStream out, int written) {
            this.out = out;
            this.written = written;
        }

        public void write(int b) throws IOException {
            out.write(b);
            written++;
        }

        @Override
        public void write(byte buff[]) throws IOException {
            out.write(buff);
            written += buff.length;
        }

        @Override
        public void write(byte buff[], int off, int len) throws IOException {
            out.write(buff, off, len);
            written += len;
        }

        @Override
        public void flush() throws IOException {
            out.flush();
        }

        @Override
        public void close() throws IOException {
            out.close();
        }
    }

    private void open(File fname, boolean append) throws IOException {
        int len = 0;
        if (append) {
            len = (int) fname.length();
        }
        FileOutputStream fout = new FileOutputStream(fname.toString(), append);
        BufferedOutputStream bout = new BufferedOutputStream(fout);
        meter = new MeteredStream(bout, len);
        setOutputStream(meter);
    }

    public MyFileHandler() throws IOException, SecurityException {
        openFiles();
    }

    public MyFileHandler(String pattern) throws IOException, SecurityException {
        if (pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        this.pattern = pattern;
        this.limit = 0;
        this.count = 1;
        openFiles();
    }

    public MyFileHandler(String pattern, boolean append) throws IOException, SecurityException {
        if (pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        this.pattern = pattern;
        this.limit = 0;
        this.count = 1;
        this.append = append;
        openFiles();
    }

    public MyFileHandler(String pattern, int limit, int count) throws IOException, SecurityException {
        if (limit < 0 || count < 1 || pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        this.pattern = pattern;
        this.limit = limit;
        this.count = count;
        openFiles();
    }

    public MyFileHandler(String pattern, int limit, int count, boolean append) throws IOException, SecurityException {
        if (limit < 0 || count < 1 || pattern.length() < 1) {
            throw new IllegalArgumentException();
        }
        this.pattern = pattern;
        this.limit = limit;
        this.count = count;
        this.append = append;
        openFiles();
    }

    private void openFiles() throws IOException {
        LogManager manager = LogManager.getLogManager();
        manager.checkAccess();
        if (count < 1) {
            throw new IllegalArgumentException("file count = " + count);
        }
        if (limit < 0) {
            limit = 0;
        }

        InitializationErrorManager em = new InitializationErrorManager();
        setErrorManager(em);

        int unique = -1;
        for (;;) {
            unique++;
            if (unique > MAX_LOCKS) {
                throw new IOException("Couldn't get lock for " + pattern);
            }
            lockFileName = generate(pattern, 0, unique).toString() + ".lck";
            synchronized (locks) {
                if (locks.get(lockFileName) != null) {
                    continue;
                }
                FileChannel fc;
                try {
                    lockStream = new FileOutputStream(lockFileName);
                    fc = lockStream.getChannel();
                } catch (IOException ix) {
                    continue;
                }
                try {
                    FileLock fl = fc.tryLock();
                    if (fl == null) {
                        continue;
                    }
                } catch (IOException ix) {
                }
                locks.put(lockFileName, lockFileName);
                break;
            }
        }

        files = new File[count];
        for (int i = 0; i < count; i++) {
            files[i] = generate(pattern, i, unique);
        }
        if (append) {
            open(files[0], true);
        } else {
            rotate();
        }
        Exception ex = em.lastException;
        if (ex != null) {
            if (ex instanceof IOException) {
                throw (IOException) ex;
            } else if (ex instanceof SecurityException) {
                throw (SecurityException) ex;
            } else {
                throw new IOException("Exception: " + ex);
            }
        }
        setErrorManager(new ErrorManager());
    }

    private File generate(String pattern, int generation, int unique) throws IOException {
        File file = null;
        String word = "";
        int ix = 0;
        boolean sawg = false;
        boolean sawu = false;
        while (ix < pattern.length()) {
            char ch = pattern.charAt(ix);
            ix++;
            char ch2 = 0;
            if (ix < pattern.length()) {
                ch2 = Character.toLowerCase(pattern.charAt(ix));
            }
            if (ch == '/') {
                if (file == null) {
                    file = new File(word);
                } else {
                    file = new File(file, word);
                }
                word = "";
                continue;
            } else if (ch == '%') {
                if (ch2 == 't') {
                    String tmpDir = System.getProperty("java.io.tmpdir");
                    if (tmpDir == null) {
                        tmpDir = System.getProperty("user.home");
                    }
                    file = new File(tmpDir);
                    ix++;
                    word = "";
                    continue;
                } else if (ch2 == 'h') {
                    file = new File(System.getProperty("user.home"));
                    if (isSetUID()) {
                        throw new IOException("can't use %h in set UID program");
                    }
                    ix++;
                    word = "";
                    continue;
                } else if (ch2 == 'g') {
                    word = word + generation;
                    sawg = true;
                    ix++;
                    continue;
                } else if (ch2 == 'u') {
                    word = word + unique;
                    sawu = true;
                    ix++;
                    continue;
                } else if (ch2 == '%') {
                    word = word + "%";
                    ix++;
                    continue;
                }
            }
            word = word + ch;
        }
        if (count > 1 && generation > 0 && !sawg) {
            word = word + "." + generation;
        }
        if (unique > 0 && !sawu) {
            word = word + "." + unique;
        }
        if (word.length() > 0) {
            if (file == null) {
                file = new File(word);
            } else {
                file = new File(file, word);
            }
        }
        return file;
    }

    private synchronized void rotate() {
        Level oldLevel = getLevel();
        setLevel(Level.OFF);

        super.close();
        for (int i = count - 2; i >= 0; i--) {
            File f1 = files[i];
            File f2 = files[i + 1];
            if (f1.exists()) {
                if (f2.exists()) {
                    f2.delete();
                }
                f1.renameTo(f2);
            }
        }
        try {
            open(files[0], false);
        } catch (IOException ix) {
            reportError(null, ix, ErrorManager.OPEN_FAILURE);

        }
        setLevel(oldLevel);
    }

    @Override
    public synchronized void publish(LogRecord record) {
        if (!isLoggable(record)) {
            return;
        }
        super.publish(record);
        flush();
        if (limit > 0 && meter.written >= limit) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {

                public Object run() {
                    rotate();
                    return null;
                }
            });
        }
    }

    @Override
    public synchronized void close() throws SecurityException {
        super.close();
        if (lockFileName == null) {
            return;
        }
        try {
            lockStream.close();
        } catch (Exception ex) {
        }
        synchronized (locks) {
            locks.remove(lockFileName);
        }
        new File(lockFileName).delete();
        lockFileName = null;
        lockStream = null;
    }

    private static class InitializationErrorManager extends ErrorManager {

        Exception lastException;

        @Override
        public void error(String msg, Exception ex, int code) {
            lastException = ex;
        }
    }

    private static native boolean isSetUID();

}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值