Log4j 1.x(舊版)常透過 `log4j.properties`/`xml` 配置,但也可完全用程式碼動態建立 `Logger`、加入 `ConsoleAppender`/`FileAppender`、設定 `PatternLayout`、閾值等。適合嵌入式元件、測試環境或不想外置配置檔的場合。
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
public final class LogUtil {
private static final String DEFAULT_PATTERN = "%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%n";
private LogUtil() {}
/**
* 取得同時輸出到 Console 與 File 的 Logger
* @param clazz 呼叫類別 (用於分類)
* @param logFile 日誌檔完整路徑 (含檔名)
* @param consoleLevel Console 輸出層級
* @param fileLevel File 輸出層級
*/
public static Logger getLogger(Class> clazz, String logFile,
Level consoleLevel, Level fileLevel) {
Logger logger = Logger.getLogger(clazz);
logger.setLevel(Level.ALL); // Logger 層級設最低,由 Appender 控制
logger.setAdditivity(false); // 不向父 Logger 傳遞,避免重複輸出
PatternLayout layout = new PatternLayout(DEFAULT_PATTERN);
// Console Appender
ConsoleAppender console = new ConsoleAppender(layout);
console.setThreshold(consoleLevel);
console.activateOptions();
logger.addAppender(console);
// File Appender
FileAppender file = new FileAppender(layout, logFile, true); // true = append
file.setEncoding("UTF-8");
file.setThreshold(fileLevel);
file.activateOptions();
logger.addAppender(file);
return logger;
}
/** 僅 Console 輸出 */
public static Logger getConsoleLogger(Class> clazz, Level level) {
Logger logger = Logger.getLogger(clazz);
logger.setLevel(Level.ALL);
logger.setAdditivity(false);
ConsoleAppender console = new ConsoleAppender(new PatternLayout(DEFAULT_PATTERN));
console.setThreshold(level);
console.activateOptions();
logger.addAppender(console);
return logger;
}
/** 僅 File 輸出 */
public static Logger getFileLogger(Class> clazz, String logFile, Level level) {
Logger logger = Logger.getLogger(clazz);
logger.setLevel(Level.ALL);
logger.setAdditivity(false);
FileAppender file = new FileAppender(new PatternLayout(DEFAULT_PATTERN), logFile, true);
file.setEncoding("UTF-8");
file.setThreshold(level);
file.activateOptions();
logger.addAppender(file);
return logger;
}
}
public class Demo {
private static final Logger LOG = LogUtil.getLogger(Demo.class, "logs/app.log", Level.INFO, Level.DEBUG);
public static void main(String[] args) {
LOG.info("啟動完成");
LOG.debug("除錯資訊:僅寫入檔案");
LOG.warn("警告訊息:Console 也會顯示");
}
}
setAdditivity(false):關鍵!防止日誌同時被 Root Logger 輸出導致重複。activateOptions():Log4j 1.x 必須呼叫,才會套用 Appender 設定。PatternLayout:%d 時間、%t 執行緒、%p 層級、%c{1} 類別簡短名、%L 行號、%m 訊息。FileAppender(..., true):第二參數 `append=true` 續寫,`false` 覆蓋。Log4j 1.x 已停止維護(EOL 2015),且有安全性風險。新專案強烈建議:
程式化配置 Logback 範例:
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.FileAppender;
import org.slf4j.LoggerFactory;
LoggerContext ctx = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(ctx);
encoder.setPattern(DEFAULT_PATTERN);
encoder.start();
ConsoleAppender<ch.qos.logback.classic.spi.ILoggingEvent> console = new ConsoleAppender<>();
console.setContext(ctx);
console.setEncoder(encoder);
console.start();
ch.qos.logback.classic.Logger logger = ctx.getLogger(Demo.class);
logger.addAppender(console);
logger.setLevel(Level.INFO);
logger.setAdditive(false);