Hiện nay, trên Java, hầu hết các ứng dụng đều sử dụng Log4J để ghi log ứng dụng. Vì thế với nhiều lập trình viện, thư viện này gần như đã quá đỗi quen thuộc. Mục đích bài viết này chủ yếu tập trung đối tượng người mới tiếp cận Java và cũng để lưu lại thông tin để tiện cho tác giả tra cứu lại!
Tải mã nguồn ví dụ demo cho bài viết: Log4JExample (Chi tiết mô tả ví dụ bạn xem mục 7. Ví du demo)
Nội dung:
1. Giới thiệu thư viện Log4J
2. Sử dụng Log4J (1.x)
3. Mô tả một số cấu hình trong tệp cấu hình Log4J (1.x)
4. Cấu hình ghi log ra tệp thông qua FileAppender
5. Cấu hình ghi log ra nhiều tệp thông qua RollingFileAppender
6. Cấu hình ghi log theo ngày thông qua DailyRollingFileAppender
7. Ví dụ demo
8. Tài liệu tham khảo
1. Giới thiệu thư viện Log4J
Apache Log4J là một framework nhỏ, linh hoạt và dễ sử dụng phục vụ cho việc ghi log ứng dụng qua đó dễ dàng trong việc xác định và sửa lỗi ứng dụng. Hiện Log4J đã có phiên bản 2.x với nhiều cải tiến đáng kể so với phiên bản 1.x, đồng thời cung cấp nhiều cải tiến có sẵn trong Logback và fix một số vấn đề cố hữu trong kiến trúc của Logback. Bạn có thể tham khảo thêm log4php cho ngôn ngữ PHP và log4cxx cho ngôn ngữ C++.Ở bài viết này, tôi tập trung nói về phiên bản 1.x đang được cộng đồng lập trình sử dụng rộng rãi. Phiên bản 2.x là phiên bản mới, có nhiều thay đổi, cách thức sử dụng và cấu hình có khác, tôi sẽ nói trong một bài viết khác.
Trong Log4J, bạn có thể định nghĩa các mức log riêng. Mặc định, Log4J hỗ trợ sẵn các mức mặc định sau:
- ALL: Tất cả các mức bao gồm cả các mức do bạn định nghĩa.
- DEBUG: Chỉ định các thông tin sử dụng để gỡ lỗi ứng dụng.
- ERROR: Chỉ định các sự kiện lỗi mà vẫn có thể cho phép các ứng dụng để tiếp tục chạy.
- FATAL: Chỉ định các sự kiện lỗi rất nghiêm trọng gây chết ứng dụng.
- INFO: Chỉ định các thông tin liên quan xử lý ứng dụng.
- OFF: Mức không ghi log.
- TRACE: Chỉ định các thông tin trên mức DEBUG.
- WARN: Chỉ định các tình huống tiềm tàng có thể gây lên lỗi ứng dụng.
Nguyên tắc ghi log như sau: Một yêu cầu ghi log ở mức p trong một logger với mức q sẽ được kích hoạt nếu p>=q. Đây là quy tắc chính trong Log4J. Thứ tự của các mức mặc định như sau: ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF. Như vậy nếu bạn muốn chỉ ghi các log DEBUG và INFO thì bạn hãy thiết lập mức của Log là WARN.
Thường khi đang phát triển bạn thiết lập mức ghi log là DEBUG để hiển thị tất cả các log từ mức DEBUG trở lên, nhưng khi ứng dụng chạy thật thì bạn chỉ nên thiết lập mức ghi log là INFO hoặc ERROR để tránh việc ghi log quá nhiều gây chậm ứng dụng.
Thường khi đang phát triển bạn thiết lập mức ghi log là DEBUG để hiển thị tất cả các log từ mức DEBUG trở lên, nhưng khi ứng dụng chạy thật thì bạn chỉ nên thiết lập mức ghi log là INFO hoặc ERROR để tránh việc ghi log quá nhiều gây chậm ứng dụng.
2. Sử dụng Log4J
Việc sử dụng Log4J rất đơn giản, bạn chỉ cần thực hiện 03 bước như sau:
* B1: Thêm thư viện Log4J vào Project
Trong trường hợp bạn sử dụng Maven, bạn hãy thêm cấu hình sau vào tệp cấu hình pom.xml của Maven:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Bạn cũng có thể vào trực tiếp trang https://logging.apache.org/log4j/1.2/download.html để download phiên bản 1.x mới nhất sử dụng, hiện tại phiên bản 1.x mới nhất là 1.2.7. Sau khi download về, bạn giải nén và thêm tệp log4j-1.2.17.jar vào lib của ứng dụng.
* B2: Cấu hình Log4J
Để sử dụng Log4J bắt buộc bản phải cấu hình trước. Nếu sử dụng code để cấu hình thì code này phải được gọi trước các code ghi log.
Cách đơn giản nhất để cấu hình là bạn gọi hàm cấu hình mặc định trong lớp org.apache.log4j.BasicConfigurator. Hàm này nên gọi:
BasicConfigurator.configure();
Khi bạn cấu hình bằng cách sử dụng method BasicConfigurator.configure() mặc định nó sử dụng ConsoleAppender và PatternLayout cho tất cả các logger.
Một cách khác bạn có thể cấu hình trực tiếp trong code như sau:
Properties properties = new Properties();
properties.setProperty("log4j.rootLogger", "TRACE,stdout,MyFile");
properties.setProperty("log4j.rootCategory", "TRACE");
properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");
properties.setProperty("log4j.appender.stdout.layout.ConversionPattern", "%d{yyyy/MM/dd HH:mm:ss.SSS} [%5p] %t (%F) - %m%n");
properties.setProperty("log4j.appender.MyFile", "org.apache.log4j.RollingFileAppender");
properties.setProperty("log4j.appender.MyFile.File", "my_example.log");
properties.setProperty("log4j.appender.MyFile.MaxFileSize", "100KB");
properties.setProperty("log4j.appender.MyFile.MaxBackupIndex", "1");
properties.setProperty("log4j.appender.MyFile.layout", "org.apache.log4j.PatternLayout");
properties.setProperty("log4j.appender.MyFile.layout.ConversionPattern", "%d{yyyy/MM/dd HH:mm:ss.SSS} [%5p] %t (%F) - %m%n");
PropertyConfigurator.configure(properties);
Nhưng cách thông dụng và được sử dụng nhiều nhất là sử dụng tệp cấu hình XML hoặc Properties. Mặc định Log4J tự động load tệp cấu hình log4j.properties hoặc log4j.xml trong thư mục WEB-INF/classes (Với ứng dụng Web) và thư mục project/classes (Với ứng dụng Java). Chi tiết tệp cấu hình sẽ trình bày chi tiết trong mục sau.
Ngoài ra bạn có thể chỉ định tới tệp cấu hình ở thư mục bất kỳ bằng lệnh:
String log4jConfigFile = "some/path/log4j.properties";
PropertyConfigurator.configure(log4jConfigFile);
Ngoài ra, bạn còn có thể cấu hình log4j trong tham số của JVM. Bạn chỉ cần thêm tham số sau khi khởi chạy JVM:
-Dlog4j.configuration=file:{path to file}Bắt buộc bạn phải có file: ở trước đường dẫn để Log4J biết theo sau là đường dẫn tới tệp cấu hình.
Với các ứng dụng Web, bạn còn có thể cấu hình đường dẫn tới tệp cấu hình của Log4J trong tệp web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Log4JExample</display-name>
<context-param>
<param-name>log4j-config-location</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</context-param>
</web-app>
Sau đây là ví dụ về tệp cấu hình log4j.properties:
# Root logger option
log4j.rootLogger=DEBUG, stdout, file
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\log4j-application.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
Trong cấu hình này, có lẽ các bạn sẽ thấy khó hiểu nhất ở cấu hình log4j.appender.stdout.layout.ConversionPattern. Chi tiết về ConversionPattern, bạn xem thêm ở địa chỉ: http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html. Ở đây, tôi xin giải thích rõ hơn:- %d{yyyy-MM-dd HH:mm:ss} = Định dạng ngày giờ, tham khảo định dạng trong lớp SimpleDateFormat.
- %-5p = Mức ưu tiên, như DEBUG hoặc ERROR. Còn -5 là tùy chọn thêm để định dạng hiển thị đẹp hơn.
- %c{1} = Tên log được thiết lập thông qua getLogger().
- %L = Xác định dòng (line number) nơi yêu cầu ghi log.
- %m%n = Thông điệp ghi log (message) và dấu ngắt dòng (line break).
* B3: Ghi log ứng dụng bằng các hàm mà Log4J cung cấp
Để ghi log trước tiên bản phải tạo đối tượng Logger ở dạng final static và xác định một tên cho đối tượng này, thông thường là tên đầy đủ của lớp để tiện cho việc debug ứng dụng:
final static Logger logger = Logger.getLogger(classname.class);
Tất nhiên bạn có thể đặt tên bất kỳ: final static Logger logger = Logger.getLogger("MyFile");
Sau khi có đối tượng này rồi, bạn sử dụng các hàm có sẵn của đối tượng này (debug, info, warn, error và fatal) để ghi log. Việc chọn hàm phụ thuộc nhiều vào chủ quan của người lập trình, nhưng các bạn nên sử dụng các hàm đúng với mức của sự kiện hoặc thông báo.
import org.apache.log4j.Logger;
public class Log4JExample03 {
private static final Logger logger = Logger.getLogger("MyFile");
public static void main(String[] args) {
logger.fatal("This is a FATAL message.");
logger.error("This is an ERROR message.");
logger.warn("This is a WARN message.");
logger.info("This is an INFO message.");
logger.debug("This is a DEBUG message.");
logger.trace("This is a TRACE message.");
try {
// ...
} catch (Exception e) {
logger.error("This is an ERROR message.", e);
}
}
}
Thông thường các ứng dụng đều sử dụng file để cấu hình Log4J bởi tính tiện dụng của nó trong việc thay đổi cấu hình mà không cần sửa code. Trong tệp cấu hình, bạn cũng có thể sử dụng biến môi trường trong hệ điều hành bằng cách sử dụng cú pháp: ${TÊN_BIẾN}.
Tệp cấu hình log4j.properties có dạng như dưới:
Các dòng tiếp theo là danh sách các Appender. Các dòng tiếp theo sẽ định nghĩa các Appender được khai báo ở dòng đầu tiên. Các Appender sẽ chịu trách nhiệm in ấn thông điệp tới một nơi xác định. Tất cả các Appender đều có các thuộc tính chung như sau:
Tệp cấu hình log4j.properties có dạng như dưới:
# Định nghĩa một rootLogger
log4j.rootLogger = LOG_LEVEL, APPENDER1, APPENDER2,...
# Định nghĩa một Appender
log4j.appender.APPENDER1 = CLASS_TO_APPENDER
log4j.appender.APPENDER1.Property_11 = value_11
log4j.appender.APPENDER1.Property_12 = value_12
...
log4j.appender.APPENDER1.Property_1n = value_1n
# Định nghĩa một Appender
log4j.appender.APPENDER2 = CLASS_TO_APPENDER
log4j.appender.APPENDER2.Property_21 = value_21
log4j.appender.APPENDER2.Property_22 = value_22
...
log4j.appender.APPENDER2.Property_2n = value_2n
...
Trong đó dòng đầu tiên định nghĩa một rootLogger, trong đó giá trị đầu tiên là mức log (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, ALL)Các dòng tiếp theo là danh sách các Appender. Các dòng tiếp theo sẽ định nghĩa các Appender được khai báo ở dòng đầu tiên. Các Appender sẽ chịu trách nhiệm in ấn thông điệp tới một nơi xác định. Tất cả các Appender đều có các thuộc tính chung như sau:
- layout: Appender sử dụng đối tượng layout này và các mẫu chuyển đổi liên quan để định dạng thông tin log.
- target: Đích để ghi log có thể là một giao diện điều khiển (console), một tệp tin (file)a file, ...
- level: Cấp độ yêu cầu để kiểm soát lọc các thông điệp log.
- threshold: Appender có thể có một mức ngưỡng (threshold level) gắn với nó, mức này độc lập với mức độ log (logger level). Appender sẽ bỏ qua bất kỳ thông điệp mà có mức độ thấp hơn mức ngưỡng.
- filter: Đối tượng filter có thể phân tích thông tin log kết hợp với mức và quyết định xem các yêu cầu ghi log sẽ được điều khiển bởi Appender cụ thể nào hay bỏ qua không xử lý.
- AppenderSkeleton
- AsyncAppender
- ConsoleAppender
- DailyRollingFileAppender
- ExternallyRolledFileAppender
- FileAppender
- JDBCAppender
- JMSAppender
- LF5Appender
- NTEventLogAppender
- NullAppender
- RollingFileAppender
- SMTPAppender
- SocketAppender
- SocketHubAppender
- SyslogAppender
- TelnetAppender
- WriterAppender
package com.mobilesoftvn.examples.appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
public class MyAppender extends AppenderSkeleton {
@Override
protected void append(LoggingEvent event) {
String message = null;
if (event.locationInformationExists()) {
StringBuilder formatedMessage = new StringBuilder();
formatedMessage.append(event.getLocationInformation().getClassName());
formatedMessage.append(".");
formatedMessage.append(event.getLocationInformation().getMethodName());
formatedMessage.append(":");
formatedMessage.append(event.getLocationInformation().getLineNumber());
formatedMessage.append(" - ");
formatedMessage.append(event.getMessage().toString());
message = formatedMessage.toString();
} else {
message = event.getMessage().toString();
}
System.out.println("MyAppender: " + message);
switch (event.getLevel().toInt()) {
case Level.INFO_INT:
//your decision
break;
case Level.DEBUG_INT:
//your decision
break;
case Level.ERROR_INT:
//your decision
break;
case Level.WARN_INT:
//your decision
break;
case Level.TRACE_INT:
//your decision
break;
default:
//your decision
break;
}
}
@Override
public void close() {
}
@Override
public boolean requiresLayout() {
return false;
}
}
Log4J cũng cung cấp một số Layout mặc định như dưới, nhưng PatternLayout vẫn được sử dụng nhiều nhất:
- DateLayout
- HTMLLayout
- PatternLayout
- SimpleLayout
- XMLLayout
4. Cấu hình ghi log ra tệp thông qua FileAppender
Trong các Appender của Log4J thì org.apache.log4j.FileAppender được sử dụng nhiều nhất. Đây là một Appender giúp bạn ghi thông tin log ra file. Các thuộc tính của FileAppender như sau:- immediateFlush: Cờ được thiết lập mặc định là true. Cờ này xác định thông điệp log của mỗi yêu cầu sẽ được đẩy luôn ra file.
- encoding: Chế độ mã hóa kí tự.
- threshold: Mức ngưỡng cho appender.
- Filename: Tên tệp ghi log.
- fileAppend: Mặc định được thiết lập là true, có nghĩa là thông tin log sẽ được ghi vào cuối tệp.
- bufferedIO: Cờ xác định có bật chế độ ghi đêm (Tức là ghi trước vào vùng nhớ đệm, sau đạt tới một giới hạn thì mới đẩy dữ liệu từ vùng đệm này ra file). Mặc định, cờ này được thiết lập là false.
- bufferSize: Nếu chế độ ghi đệm được thiết lập (bufferIO=true), tham số này xác định kích thước vùng nhớ đệm. Mặc định là 8kb.
# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, overwrite
log4j.appender.FILE.Append=false
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
Bạn cũng có thể sử dụng tệp log4j.xml như sau: <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<appender name="FILE" class="org.apache.log4j.FileAppender">
<param name="file" value="${log}/log.out"/>
<param name="immediateFlush" value="true"/>
<param name="threshold" value="debug"/>
<param name="append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="conversionPattern" value="%m%n"/>
</layout>
</appender>
<logger name="log4j.rootLogger" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="FILE"/>
</logger>
</log4j:configuration>
5. Cấu hình ghi log ra nhiều tệp thông qua RollingFileAppender
Log4J còn hỗ trợ bạn ghi log ra nhiều tệp thông qua org.apache.log4j.RollingFileAppender. Lớp này là lớp kế thừa từ FileAppender, vì thế RollingFileAppender có đầy đủ thuộc tính của FileAppender, ngoài ra nó còn hỗ trợ thêm hai thuộc tính sau:- maxFileSize: Đây là kích thước tới hạn của tập tin, nếu quá giá trị này dữ liệu tiếp sẽ tự động đẩy sang tệp mới. Giá trị mặc định là 10 MB.
- maxBackupIndex: Thuộc tính này xác định số lượng tệp sao lưu được tạo. Mặc định là 1.
# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, should not overwrite
log4j.appender.FILE.Append=true
# Set the maximum file size before rollover
log4j.appender.FILE.MaxFileSize=5KB
# Set the the backup index
log4j.appender.FILE.MaxBackupIndex=2
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
Bạn cũng có thể chuyển cấu hình sang dạng XML nếu bạn muốn. Trong cấu hình trên, kích thước tối đa cho phép mỗi tệp tin là 5KB, khi vượt quá kích thước này, file mới sẽ được tạo ra. Do maxBackupIndex được định nghĩa là 2, khi tệp tin thứ 2 đạt tới kích thước tối đa thì tệp tin đầu tin sẽ bị xóa và các log mới lại ghi vào tệp đầu tiên này.6. Cấu hình ghi log theo ngày thông qua DailyRollingFileAppender
Trong nhiều trường hợp bạn cần ghi log theo ngày, khi đó bạn phải sử dụng lớp org.apache.log4j.DailyRollingFileAppender. Lớp này được kế thừa từ lớp FileAppender vì thế nó có đầy đủ thuộc tính của FileAppender, ngoài ra nó còn có thêm thuộc tính:- DatePattern: Tham số này xác định thời điểm chuyển đổi ghi log sang tệp tin mới. Mặc định, việc chuyển đổi tệp tin này sẽ thực hiện vào lúc nửa đêm.
DatePattern điều khiển lịch trình đổi tệp log, sử dụng các mẫu sau:
- '.' yyyy-MM: Chuyển đổi tệp log theo từng tháng. Thời điểm chuyển đổi là cuối mỗi tháng và sang đầu tháng tiếp theo.
- '.' yyyy-MM-dd: Chuyển đổi tệp tin theo từng ngày. Thời điểm chuyển đổi là lúc giữa đêm từng ngày.
- '.' yyyy-MM-dd-a: Chuyển đổi tệp tin vào lúc giữa trưa và nửa đêm của mỗi ngày.
- '.' yyyy-MM-dd-HH: Chuyển đổi tệp tin theo giờ. Thời điểm chuyển đổi là đầu mỗi giờ.
- '.' yyyy-MM-dd-HH-mm: Chuyển đổi tệp tin theo từng phút.
- '.' yyyy-ww: Chuyển đổi tệp tin theo tuần. Thời điểm chuyển đổi là ngày đầu tiên của mỗi tuần (Phụ thuộc vào địa điểm).
# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=${log}/log.out
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, should not overwrite
log4j.appender.FILE.Append=true
# Set the DatePattern
log4j.appender.FILE.DatePattern='.' yyyy-MM-dd-a
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n
7. Ví dụ demo
Để demo cho bài viết này, tôi xây dựng một project nhỏ: Log4JExample. Project gồm nhiều tệp Log4JExampleXX.java, mỗi tệp demo cho một trường hợp. Bạn hãy chạy mỗi tệp để thử (Để run một tệp, trên IDE chẳng hạn Netbean, bạn kích phải vào tệp rồi chọn Run File):- Tệp Log4JExample01.java: Demo sử dụng cấu hình mặc định của Log4J (BasicConfigurator.configure()).
- Tệp Log4JExample02.java: Demo trường hợp sử dụng cấu hình trực tiếp bằng code.
- Tệp Log4JExample03.java: Demo trường hợp sử dụng cấu hình FileAppender. Bạn sẽ thấy log được ghi ra tệp logs/file-appender.log
- Tệp Log4JExample04.java: Demo trường hợp sử dụng cấu hình RollingFileAppender. Bạn sẽ thấy các log mới nhất luôn được ghi ra tệp logs/rolling-file-appender.log. Khi tệp đạt được 5K, các log cũ sẽ được đẩy sang tệp logs/rolling-file-appender.log.1 (Đúng 5K), sau đó khi tệp logs/rolling-file-appender.log lại đầy thì log cũ lại đẩy sang tệp logs/rolling-file-appender.log.2 (Đủ 5K), tiếp theo khi đầy lại đẩy log cũ sang logs/rolling-file-appender.log.1 và cứ xoay vòng như vậy.
- Tệp Log4JExample05.java: Demo trường hợp sử dụng cấu hình DailyRollingFileAppender (Ghi log theo phút, để tiện kiểm tra). Bạn sẽ thấy các log mới nhất sẽ được đẩy vào tệp logs/daily-rolling-file-appender.log. Sau khi sang phút tiếp theo, dữ liệu log của phút cũ được lưu sang tệp tương ứng ví dụ daily-rolling-file-appender.log.2016-05-17-01-28,...
- Tệp Log4JExample06.java: Demo trường hợp tự tạo một Appender riêng.