Saturday, September 3, 2016

Sử dụng thư viện Cron4J trong việc lập lịch chạy các nghiệp vụ trên Java

Cron4j là thư viện java nhỏ, nhẹ, đơn giản, dễ sử dụng trong việc lập lịch chạy các nghiệp vụ trên Java. Với thư viện này, bạn có thể thực hiện một công việc bất kỳ vào đúng thời điểm bạn cần theo một số quy tắc đơn giản.
Theo tôi Cron4J có một số điểm mạnh:
  • Thư viện nhẹ, nhỏ gọn, và miễn phí.
  • Lập trình rất dễ vì bạn chỉ cần nhớ vài phương thức.
  • Chạy trên mọi phiên bản Java.
  • Cú pháp cấu hình lập lịch đơn giản nhưng rất linh hoạt
Bạn có thể tải thư viện tại địa chỉ cron4j-2.2.5.zip, hoặc vào trực tiếp trang của dự án http://www.sauronsoftware.it/projects/cron4j/ để tải về

1. Lập trình với thư viện Cron4J

Việc lập trình sử dụng Cron4J rất đơn giản theo 04 bước như sau:

+ B1: Tạo một đối tượng là thể hiện lớp Scheduler (it.sauronsoftware.cron4j.Scheduler)
+ B2: Lập lịch để thực hiện tác vụ của bạn tại thời điểm bạn muốn. Lịch được lập bằng một xâu theo định dạng SchedulingPattern (it.sauronsoftware.cron4j.SchedulingPattern). Còn để thực hiện tác vụ bạn có thế sử dụng đối tượng Runnable (java.lang.Runnable) hoặc Task (it.sauronsoftware.cron4j.Task).
+ B3: Khởi chạy đối tượng Scheduler
+ B4: Dừng chạy đối tượng Scheduler nếu bạn không muốn làm gì thêm.

Dưới dây là đoạn mã ví dụ, xâu "* * * * *" xác định tác vụ được thực hiện hàng phút:

import it.sauronsoftware.cron4j.Scheduler;

public class Quickstart {
 public static void main(String[] args) {
  // Tạo một đối tượng Scheduler
  Scheduler s = new Scheduler();
  
  // Lập lịch và xác định tác vụ cần thực hiện
  s.schedule("* * * * *", new Runnable() {
   public void run() {
    System.out.println("Another minute ticked away...");
   }
  });
  
  // Khởi chạy đối tượng
  s.start();
  
  // Chờ 10 phút
  try {
   Thread.sleep(1000L * 60L * 10L);
  } catch (InterruptedException e) {
   ;
  }
  
  // Dừng tác vụ
  s.stop();
 }
}
Ví dụ trên chạy trong 10 phút. Mỗi phút sẽ in ra màn hình câu thông báo "Another minute ticked away...".

2. Cấu hình đặt lịch (Scheduling pattern)

Cron4J sử dụng Scheduling Pattern để cấu hình đặt lịch thực hiện, cấu hình tương tự như crontab trên UNIX. Đơn vị thời gian nhỏ nhất cho phép là phút.

Xâu cấu hình này được chia thành 05 phần như sau:

  • Minutes sub-pattern: Xác định phút nào tác vụ được chạy. Nhận giá trị từ 0 đến 59.
  • Hours sub-pattern: Xác định giờ nào tác vụ được chạy. Nhận giá trị từ 0 đến 23.
  • Days of month sub-pattern: Xác định ngày nào trong tháng tác vụ được chạy. Nhận giá trị từ 1 đến 31, và giá trị đặc biệt "L" để xác định ngày cuối tháng.
  • Months sub-pattern: Xác định tháng nào trong năm tác vụ được chạy. Nhận giá trị từ 1 (January) đến 12 (December), và giá trị alias tháng: "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov" và "dec".
  • Days of week sub-pattern: Xác định thứ mấy trong tuần tác vụ được chạy. Nhận giá trị từ 0 (Sunday) đến 6 (Saturday), và giá trị aliass như: "sun", "mon", "tue", "wed", "thu", "fri" và "sat"
Mỗi phần này theo chuẩn sau:
  • Kí tự * xác định mọi giá trị.
  • Kí tự , (phẩy) được sử dụng nếu có nhiều giá trị.
  • Kí tự - xác định dải giá trị. Ví dụ a-b tức là từ a đến b.
  • Kí tự / (slash) xác định bước nhảy thời gian.
  • Kí tự | nếu bạn muốn sử dụng kết hợp nhiều xâu pattern.
Bạn có thể kết hợp lại để tạo được xâu pattern mà bạn muốn. Dưới đây là một số ví dụ:
  • 5 * * * *
    Mẫu này xác định tác vụ sẽ được chạy vào phút thứ 5 hàng giờ. Ví dụ: 00:05, 01:05, 02:05...
  • * * * * *
    Mẫu này xác định mỗi phút tác vụ sẽ được thực hiện 1 lần.
  • * 12 * * Mon
    Mẫu này xác định tác vụ sẽ được thực hiện từng phút trong khoảng thời gian 12h của ngày thứ 2.
  • * 12 16 * Mon
    Mẫu này xác đinh tác vụ sẽ được thực hiện từng phút trong khoảng 12h thứ 2 ngày 16. Nếu vào ngày 16 mà không phải là thứ 2 thì tác vụ cũng sẽ không được thực hiện.
  • 59 11 * * 1,2,3,4,5
    Tác vụ này sẽ được thực hiện vào lúc 11:59AM vào các ngày Thứ Hai, Thứ Ba, Thứ tư, Thứ 5 và Thứ 6.
  • 59 11 * * 1-5
    Mẫu này tương đương với mẫu 59 11 * * 1,2,3,4,5 ở trên.
  • */5 * * * *
    Mẫu này xác định cứ 5 phút tác vụ sẽ được thực hiện một lần. Ví dụ: 0:00, 0:05, 0:10; 0:15,...
  • 3-18/5 * * * *
    Mẫu này xác định tác vụ sẽ được thực hiện 5 phút 1 lần trong khoảng thời gian từ phút thứ 3 đến phút thứ 18. Ví dụ: 0:03, 0:08, 0:13, 0:18, 1:03, 1:08,...
  • */15 9-17 * * *
    Mẫu này xác định tác vụ được thự hiện 15 phút 1 lần trong khoảng thời gian từ 9h đến 17h. Ví dụ: 9:00, 9:15, 9:30, 9:45,..., 17:45.
  • * 12 10-16/2 * *
    Mẫu này xác định tác vụ được thực hiện từng phút vào lúc 12h trong các ngày mùng 10, 12, 14, 16 của tháng.
  • * 12 1-15,17,20-25 * *
    Mẫu này xác định tác vụ sẽ được thực hiện từng phút vào lúc 12h trong các ngày từ mùng 1 đến 15, ngày 17 và từ ngày 20 đến ngày 25.
  • 0 5 * * *|8 10 * * *|22 17 * * *
    Mẫu này xác định tác vụ được thực hiện hàng ngày vào lúc 05:00, 10:08 và 17:22.

Tài liệu tham khảo:
- http://www.sauronsoftware.it/projects/cron4j/manual.php

Thursday, July 14, 2016

Chạy tiến trình Java sử dụng Java Service Wrapper

Java Service Wrapper cho phép bạn chạy một ứng dụng Java dưới dạng một dịch vụ trên Windows (Windows Service) hay trên Linux/Unix (UNIX Daemon). Nó cũng được sử dụng để giám sát sức khỏe ứng dụng của bạn và của JVM. Sử dụng Java Service Wrapper có hai ưu điểm vượt trội:
  • Tích hợp đơn giản, bạn không cần lập trình gì thêm trong ứng dụng.
  • Triển khai và cài đặt ứng dụng như một dịch vụ trên các nền tảng khác nhau.

Cũng vì lợi ích này mà hiện nay có rất nhiều nhà phát triển Java sử dụng Java Service Wrapper để triển khai các tiến trình trên server. Chi tiết bạn có thể xem trực tiếp trên trang chủ: Java Service Wrapper

Ứng dụng hỗ trợ 03 phiên bản:

  • Professional Edition: Bao gồm tất cả các tính năng cơ bản và nâng cao. Để sử dụng phiên bản này, bạn phải mua bản quyền ứng dụng.
  • Standard Edition: Bao gồm tất cả các tính năng cơ bản và một số tính năng nâng cao. Để sử dụng phiên bản này, bạn cũng phải mua bản quyền ứng dụng.
  • Community Edition: Bao gồm tất cả các tính năng cơ bản, không có tính năng nâng cao. Phiên bản này hoàn toàn miễn phí, nếu không sử dụng gì đặc biệt có lẽ phiên bản này cũng là đủ với các bạn.
Chi tiết về các tính năng của từng phiên bản, bạn xem tại địa chỉ: Java Service Wrapper: Product Features.

Để tải ứng dụng, bạn vào địa chỉ: Java Service Wrapper: Download. Để tiện lợi khi sử dụng, bạn tải bản Cross-Platform để có thể chạy trên mọi nền tảng, dĩ nhiên kích thước của bản này sẽ lớn hơn. Có lẽ đến đây bạn quan tâm làm thế nào để tích hợp được và Java Service Wrapper?. Có 04 cách tích hợp ứng dụng của bạn với Java Service Wrapper, trong đó có 03 cách bạn không cần phải thêm bất kỳ đoạn mã nào trong ứng dụng của bạn. Dưới đây là chi tiết cách tích hợp:

* C1: Sử dụng WrapperSimpleApp

Sử dụng lớp WrapperSimpleApp để chạy ứng dụng. Đây là cách đơn giản nhất để tích hợp ứng dụng với Wrapper. Theo cách này, bạn chỉ cần cấu hình lớp Main để khởi động ứng dụng. Cách này thích hợp với các ứng dụng chỉ có một lớp Main để khởi động ứng dụng.

Sử dụng các này có một nhược điểm về vấn đề giải phóng tài nguyên khi kết thúc ứng dụng. Khi Wrapper tắt JVM, nó không gọi trực tiếp tới ứng dụng để tắt ứng dụng, Wrapper sẽ tắt JVM bằng cách gọi lệnh System.exit() từ trong JVM. Vì thế nếu ứng dụng đã đăng ký Shutdown Hook thì ứng dụng sẽ được tắt một cách bình thường, còn ngược lại ứng dụng sẽ bị tắt một cách đột ngột, trong trường hợp này có thể ứng dụng chưa giải phóng hết tài nguyên khi tắt.

Khi tích hợp theo cách này, lớp WrapperSimpleApp sẽ thay thế lớp chính (Main class) của ứng dụng. Khi bật ứng dụng, lớp WrapperSimpleApp sẽ khởi tạo sau đó gọi lớp Main trong lớp trình, lớp main này được cấu hình trong tệp.
Để hiểu rõ hơn bạn xem ví dụ cấu hình tích hợp chạy JBOSS sử dụng WrapperSimpleApp:
* Trên Windows: Hướng dẫn tích hợp JBOSS sử dụng WrapperSimpleApp trên Windows
* Trên Windows: Hướng dẫn tích hợp JBOSS sử dụng WrapperSimpleApp trên Linux/UNIX

* C2: Sử dụng WrapperStartStopApp

Cách này giúp tích hợp các ứng dụng mà sử dụng một lớp để chạy ứng dụng và sử dụng một lớp khác để dừng ứng dụng (Ví dụ như Tomcat). Thông thường, các ứng dụng loại này sẽ mở một Socket khi chạy để nhận bản tin yêu cầu dừng ứng dụng. Khi đó một lớp sẽ được gọi để dừng ứng dụng. Theo cách này bạn phải cấu hình hai lớp: Một lớp để khởi động ứng dụng và một lớp để dừng ứng dụng.
Để hiểu rõ hơn bạn xem ví dụ cấu hình tích hợp chạy Tomcat sử dụng JWrapperStartStopApp:
* Trên Windows: Hướng dẫn tích hợp Tomcat sử dụng WrapperStartStopApp trên Windows
* Trên Windows: Hướng dẫn tích hợp JBOSS sử dụng WrapperStartStopApp trên Linux/UNIX

* C3: Sử dụng WrapperListener

Cách này cung cấp một cơ chế linh động để truy cập vào tất cả các tính năng của Wrapper, nhưng cách này yêu cầu bạn phải lập trình thêm trong ứng dụng. Trong ứng dụng, bạn phải tạo một lớp cài đặt lại các phương thức trong lớp giao diện WrapperListener, sau đó bạn tạo ra một thể hiện lớp này và đăng ký với WrapperManager. Nếu không có gì đặc biệt, tôi khuyên các bạn không nên sử dụng cách này vì phức tạp và phải sửa code ứng dụng.
Nếu bạn muốn tìm hiểu sâu về cách tích hợp này, bạn xem thêm tại Hướng dẫn tích hợp WrapperListener

* C4: Sử dụng WrapperJarApp

Đây là một phương thức đơn giản khác giúp bạn chạy một ứng dụng đã được cấu hình chạy như một tệp executable jar. Khi sử dụng cách này, JVM sẽ không đóng ứng dụng của bạn như bình thường để đảm bảo mọi tài nguyên ứng dụng đều đã được giải phóng mà nó thoát JVM bằng cách gọi System.exit().
Để hiểu rõ hơn bạn xem ví dụ cấu hình tích hợp chạy Hudson sử dụng WrapperJarApp:
* Trên Windows: Hướng dẫn tích hợp Hudson sử dụng WrapperJarApp trên Windows
* Trên Windows: Hướng dẫn tích hợp Hudson sử dụng WrapperJarApp trên Linux/UNIX

Về cơ bản, đọc các ví dụ từ trang Wrapper bạn đã có thể tự tích hợp được cho mình. Vì vậy trong bài này tôi không đi chi tiết, mà nói trong nhưng trường hợp ứng dụng cụ thể trong các bài viết sắp tới.

Thursday, July 7, 2016

Một số lệnh hay dùng trên Linux/Ubuntu

Như chúng ta đã biết, Linux là một hệ điều hành mã nguồn mở (open-source OS) với nhiều tính năng không thua kém các hệ điều hành hiện nay và đặc biệt Linux là miễn phí. Đây là hệ điều hành đáng tin cậy, an toàn, ngày càng thân thiện với người dùng và được hàng ngàn lập trình viên trên thế giới tiếp tục phát triển.
Cơ chế dòng lệnh (Command Line) là cách đơn giản nhất để tương tác với hệ thống. Ưu điểm của nó là thực hiện tác vụ nhanh hơn so với việc chúng ta sử dụng giao diện đồ họa. Dưới đây là một số câu lệnh thông dụng mà chúng tôi giới thiệu đến các bạn tham khảo:
1. Lệnh xem thông tin server
      1.1. Xem thông tin nhà sản xuất
      1.2. Xem thông tin thông tin main
      1.3. Xem thông tin CPU
      1.4. Xem thông tin RAM
      1.5. Xem thông tin HDD
      1.6. Xem thông tin PCI Bus
      1.7. Xem thông tin hệ điều hành
      1.8. Xem phiên bản bộ biên dịch C/C++
      1.9. Xem phiên địa chỉ IP
      1.10. Xem thông tin kết nối
      1.11. Xem log đăng nhập hệ thống
      1.12. Xem log các lệnh đã thực thi trên hệ thống
      1.13. Xem không gian ổ đĩa
      1.14. Xem dung lượng bộ nhớ
2. Lệnh quản trị hệ thống
      2.1. Kiểm tra, cài đặt, gỡ bỏ các gói cài đặt
      2.2. Kiểm tra các tiến trình đang chạy
      2.3. Dừng các tiến trình bị treo
      2.4. Xem tài nguyên hệ thống
      2.5. Hiển thị tiến trình đang chạy dưới dạng cây
      2.6. Xem cú pháp dòng lệnh
3. Lệnh thao tác người dùng
      3.1. Lệnh tạo người dùng mới
      3.2. Lệnh tạo nhóm người dùng mới
      3.3. Thay đổi mật khẩu người dùng
      3.4. Xóa người dùng
4. Lệnh thao tác với thư mục, tệp tin
      4.1. Lệnh thao tác tệp trên FTP Server
4. Lệnh khi làm việc trên terminal
5. Lệnh quản lý hệ thống

1. Lệnh xem thông tin server

Ghi chú: Hầu hết các lệnh trên xem thông tin cấu hình server đều phải sử dụng quyền root.

1.1. Xem thông tin nhà sản xuất

dmidecode | grep "System Information" –A 9
Lệnh này cho phép xem thông tin về nhà sản xuất server.
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

1.2. Xem thông tin thông tin main

dmidecode | grep "Base Board" – A 10
Lệnh này sẽ xuất ra màn hình thông tin Mainboard của server, tuy nhiên không phải tất cả server đều có thông tin này.
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

1.3. Xem thông tin CPU

cat /proc/cpuinfo | head –n 25
Lệnh này sẽ trả về thông tin của CPU trong server, tuy nhiên sẽ chỉ trả về thông tin của từng Core.
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

Để lấy thông tin về tổng số core của CPU, bạn sử dụng lệnh sau:

cat /proc/cpuinfo | grep processor | wc -l

https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

Bạn lấy thông tin chi tiết chỉ cần đánh lệnh:

cat /proc/cpuinfo

1.4. Xem thông tin RAM

cat /pro/meminfo
Lệnh này sẽ trả về các thông tin về bộ nhớ RAM, trong đó MemTotal chính là tổng dung lượng bộ nhớ RAM đang có trong server.
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

1.5. Xem thông tin HDD

cat /proc/scsi/scsi
Lệnh này sẽ trả về thông tin những HDD vật lý đang được lắp trong server tuy nhiên chỉ bao gồm model HDD chứ không bao gồm dung lượng.
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

Để liệt kê dung lượng các HDD đang được lắp, bạn sử dụng lệnh sau:
https://laptrinh365.blogspot.com - Tự học lập trình - Một số lệnh hay dùng trên Linux/Ubuntu

1.6. Xem thông tin PCI Bus

lspci
Lệnh này sẽ hiển thị thông tin về tất cả PCI Bus và các thiết bị kết nối tới nó. Lệnh này có thể gộp của "ls" + "pci".
# lspci
00:00.0 Host bridge: Intel Corporation 5500 I/O Hub to ESI Port (rev 13)
00:01.0 PCI bridge: Intel Corporation 5520/5500/X58 I/O Hub PCI Express Root Port 1 (rev 13)
00:09.0 PCI bridge: Intel Corporation 7500/5520/5500/X58 I/O Hub PCI Express Root Port 9 (rev 13)
00:14.0 PIC: Intel Corporation 7500/5520/5500/X58 I/O Hub System Management Registers (rev 13)
00:14.1 PIC: Intel Corporation 7500/5520/5500/X58 I/O Hub GPIO and Scratch Pad Registers (rev 13)
00:14.2 PIC: Intel Corporation 7500/5520/5500/X58 I/O Hub Control Status and RAS Registers (rev 13)
00:1a.0 USB controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #4 (rev 02)
00:1c.0 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 1 (rev 02)
00:1d.0 USB controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #1 (rev 02)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 92)
00:1f.0 ISA bridge: Intel Corporation 82801IB (ICH9) LPC Interface Controller (rev 02)
00:1f.2 IDE interface: Intel Corporation 82801IB (ICH9) 2 port SATA Controller [IDE mode] (rev 02)
01:00.0 Ethernet controller: Broadcom Corporation NetXtreme II BCM5709 Gigabit Ethernet (rev 20)
01:00.1 Ethernet controller: Broadcom Corporation NetXtreme II BCM5709 Gigabit Ethernet (rev 20)
03:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS 2108 [Liberator] (rev 05)
06:03.0 VGA compatible controller: Matrox Electronics Systems Ltd. MGA G200eW WPCM450 (rev 0a)

Ngoài ra bạn có thể sử dụng thêm các tham số tùy theo mục đích sử dụng. Ví dụ: Bạn muốn xem thông tin SubSystem sử dụng lệnh sau:

lspci -m
Bạn muốn hiển thị dưới dạng cây để xem các thiết bị nào kết nối tới nó, hãy sử dụng lệnh sau:
lspci -t
Còn nếu bạn muốn xem thông tin chi tiết, hãy sử dụng lệnh sau:
lspci -v

1.7. Xem thông tin hệ điều hành

Để xem đầy đủ thông tin hệ điều hành, bạn sử dụng lệnh sau:
uname -a
Linux TEST-APP01 2.6.18-308.el5 #1 SMP Tue Feb 21 20:06:06 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
Ngoài ra bạn có thể sử dụng tham số sau để lấy thông tin từng loại:
  • -s: Tên nhân hệ điều hành (Kernel name)
  • -r: Phiên bản nhân release hệ điều hành sử dụng (Kernel release)
  • -v: Phiên bản nhân (Kernel version)
  • -n: Tên node (Nodename)
  • -m: Tên phần cứng (Hardware name)
  • -i: Platform phần cứng (Hardware platform)
  • -p: Kiểu bộ vi xử lý (Processor type)
  • -o: Hệ điều hành (Operating system)

1.8. Xem phiên bản bộ biên dịch C/C++

gcc -v
Lệnh này để xem phiên bản bộ biên dịch C/C++ đã được cài đặt.

1.9. Xem phiên địa chỉ IP

/sbin/ifconfig
Lệnh này để xem tất cả các địa chỉ IP trên máy.

1.10. Xem thông tin kết nối

netstat
Lệnh này để xem tất cả các kết nối. Bạn có thể sử dụng thêm với lệnh grep để lấy chi tiết thông tin. Ví dụ:
Liệt kê kết nối tới cổng 8080:
netstat -an | grep :8080
Hay đếm số kết nối tới cổng 8080:
netstat -an | grep :8080 | wc -l

1.11. Xem log đăng nhập hệ thống

last
Lệnh này để xem tất cả các log đăng nhập hệ thống.

1.12. Xem log các lệnh đã thực thi trên hệ thống

history
Lệnh này để xem tất cả các lệnh mà đã được thực thi trên server trước đó.

1.13. Xem không gian ổ đĩa

df
Lệnh này để xem thông tin ổ đĩa (Tổng dung lượng, dung lượng đã sử dụng, dung lượng chưa sử dụng).

1.14. Xem dung lượng bộ nhớ

free -m
Lệnh này để xem dung lượng bộ nhớ (Tổng dung lượng, dung lượng đã sử dụng, dung lượng chưa sử dụng).

2. Lệnh quản trị hệ thống

2.1. Kiểm tra, cài đặt, gỡ bỏ các gói cài đặt

Lệnh sau thực hiện cài đặt gói RPM:
rpm -ivh pidgin-2.7.9-5.el6.2.i686.rpm
Trong đó: -i là cài đặt; -v để hiển thị đẹp hơn và -h để hiển thị dấu # cho các gói đã giải nén. Trong trường hợp bạn thấy tất cả các thành cần thiết đều đã được cài đặt thì hệ thống vẫn báo thiếu, bạn có thể sử dụng tham số –nodeps để bỏ qua không yêu cầu phải cài đặt các thành phần phụ thuộc trước:
rpm -ivh --nodeps BitTorrent-5.2.2-1-Python2.4.noarch.rpm
Lệnh sau kiểm tra các thành phần phụ thuộc:
rpm -qpR BitTorrent-5.2.2-1-Python2.4.noarch.rpm
Trong đó, tham số -q nghĩa là truy vấn, -p là liệt kê danh sách các thành phần mà gói hỗ trợ, -R là liệt kê danh sách các thành phần mà gói này phụ thuộc.
Để kiểm tra một gói RPM đã được cài đặt hay chưa, bạn hãy sử dụng tham số -q:
rpm -q BitTorrent
Để hiển thị chi tiết các tệp trong gói RPM đã được cài đặt, bạn hãy sử dụng tham số -ql (query list):
rpm -ql BitTorrent

Ngoài ra còn nhiều cách sử dụng khác nữa, chi tiết xem địa chỉ: 20 Practical Examples of RPM Commands in Linux.

2.2. Kiểm tra các tiến trình đang chạy

ps là lệnh sử dụng để kiểm tra tiến trình đang chạy. Cú pháp của lệnh hỗ trợ cả hai hai kiểu cú pháp là BSD và UNIX.

Để hiển thị danh sách các tiến trình và thông tin chi tiết tiến trình, bạn sử dụng một trong hai lệnh sau:

ps aux
ps -ef -f
Để hiển thị các tiến trình của một người dùng nào đó, bạn sử dụng tham số -u:
ps -f -u test_user
Để tìm kiếm tiến trình theo tên, bạn sử dụng tham số -C:
ps -C apache2
Để tìm kiếm tiến trình theo Process ID, bạn sử dụng tham số -p:
ps -f  -p 3150,7298,6544
Để hiển thị tiến trình sắp xếp theo thứ tự sử dụng CPU, RAM, bạn hãy sử dụng lệnh sau:
ps aux --sort=-pcpu,+pmem
Để hiển thị tiến trình theo cấu trúc cây, bạn sử dụng tham số --forest:
ps -f --forest -C apache2
Ngoài ra bạn kết hợp với lệnh grep để tìm đúng tiến trình mình mong muốn:
ps -ef | grep process_test
Chi tiết bạn xem thêm tại địa chỉ: 10 basic examples of Linux ps command

2.3. Dừng các tiến trình bị treo

kill là lệnh dừng các tiến trình khi tiến trình đó bị treo. Chỉ có super-user mới có thể dừng tất cả các tiến trình còn user khác chỉ có thể dừng tiến trình mà user đó tạo ra.

Trước khi kill một tiến trình, bạn cần xác định pid của tiến trình đó, sau đó sử dụng một trong các lệnh sau:

kill -TERM pid
kill -SIGTERM pid
kill -9 pid
Ví dụ kill tiến trình firefox:
$ ps -ef | grep firefox
1986 ?        Sl     7:22 /usr/lib/firefox-3.5.3/firefox

$ kill -9 1986
Với lệnh killall, bạn có thể kill tiến trình theo tên:
killall -9 firefox
Lệnh pkill sẽ kill tất cả các tiến trình có tên chứa xâu truyền vào:
pkill sample
Chi tiết hơn, bạn có thể xem tại địa chỉ: 4 Ways to Kill a Process – kill, killall, pkill, xkill

2.4. Xem tài nguyên hệ thống

top là lệnh hiển thị sự hoạt động của các tiến trình, đặc biệt là thông tin về tài nguyên hệ thống và việc sử dụng các tài nguyên đó của từng tiến trình.

Lệnh sau sẽ hiển thị thông tin các Task, thông tin bộ nhớ, CPU và vùng Swap. Nhấn phím 'q' để thoát khỏi cửa sổ:

top
Sử dụng tham số -O (Không phải số 0 mà là chữ O viết hoa) để sắp xếp tiến trình:
top -O
Tiếp đó bạn nhấn (Shift + O) để hiển thị danh sách kí tự tương ứng với trường thông tin, sau đó bạn nhấn kí tự tương ứng với trường để sắp xếp theo trường đó. Ví dụ nhấn phím 'a' để sắp xếp theo PID, nhấn (Shift+P) để sắp xếp theo % sử dụng CPU.

Sử dụng tham số -u để hiển thị thông tin các tiến trình theo user:

top -u tecmint
Để lưu kết quả vào tệp "/root/.toprc", bạn nhấn phím: (Shift+W).

Chi tiết bạn xem tại địa chỉ: 12 TOP Command Examples in Linux

2.5. Hiển thị tiến trình đang chạy dưới dạng cây

pstree là lệnh hiển thị các tiến trình đang chạy dưới dạng cây. Bạn có thể sử dụng một trong các cú pháp sau:
pstree
pstree pid
pstree user
Chi tiết xem tại địa chỉ: pstree Command Examples: See A Tree Of Processes

2.6. Xem cú pháp dòng lệnh

man là lệnh xem hướng dẫn về dòng lệnh như cú pháp, các tham số... Ví dụ:
man man
Chi tiết xem tại địa chỉ: Linux and Unix man command

3. Lệnh thao tác người dùng

3.1. Lệnh tạo người dùng mới

useradd: là lệnh tạo một người dùng mới. Cú pháp của lệnh như sau:
useradd [options] username
Đơn giản nhất để tạo user mới bạn sử dụng lệnh sau:
useradd tecmint
Lệnh này tạo user mới nhưng user này ở trạng thái khóa, để mớ khóa user này bạn cần phải thiết lập mật khẩu bằng lệnh passwd:
passwd tecmint
Hệ thống hiển thị giao diện để bạn nhập mật khẩu. Khi người dùng mới được tạo, hệ thống sẽ tự động thêm vào tệp ‘/etc/passwd‘. Tệp này được sử dụng để lưu trữ thông tin các người dùng. Nội dung thêm dạng như dưới:
tecmint:x:504:504:tecmint:/home/tecmint:/bin/bash
(Thư mục home mặc định hệ thống để là: /home/)

Để tạo user với thư mục home được xác định trước, bạn dùng lệnh sau:

useradd -d /data/projects anusha
Để tạo user trong một nhóm xác định, bạn sử dụng tham số -g theo sau là GID (Group ID). Nếu bạn muốn xác định User ID (UID) bạn sử dụng tham số -u theo sau là UID:
useradd -u 1000 -g 500 tarunika
Để thêm user vào nhiều group, bạn dùng tham số -G theo sau là danh sách tên các group:
useradd -G admins,webadmin,developers tecmint
Mặc định khi tạo tài khoản người dùng mới, tài khoản sẽ không bao giờ bị hết hạn. Nếu bạn muốn tạo tài khoản có thời gian sử dụng bạn sử dụng tham số -e:
useradd -e 2014-03-27 aparna
Nếu muốn thiết lập thời gian hết hạn của mật khẩu, bạn sử dụng tham số -f theo sau số ngày:
useradd -e 2014-04-27 -f 45 tecmint
Còn nếu bạn muốn kiểm tra thời gian hết hạn của tài khoản, bạn sử dụng lệnh change với tham số -l:
chage -l aparna
Chi tiết hơn về lệnh useradd, bạn có thể xem tại địa chỉ: The Complete Guide to “useradd” Command in Linux – 15 Practical Examples

3.2. Lệnh tạo nhóm người dùng mới

groupadd: là lệnh tạo một nhóm người dùng mới. Khi dùng lệnh này, thông tin sẽ được cập nhật vào tệp "/etc/group". Cú pháp lệnh như sau:
groupadd [options] group

Để tạo nhóm người dùng mới, bạn dùng lệnh sau:

groupadd apache
Để kiểm tra chắc chắn bạn đã tạo thành công chưa, bạn sử dụng lệnh sau:
grep apache /etc/group
Nếu thấy có dòng có tên nhóm là apache là okie. Chi tiết hơn bạn có thể xem tại địa chỉ: 3 UNIX / Linux groupadd Command Examples

3.3. Thay đổi mật khẩu người dùng

passwd là lệnh thay đổi mật khẩu người dùng. Cú pháp của lệnh như sau:
passwd {options} {user_name}

Nếu bạn đăng nhập với người dùng thông thường, lệnh sau sẽ thay đổi mật khẩu của người dùng hiện tại:

passwd

Nếu bạn đăng nhập dưới người dùng root, bạn sẽ có thể thay đổi mật khẩu các các người dùng khác:

passwd linuxtechi
Để hiển thông tin trạng thái mật khẩu, bạn sử dụng tham số -S:
passwd -S linuxtechi
Để hiển thị thông tin trạng thái mật khẩu của tất cả người dùng, bạn sử dụng tham số -Sa:
passwd -Sa
Để xóa mật khẩu của người dùng, bạn sử dụng tham số -d:
passwd -d linuxtechi
Để thiết lập mật khẩu của người dùng hết hạn ngay lập tức, bạn sử dụng tham số -e:
passwd -e linuxtechi
Để khóa mật khẩu người dùng, bạn sử dụng tham số -l:
passwd -l linuxtechi
Để mở khóa mật khẩu người dùng, bạn sử dụng tham số -u:
passwd -u linuxtechi
Để thiết lập sau bao nhiêu ngày phải đổi mật khẩu, bạn sử dụng tham số -n:
passwd -n 90 linuxtechi
Chi tiết hơn bạn xem tại địa chỉ: 10 passwd command examples in Linux

3.4. Xóa người dùng

userdel là lệnh xóa người dùng. Cú pháp của lệnh như sau:
userdel [options] username
Lệnh sau xóa người dùng linuxtechi:
userdel -r linuxtechi
Chi tiết bạn xem tại địa chỉ: Linux and Unix userdel command

3.5. Thao tác nhóm người dùng

groupdel là lệnh xóa người nhóm dùng. Cú pháp của lệnh như sau:
groupdel group
Lệnh sau xóa nhóm test:
groupdel test

gpasswd là lệnh giúp quản trị nhóm người dùng, bạn có thể sử dụng lệnh này để đổi mật khẩu, thêm hay loại bỏ người dùng khỏi nhóm. Cú pháp của lệnh như sau:

gpasswd [option] group
Sử dụng tham số -r để xóa mật khẩu:
gpasswd -r test
Sử dụng tham số -a để thêm người dùng vào nhóm:
gpasswd -a daothang test
Sử dụng tham số -d để xóa người dùng khỏi nhóm:
gpasswd -d daothang test
Chi tiết bạn xem tại địa chỉ: Linux and Unix gpasswd command

groups giúp hiển thị danh sách người dùng trong một nhóm. Cú pháp của lệnh như sau:

groups [user]
Lệnh sau hiển thị danh sách người dùng trong trong nhóm chứa người dùng hiện tại:
groups
Lệnh sau hiển thị danh sách người dùng trong trong nhóm chứa người dùng daothang:
groups daothang

4. Lệnh thao tác với thư mục, tệp tin

4.1. Lệnh thao tác tệp trên FTP Server

Sử dụng lệnh ftp để kết nối tới server FTP:
ftp 192.168.0.1
ftp domain.com
ftp user@ftpdomain.com
Sử dụng lệnh cd để chuyển thư mục, lệnh ls để xem danh sách tệp. Ví dụ:
cd test
ls
Để chuyển tệp giữa các thư mục trên FTP, bạn sử dụng lệnh rename:
mkdir bk
rename my_file.txt bk/my_file.txt
Để lấy tệp từ server, trước hết bạn phải dùng lệnh lcd để thiết lập thư mục sẽ tải tệp về, sau đó dùng lệnh get để tải tệp:
lcd /u01/test
get my_file.txt
Để lấy nhiều tệp, bạn sử dụng lệnh mget:
mget *.txt
Lệnh này sẽ hỏi bạn có thực hiện từng tệp không, để hệ thống không hỏi lại khi kết nối tới FTP bạn phải thêm tham số -i:
ftp -i 192.168.0.1
Để đẩy tệp lên FTP Server bạn sử dụng lệnh put:
put test_file.xls
Để đẩy nhiều tệp, bạn sử dụng lệnh mput:
mput *.xls
Để đóng kết nối, bạn có thể sử dụng một trong các lệnh sau:
bye
exit
quit
1. Quản lý hệ thống : xoá nhóm người dùng đã tạo. su: cho phép đăng nhập với tư cách người dùng khác. groups: hiển thị nhóm của user hiện tại. who: cho biết ai đang đăng nhập hệ thống. w: tương tự như lệnh who. 2. Trên terminal¶ clear: xoá trắng cửa sổ dòng lệnh. date: xem ngày, giờ hệ thống. find /usr/share/zoneinfo/ | grep -i pst: xem Timezone. ln -f -s /usr/share/zoneinfo/Asia/Ho_Chi_Minh /etc/localtime: Đổi Server Time về Timezone Việt Nam. date -s "1 Oct 2009 18:00:00" : thay đổi thời gian hệ thống. cal: xem lịch hệ thống. 4. Liên quan đến vận hành hệ thống ¶ exit: thoát khỏi terminal. logout: tương tự exit. reboot: khởi động lại hệ thống. mount: gắn hệ thống tập tin từ một thiết bị lưu trữ vào cây thư mục chính. umount: ngược với lệnh mount. 5. Trên File - Folder ¶ ls: lấy danh sách tất cả các file và folder trong folder hiện hành. pwd: xuất đường dẫn của folder làm việc. cd: thay đổi folder làm việc đến một folder mới. mkdir: tạo folder mới. rmdir: xoá folder rỗng. cp: copy một hay nhiều file đến folder mới. mv: đổi tên hay di chuyển file, folder. rm: xóa file. wc: đếm số dòng, số kí tự... trong file. touch: tạo file. cat: xem nội dung file. vi: khởi động trình soạn thảo văn bản vi. df: kiểm tra disk space. du: xem disk space đã dùng cho một số file nhất định. tar -cvzpf archive.tgz /home/example/public_html/folder: nén một folder tar -tzf backup.tar.gz: liệt kê file nén gz. tar -xvf archive.tar: giải nén một file tar. unzip file.zip: giải nén file .zip wget: download file. chown -hR user:user folder/ : Đổi owner cho folder hay file. tail 100 matbao.log: Xem 100 dòng cuối cùng của file matbao.log.

Tham khảo:
http://wiki.matbao.net/Cac-command-huu-ich-tren-he-thong-Linux.ashx
http://wiki.matbao.net/Cac-cau-lenh-command-co-ban-tren-Server-Linux.ashx

Friday, June 24, 2016

Cấu hình sử dụng Log4j (1.x) trong lập trình Java

Việc ghi log là một yêu cầu bắt buộc với các ứng dụng hiện nay. Nó giúp chúng ta dễ dàng giám sát, rà soát phát hiện lỗi của các chương trình đang chạy trên môi trường thật (Bản Production) nhằm đưa ra câu trả lời chính xác cho tình huống lỗi của ứng dụng và đưa ra giải pháp để khắc phục lỗi. Log của ứng dụng cũng là bằng chứng trong trường hợp cần phải chứng minh lỗi do nguyên nhân nào gây lên? Người dùng nhập sai thông tin, Hệ thống xử lý bị timeout, mã lỗi trả về từ hệ thống.

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 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.

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 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 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:
# Đị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ý.
Ngoài ra, với mỗi Appender sẽ có thêm các thuộc tính của riêng nó, tùy vào loại Appender. Log4J cung cấp sẵn cho bạn các Appender sau nhưng được sử dụng nhiều nhất vẫn là FileAppender:
  • AppenderSkeleton
  • AsyncAppender
  • ConsoleAppender
  • DailyRollingFileAppender
  • ExternallyRolledFileAppender
  • FileAppender
  • JDBCAppender
  • JMSAppender
  • LF5Appender
  • NTEventLogAppender
  • NullAppender
  • RollingFileAppender
  • SMTPAppender
  • SocketAppender
  • SocketHubAppender
  • SyslogAppender
  • TelnetAppender
  • WriterAppender
Ngoài ra bạn cũng có thể tạo một Appender riêng bằng cách tạo một lớp mới kế thừa từ một trong các lớp Appender ở trên và chồng lại 03 hàm append, close và requiresLayout. Dưới đây là ví dụ customize một Appender:
 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
Sử dụng HTMLLayoutXMLLayout, bạn có thể sinh log theo định dạng HTML hoặc XML.

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.
Dưới đây là tệp cấu hình log4j.properties sử dụng FileAppender:
 # 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.
Dưới đây là ví dụ tệp log4j.properties sử dụng RollingFileAppender:
 # 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).
Dưới đây là ví dụ tệp cấu hình log4j.properties sinh ra tệp log vào giữa trưa và nửa đêm của mỗi ngày:
 # 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.
Để download sourcecode của ví dụ, hãy nhấn vào link: Log4JExample

8. Tài liệu tham khảo

Bài viết tham khảo từ các nguồn sau:

Tối ưu tốc độ Web thông qua cấu hình chế độ nén dữ liệu truyền qua giao thức HTTP

Hiện tại hầu hết các Web Server đều hỗ trợ chế độ nén dữ liệu trao đổi qua giao thức HTTP bằng cơ chế nén GZIP. Chế độ này là giải pháp hết sức đơn giản giúp tăng tốc độ trang web, tiết kiệm băng thông trao đổi qua đó giúp tăng trải nghiệm người dùng.

Bài viết này tôi dướng dẫn các bạn cấu hình để thực hiện việc này. Nội dung bài viết gồm:
1. Vì sao cơ chế nén dữ liệu giúp tăng tốc độ website?
2. Cấu hình trên các server Web
     2.1 Cấu hình trên server Tomcat
     2.2 Cấu hình trên server Apache
     2.3 Cấu hình trên server ISS
     2.4 Cấu hình trên các server khác
3. Kiểm tra trên ứng dụng Web
4. Xử lý trên ứng dụng Android
5. Xử lý trên ứng dụng iOS

1. Vì sao cơ chế nén dữ liệu giúp tăng tốc độ website?

Hầu hết các website lớn trên thế giới như Amazon, Google, Alibaba... hay của Việt Nam như đều cấu hình chế độ này:

Đây là cấu hình cơ bản khi triển khai các ứng dụng Web nhưng nhiều kỹ sư triển khai vẫn chưa để ý việc này.

Giờ chúng ta sẽ tìm hiểu kỹ hơn tại sao cơ chế này lại giúp tăng tốc độ của ứng dụng Web? Thực tế khi server chưa hỗ trợ nén, khi bạn thực gửi request, dữ liệu trả về ở dạng text thuần với kích thước rất lớn, sẽ mất nhiều thời gian trong việc truyền tải dữ liệu:
https://laptrinh365.blogspot.com - Tối ưu tốc độ web qua HTTP 
Trong khi đó nếu server cấu hình chế độ nén, kích thước Response trả về sẽ giảm khoảng 5 đến10 lần, do đó thời gian tải dữ liệu sẽ nhanh hơn:
 https://laptrinh365.blogspot.com - Tối ưu tốc độ web qua HTTP
=> Như vậy: Kích thước file nhỏ hơn <=> Tải dữ liệu nhanh hơn <=> Người dùng happy hơn.

2. Cấu hình trên các server Web

2.1 Cấu hình trên server Tomcat

Để cấu hình chế độ nén trên server Tomcat bạn thực hiện các bước như sau:
  • Bước 1: Trong thư mục của Tomcat bạn mở tệp conf/server.xml bằng trình soạn thảo văn bản bất kỳ.
  • Bước 2: Tìm đến thẻ Connector
    https://laptrinh365.blogspot.com - Tối ưu tốc độ web qua HTTP 
  • Bước 3: Trong thẻ Connector, bạn thêm các thuộc tính với các giá trị như bên dưới:
     compression="on"  
     compressionMinSize="2048"  
     noCompressionUserAgents="gozilla, traviata"  
     compressableMimeType="text/html,text/xml,text/css,text/plain,application/json, application/javascript,text/javascript,application/x-javascript"  
    
    Kết quả cấu hình như ảnh dưới:
    https://laptrinh365.blogspot.com - Tối ưu tốc độ web qua HTTP
  • Bước 4: Sau khi cấu hình xong, bạn restart lại server để kích hoạt cấu hình mới.

2.2 Cấu hình trên server Apache

Để cấu hình chế độ nén trên server Apache bạn thực hiện các bước như sau:
  • Bước 1: Vào thư mục triển khai ứng dụng Web của bạn trên server Apache, tìm và mở tệp .htaccess 
  • Bước 2: Thêm các dòng sau vào tệp .htaccess:
     # compress text, html, javascript, css, xml:  
     AddOutputFilterByType DEFLATE text/plain  
     AddOutputFilterByType DEFLATE text/html  
     AddOutputFilterByType DEFLATE text/xml  
     AddOutputFilterByType DEFLATE text/css  
     AddOutputFilterByType DEFLATE application/xml  
     AddOutputFilterByType DEFLATE application/xhtml+xml  
     AddOutputFilterByType DEFLATE application/rss+xml  
     AddOutputFilterByType DEFLATE application/javascript  
     AddOutputFilterByType DEFLATE application/x-javascript  
     # Or, compress certain file types by extension:  
     <files *.html>  
     SetOutputFilter DEFLATE  
     </files>  
    
  • Bước 3: Sau khi cấu hình xong, bạn restart lại server để kích hoạt cấu hình mới.

2.3 Cấu hình trên server ISS

Để cấu hình chế độ nén trên server IIS bạn có thể sử dụng một trong hai cách sau:
  • Cách 1: Sử dụng giao diện 
    • Bước 1: Mở trình quản lý “IIS Manager”, chuyển tới mức mà bạn muốn quản lý.
    • Bước 2: Trong “Features View” bạn kích vào “Compression”.
    • Bước 3: Trên trang “Compression”, chọn “Enable static content compression”.
    • Bước 4: Kích vào nút “Apply” trong khung “Actions”.
  • Cách 2: Sử dụng dòng lệnh
    Đánh lệnh sau trong cửa sổ dòng lệnh:
     appcmd set config /section:urlCompression /doStaticCompression:True  
    
(Ngoài chế độ “Static content compression”, ISS còn hỗ trợ chế độ “Dynamic content compression” nhưng khuyến cáo không nên sử dụng chế độ Dynamic vì chế độ này làm tăng tải của CPU). 

2.4 Cấu hình trên các server khác

Hầu hết các server đều hỗ trợ chế độ nén này, vì thế bạn có thể dễ dàng tìm được hướng dẫn bằng Google.

3. Kiểm tra trên ứng dụng Web

Với ứng dụng web, để hỗ trợ chế độ nén HTTP, bạn chỉ cần cấu hình trên server, còn trong ứng dụng bạn không phải làm gì. Để kiểm tra server đã bật chế độ nén này chưa bạn có thể sử dụng các cách sau:
  • Cách 1: Với site public, có thể nhập trực tiếp link site vào ô ” Web Page URL” trên trang ”Online gzip test”: 
  • Cách 2: Bật Firebug trên trình duyệt, sau đó kiểm tra Response Headers, nếu thấy có header Content-Encoding: ”gzip” thì server đã hỗ trợ chế độ nén.

4. Xử lý trên ứng dụng Android

Trên ứng dụng Android, khi xử lý lấy dữ liệu HTTP, bạn cần thêm header:
 Accept-Encoding="gzip,deflate"  

Và khi nhận Response về bạn phải kiểm tra header Content-Encoding, nếu có trường này trong header trả về thì phải xử lý thêm. Đoạn mã dưới là ví dụ trong đó phần chữ màu xanh là phần xử lý nén:

 public static String readDataFromServer(String url) {  
      StringBuilder builder = new StringBuilder();  
      HttpParams httpParameters = new BasicHttpParams();  
      HttpConnectionParams.setConnectionTimeout(httpParameters, 30000);  
      HttpConnectionParams.setSoTimeout(httpParameters, 30000);  
      HttpClient client = new DefaultHttpClient(httpParameters);  
      HttpGet httpGet = new HttpGet(url);  
      httpGet.setHeader("Referer", "http://" + AppInfo.getAppId());  
      httpGet.setHeader("Accept-Encoding", "gzip,deflate");  
      try {  
           HttpResponse response = client.execute(httpGet);  
           StatusLine statusLine = response.getStatusLine();  
           int statusCode = statusLine.getStatusCode();  
           if (statusCode == HttpStatus.SC_OK) {  
                // Kiem tra xem du lieu tra ve co duoc nen hay khong?  
                Header[] header = response.getHeaders("Content-Encoding");  
                boolean isCompressed = false;  
                if (header != null && header.length > 0) {  
                     for (int i = 0; i < header.length; i++) {  
                          if (header[i].getValue().indexOf("gzip") >= 0) {  
                               isCompressed = true;  
                               break;  
                          }  
                     }  
                }  
                HttpEntity entity = response.getEntity();  
                InputStream content = entity.getContent();  
                InputStreamReader in = null;  
                if (isCompressed) {  
                     // Giai nen du lieu truoc  
                     GZIPInputStream gzis = new GZIPInputStream(content);  
                     in = new InputStreamReader(gzis);  
                } else {  
                     // Du lieu khong duoc nen  
                     in = new InputStreamReader(content);  
                }  
                BufferedReader reader = new BufferedReader(in, 10*1024);  
                String line;  
                while ((line = reader.readLine()) != null) {  
                     builder.append(line);  
                }  
           } else {  
                // Có lỗi xảy ra  
           }  
      }  
      catch (ConnectTimeoutException e) {  
           // Timeout  
      }  
      catch (Exception e) {  
           // Có lỗi  
      }  
      return builder.toString();  
 }  

5. Xử lý trên ứng dụng iOS

Trên ứng dụng iOS, có lớp NSURLConnection có hỗ trợ chế độ nén này trong suốt, tức khi thêm header Accept-Encoding thì khi nhận được response về sẽ tự giải nén:
 [urlReq setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]