簡易Java日誌(Log)輸出工具的封裝
阿新 • • 發佈:2019-02-07
平時 Java 專案的開發通常需要統一管理日誌(Log)的輸出,例如控制日誌資訊輸送的目的地(控制檯、檔案等),控制每一條日誌的輸出格式,把日誌分為不同的級別等。常用的比較成熟的 Java 日誌管理工具有 Apache 的 Log4j 等。但有時我們平時一時興趣想寫個小Dmeo或小工具,想較好的控制日誌的輸出,引入專業的日誌管理庫又顯得比較繁瑣,下面我就自己封裝一個簡單的日誌工具類(LogUtils.java
),需要用時拷貝即用。
該LogUtils
工具類支援 4 種日誌級別(debug、info、warn、error),可以把日誌資訊格式化輸出到 控制檯 或 檔案。
使用方法如下:
package com.xiets.log;
import java.io.File;
public class Main {
private static final String TAG = "Main";
public static void main(String[] args) throws Exception {
// (可選) 設定日誌輸出級別, 預設為 INFO 級別
LogUtils.setLogOutLevel(LogUtils.Level.DEBUG);
// (可選) 設定日誌輸出檔案(追加到檔案尾部)
LogUtils.setLogOutFile(new File("MyLog.log"));
// (可選) 設定日誌輸出位置(是否輸出到控制檯 和 是否輸出到檔案), 預設只輸出到控制檯, 不輸出到檔案
LogUtils.setLogOutTarget(true, true);
// 輸出日誌
LogUtils.debug(TAG, "The debug log.");
LogUtils.info(TAG, "The info log.");
LogUtils.warn(TAG, "The warn log.");
LogUtils.error(TAG, "The error log." );
}
}
LogUtils.java
日誌工具類的封裝:
package com.xiets.log;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日誌輸出工具 <br/><br/>
*
* 可以輸出到控制檯和指定的檔案中, 分為4個級別, 由低到高分別為: debug, info, warn, error
*
* <br/><br/>
*
* 輸出級別:
*
* <ul>
* <li> debug: 輸出 debug, info, warn, error </li>
* <li> info: 輸出 info, warn, error </li>
* <li> warn: 輸出 warn, error </li>
* <li> error: 輸出 error </li>
* </ul>
*
* 預設為 info 輸出級別
*
* <p/>
*
* Demo:
*
* <pre>{@code
* // (可選) 設定日誌輸出級別, 預設為 INFO 級別
* LogUtils.setLogOutLevel(LogUtils.Level.DEBUG);
*
* // (可選) 設定日誌輸出檔案(追加到檔案尾部)
* LogUtils.setLogOutFile(new File("MyLog.log"));
*
* // (可選) 設定日誌輸出位置(是否輸出到控制檯 和 是否輸出到檔案), 預設只輸出到控制檯, 不輸出到檔案
* LogUtils.setLogOutTarget(true, true);
*
* // 輸出日誌
* LogUtils.debug("TAG", "The debug log.");
* LogUtils.info("TAG", "The info log.");
* LogUtils.warn("TAG", "The warn log.");
* LogUtils.error("TAG", "The error log.");
* }</pre>
*
* @author xietansheng
*/
public class LogUtils {
/** 每條 Log 的 tag 輸出的最大長度, 超過部分將被截斷 */
private static final int TAG_MAX_LENGTH = 20;
/** 每條 Log 的 message 輸出的最大長度, 超過部分將被截斷 */
private static final int MESSAGE_MAX_LENGTH = 1024;
/** 日期字首格式化 */
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS");
/** 日誌當前的輸出級別, 預設為 INFO 級別 */
private static Level logOutLevel = Level.INFO;
/** 是否輸出到控制檯, 預設輸出 */
private static boolean isOutToConsole = true;
/** 是否輸出到檔案 */
private static boolean isOutToFile = false;
/** 日誌輸出檔案, 追加到檔案尾 */
private static File logOutFile;
/** 日誌檔案輸出流, 追加到檔案尾 */
private static RandomAccessFile logOutFileStream;
public static void setLogOutLevel(Level currentLevel) {
if (currentLevel == null) {
currentLevel = Level.INFO;
}
LogUtils.logOutLevel = currentLevel;
}
public static synchronized void setLogOutFile(File logOutFile) throws IOException {
LogUtils.logOutFile = logOutFile;
if (logOutFileStream != null) {
closeStream(logOutFileStream);
logOutFileStream = null;
}
if (LogUtils.logOutFile != null) {
try {
logOutFileStream = new RandomAccessFile(LogUtils.logOutFile, "rw");
logOutFileStream.seek(LogUtils.logOutFile.length());
} catch (IOException e) {
closeStream(logOutFileStream);
logOutFileStream = null;
throw e;
}
}
}
public static void setLogOutTarget(boolean isOutToConsole, boolean isOutToFile) {
LogUtils.isOutToConsole = isOutToConsole;
LogUtils.isOutToFile = isOutToFile;
}
public static void debug(String tag, String message) {
printLog(Level.DEBUG, tag, message, false);
}
public static void info(String tag, String message) {
printLog(Level.INFO, tag, message, false);
}
public static void warn(String tag, String message) {
printLog(Level.WARN, tag, message, false);
}
public static void error(String tag, String message) {
printLog(Level.ERROR, tag, message, true);
}
public static void error(String tag, Exception e) {
if (e == null) {
error(tag, (String) null);
return;
}
PrintStream printOut = null;
try {
ByteArrayOutputStream bytesBufOut = new ByteArrayOutputStream();
printOut = new PrintStream(bytesBufOut);
e.printStackTrace(printOut);
printOut.flush();
error(tag, new String(bytesBufOut.toByteArray(), "UTF-8"));
} catch (Exception e1) {
e1.printStackTrace();
} finally {
closeStream(printOut);
}
}
private static void printLog(Level level, String tag, String message, boolean isOutToErr) {
if (level.getLevelValue() >= logOutLevel.getLevelValue()) {
String log = DATE_FORMAT.format(new Date()) +
" " +
level.getTag() +
"/" +
checkTextLengthLimit(tag, TAG_MAX_LENGTH) +
": " +
checkTextLengthLimit(message, MESSAGE_MAX_LENGTH);
if (isOutToConsole) {
outLogToConsole(isOutToErr, log);
}
if (isOutToFile) {
outLogToFile(log);
}
}
}
private static void outLogToConsole(boolean isOutToErr, String log) {
if (isOutToErr) {
// System.err 和 System.out 是兩個不同的輸出流通道, 如果極短時間內連
// 續輸出 log 到 err 和 out, 控制檯上的列印順序可能會不完全按時序列印.
System.err.println(log);
} else {
System.out.println(log);
}
}
private static synchronized void outLogToFile(String log) {
if (logOutFileStream != null) {
try {
logOutFileStream.write((log + "\n").getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String checkTextLengthLimit(String text, int maxLength) {
if ((text != null) && (text.length() > maxLength)) {
text = text.substring(0, maxLength - 3) + "...";
}
return text;
}
private static void closeStream(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
// nothing
}
}
}
public static enum Level {
DEBUG("D", 1), INFO("I", 2), WARN("W", 3), ERROR("E", 4);
private String tag;
private int levelValue;
private Level(String tag, int levelValue) {
this.tag = tag;
this.levelValue = levelValue;
}
public String getTag() {
return tag;
}
public int getLevelValue() {
return levelValue;
}
}
}
控制檯輸出結果:
日誌檔案輸出結果: