Log rất quan trọng trong ứng dụng vậy ghi log thế nào cho đúng?

Overview

1. Log là gì? Tại sao cần thiết ghi log?

Log là những bạn dạng ghi, tài liệu về sự việc khiếu nại xẩy ra trong lúc phần mềm của người tiêu dùng hoạt động và sinh hoạt.

Tại sao cần được ghi log?

Trong quy trình hoạt động và sinh hoạt luôn luôn trực tiếp sở hữu những trường hợp bất ngờ xẩy ra, những nước ngoài lệ chúng ta ko tính cho tới và khi ê log thể hiện nay tầm quan trọng của tớ. Nó giúp đỡ bạn tìm hiểu rời khỏi nguyên vẹn nhân trường hợp bất ngờ giúp đỡ bạn xử lý nó. Trong môi trường xung quanh develop chúng ta trọn vẹn rất có thể dùng những khí cụ tuy nhiên IDE tương hỗ nhằm debug. Nhưng bên trên môi trường xung quanh product các bạn ko thể tái ngắt hiện nay được lỗi xẩy ra. Ví dụ: Khách sản phẩm gửi chi phí ko thành công xuất sắc các bạn ko thể đòi hỏi quý khách gửi lại nhằm các bạn đánh giá được. Vậy nếu như ghi log chính bạn cũng có thể trải qua ê tìm hiểu rời khỏi nguyên vẹn nhân lỗi nhằm xử lý.

Bạn đang xem: Log rất quan trọng trong ứng dụng vậy ghi log thế nào cho đúng?

2. Chúng tớ cần thiết ghi log những gì?

Dữ liệu nguồn vào và đầu ra

Thường là API Enpoint, Controller, Listener(DB, message queue)... tiếp tục ghi lại những vấn đề tương quan cho tới tài liệu nguồn vào và sản phẩm trả ra phía bên ngoài.

Với một API bạn cũng có thể ghi những vấn đề như request/response body toàn thân, header, ip, parameters, url, vấn đề người tiêu dùng, thời hạn xử lý.

Với những input kể từ database, message queue này ê thì bạn cũng có thể ghi input object và output object.


Chú ý: Mỗi một luồng xử lý bạn phải tạo nên cho tới nó một ID nhằm đáp ứng cho tới việc hiểu log đơn giản và dễ dàng rộng lớn.

Ví dụ như sau:

1INFO: Add user with request { "user": "test1", "email": "[email protected]" }
2INFO: Add user with request { "user": "test2", "email": "[email protected]" }
3INFO: Get connection to lớn database successfully.
4INFO: Success
5INFO: Get connection to lớn database successfully
6ERROR: Thư điện tử already exist

Như ví dụ bên trên bản thân sở hữu 2 request tạo nên user đôi khi và 1 request thành công xuất sắc, một request thất bại tuy nhiên các bạn sẽ ko hiểu rằng loại này thành công xuất sắc, loại này thất bại. Nếu lượng request nhiều lên nữa và log bao gồm nhiều vấn đề thì tiếp tục đặc biệt khó khăn nhằm rất có thể hiểu và tìm hiểu rời khỏi lỗi.

Khi tạo nên ID cho từng request và ghi nhập log tất cả chúng ta tiếp tục đơn giản và dễ dàng rất có thể tra cứu vớt được luồng xử lý.

1[00000001] - INFO: Add user with request { "user": "test1", "email": "[email protected]" }
2[00000002] - INFO: Add user with request { "user": "test2", "email": "[email protected]" }
3[00000002] - INFO: Get connection to lớn database successfully.
4[00000002] - INFO: Success
5[00000001] - INFO: Get connection to lớn database successfully.
6[00000001] - ERROR: Thư điện tử already exist

Với những tủ sách ghi log của JAVA (với những framework blocking dùng thread cho tới từng request như Spring) thì khá dễ dàng dàng

 1SLF4j: MDC
 2LOG4J2: ThreadContext
 3
 4public void filter() {
 5    String logId = generateLogId();
 6    MDC.put("log_id", logID);
 7    ///
 8    /// Do some things 
 9    ///
10    // Nếu hàm rất có thể văng exception thì cho tới nhập block try finnally
11    MDC.clear();
12}

Với những hàm non-blocking thì những các bạn sẽ nên truyền logId trải qua param và ghi tay chân. (Nếu các bạn tìm kiếm được cách tiếp theo đơn giản và dễ dàng hơn nữa thì báo bản thân nhé).

Đây là 1 trong những hàm helper khi sử dụng vertx, khi request nhập thì tiếp tục mix logId nhập RoutingContext và khi hàm trả lại sản phẩm thì lấy logId rời khỏi và dùng.

 1package com.truongnq;
 2
 3import io.vertx.core.AsyncResult;
 4import io.vertx.core.Handler;
 5import io.vertx.core.buffer.Buffer;
 6import io.vertx.ext.web.RoutingContext;
 7import lombok.extern.slf4j.Slf4j;
 8import com.truongnq.Constant;
 9
10import java.util.function.Function;
11
12/**
13 * @author truongnq
14 * Date: 19/01/2021
15 */
16@Slf4j
17public class ResultHandler {
18
19    private ResultHandler() {
20    }
21
22    /**
23     * This method generates handler for async methods in REST APIs.
24     */
25    public static <T> Handler<AsyncResult<T>> create(RoutingContext context, Function<T, Buffer> converter) {
26        return create(context, converter, 200);
27    }
28
29    public static <T> Handler<AsyncResult<T>> create(RoutingContext ctx,
30                                                     Function<T, Buffer> converter,
31                                                     int status) {
32        return res -> {
33            // Lấy logId và thời hạn request kể từ context
34            final String logId = ctx.get(Constant.LOG_TOKEN_NAME);
35            final Long startTime = ctx.get(Constant.REQUEST_TIME);
36            try {
37                if (res.succeeded()) {
38                    Buffer response = converter.apply(res.result());
39                    log.info("[{}] - Response: {}", logId, response);
40                    ctx.response().setStatusCode(status).end(response);
41                } else {
42                    ctx.fail(res.cause());
43                }
44            } catch (Throwable cause) {
45                ctx.fail(cause);
46            } finally {
47                long processTime = System.currentTimeMillis() - startTime;
48                log.info("[{}] - Request finish in: {}", logId, processTime);
49            }
50        };
51    }
52}

Các bước xử lý trong những hàm, những service

Ngoài những đầu tiêu thụ tài liệu kể từ những mối cung cấp bên phía ngoài phần mềm thì những service, những hàm nội cỗ cũng nên ghi log input và output. Thường được ghi với những nấc log thấp hơn hoàn toàn như DEBUG. Nó tiếp tục tương hỗ tìm hiểu và xử lý lỗi tương quan cho tới logic và nhiệm vụ. Ghi rõ rệt quá trình xử lý, và nếu như có tương đối nhiều case trả về nằm trong sản phẩm cần thiết ghi thêm thắt nguyên vẹn nhân.

 1// Đây là 1 trong những hàm nhập websocket server dùng Netty.
 2// Hàm gửi thông tin cho tới những websocket client
 3public boolean notify(Set<ChannelId> sessionIds, @Nonnull Notify<?> notifyMessage) {
 4    long logId = notify.getId();
 5    if (null == sessionIds || sessionIds.isEmpty()) {
 6        // Thành công tuy nhiên đó là case quan trọng đặc biệt vì thế không tồn tại client này được truyền nhập.
 7        log.debug("[{}] - Empty sessions", logId);
 8        return true;
 9    }
10    // Chuẩn bị tài liệu nhằm gửi
11    log.debug("[{}] - Prepare data to lớn send", logId);
12    sessionIds.forEach(session::send);
13    log.debug("[{}] - All message are scheduled to lớn send", logId);
14    // Thành công gửi thông tin cho tới những client
15    return true;
16}

Các vấn đề tương quan cho tới hưởng thụ người tiêu dùng, hoặc tổng hợp cho tới mục tiêu sale.

Khi một tính năng tốn rất nhiều thời hạn nhằm xử lý hoặc thông thường xuyên lỗi tất cả chúng ta cũng cần được ghi lại nhằm tách tác động cho tới cảm biến người tiêu dùng.

Các vấn đề tổng hợp rất có thể dùng cho tới sale như con số thanh toán, lô hàng trong thời gian ngày, con số người tiêu dùng trực tuyến ... cũng rất có thể được ghi lại.

Thông tin cậy tương quan khi thay cho thay đổi dữ liệu

Khi sở hữu những thay cho thay đổi tài liệu (CRUD) tất cả chúng ta cần thiết lưu vấn đề mối cung cấp tạo nên đòi hỏi, rất có thể từ là một người tiêu dùng hoặc từ là một khối hệ thống không giống. Các vấn đề thông thường lưu như userName, serviceId, thời hạn, hành động (Thêm mới mẻ, sửa, xoá, đọc). Các ngôi trường tài liệu có khả năng sẽ bị thay cho thay đổi và nếu như quan trọng rất có thể lưu cả vấn đề bạn dạng ghi cũ và mới mẻ.

Thông tin cậy tương quan cho tới perfomance

Ví dụ:

  • Số thứ tự gọi API (Thành công và thất bại)
  • Tài nguyên vẹn dùng (CPU, Mem)
  • Thời gian giảo xử lý trung bình
  • Tỷ lệ lỗi.

Các rủi ro khủng hoảng và lỗ hổng bảo mật

Trước bản thân đã có được nghe anh thaidn(https://vnhacker.blogspot.com/) nói đến việc thực hiện bảo mật thông tin.

Việc thi công một phần mềm bảo mật thông tin chất lượng tốt tương tự xây một bức tường chắn rào thiệt cao. Nhưng cao bao nhiêu rồi cũng rất có thể bị đột nhập. Vậy nên ngoài xây tường cao thì người tớ còn tồn tại thêm thắt những camera, cảm ứng vận động ... nhằm ngăn chặm đột nhập.

Với phần mềm bạn cũng có thể ghi lại log những rủi ro khủng hoảng tiềm ẩn những hành vi xứng đáng ngờ của người tiêu dùng, cũng như các thay cho thay đổi không bình thường của khối hệ thống.

Ví dụ:


Người người sử dụng singin thất bại rất nhiều lần. Các vấn đề rất có thể ghi lại như:

Xem thêm: TOP 9 cách khóa màn hình máy tính đơn giản, chống nhìn trộm

  • UserName
  • Địa chỉ IP người dùng
  • Số thứ tự thất bại
  • Thời gian
  • Phân quyền của những người dùng


Hệ thống sở hữu tuy nhiên vấn đề không bình thường về:

  • Tài nguyên vẹn tiêu xài thụ
  • Thời gian giảo xử lý
  • Số lượng lỗi

Tất những cụm vấn đề bên trên được ghi lại rất có thể được dùng cho những khối hệ thống khí cụ monitor nhằm chú ý cho tới người giám sát.

3. Những tài liệu tránh việc log hoặc là phải ẩn vấn đề trước lúc ghi log.


Ẩn vấn đề rất có thể tiến hành vày cách:

  • Mask SDT: 0987654321 -> 098***321, Số tài khoản: A0003249230204 -> A00***0204
  • Xoá vứt trọn vẹn ko lưu nhập log
  • Mã hoá

Tuỳ nhiệm vụ tuy nhiên con số và địa điểm ký tự động được hội tụ lại rất có thể thay cho thay đổi.


Thông tin cậy cá thể người tiêu dùng.

  • Tên
  • Tuổi
  • Địa chỉ
  • Số năng lượng điện thoại

Thông tin cậy thanh toán

  • Số tài khoản
  • Số thẻ
  • Số dư

Các thông tin

  • Mật khẩu
  • Auth token
  • Private key
  • Secret key

4. Tổng kết

Ghi log nên sở hữu log id cho 1 luồng xử lý

12021-11-06T18:50:49+05:30 - INFO  -[fJLKjlkqjCLlqjwerlJKLZ] - GET /user/1
22021-11-06T18:50:49+05:30 - DEBUG -[fJLKjlkqjCLlqjwerlJKLZ] - [201.123.100.103] GET / HTTP/1.1 200 22.415µs Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, lượt thích Gecko) Chrome/78.0.3904.108 Safari/537.36
32021-11-06T18:50:50+05:30 - ERROR -[fJLKjlkqjCLlqjwerlJKLZ] - [201.123.100.103] Can't connect to lớn the database
42021-11-06T18:50:50+05:30 - INFO  -[fJLKjlkqjCLlqjwerlJKLZ] - [201.123.100.103] Can't get user info. Response to lớn client { "code": 500, "message": "internal error"

Sử dụng chính log level

Tài liệu tham ô khảo: https://reflectoring.io/logging-levels/

  • FATAL: Các lỗi rất có thể tạo ra ngừng phần mềm. Thường ghi rời khỏi nguyên vẹn nhân lỗi trước lúc phần mềm bị ngừng. Ví dụ: Tràn bộ nhớ lưu trữ.

  • ERROR: Thường được dùng khi những yếu tố tương quan cho tới business ko thể tiến hành được bởi nguyên do về chuyên môn và ko thể xử lý. Ví dụ: Lỗi xẩy ra khi trừ tiền

    • Không thể trừ chi phí bởi thông tin tài khoản ko đầy đủ hoặc thông tin tài khoản đích ko tồn bên trên -> Đây ko nên lỗi của phần mềm.
    • Không thể trừ chi phí bởi ko liên kết được cho tới hạ tầng tài liệu -> Đây là lỗi.

Khi vạc hiện nay log ERROR rất có thể developer tiếp tục nên sửa tức thì nhằm đáp ứng phần mềm kế tiếp hoạt động và sinh hoạt đúng đắn. Vậy các bạn tránh việc sử dụng quá log error nhằm tách có được những chú ý ko quan trọng. Trong Java một vài Exception được các bạn dẫn đến và được xử lý ví dụ khi login không tìm kiếm thấy User các bạn throw rời khỏi UserNotFoundException tình huống này cần thiết suy nghĩ nhằm ko ghi log Error nếu như không các bạn sẽ có được chú ý lỗi thông thường xuyên.

  • WARN: Các chú ý cũng cần được đánh giá và xử lý tuy nhiên phỏng ưu tiên thấp rộng lớn ERROR. Các chú ý như tỷ trọng lỗi cao, lượng ram to hơn nấc thông số kỹ thuật (ví dụ: 70%). Hoặc với những lỗi liên kết tuy nhiên sở hữu phương án xử lý như demo lại(retry). Ví dụ: Không gửi được bạn dạng tin cậy lên kafka bạn cũng có thể gửi lại và ghi log WARN cho tới việc này, sau một vài thứ tự chắc chắn tuy nhiên ko thành công xuất sắc thì rất có thể Đánh Giá và ghi log ERROR.

  • INFO: Các bạn dạng tin cậy, sự khiếu nại cần thiết trong lúc phần mềm hoạt động và sinh hoạt.

  • DEBUG: Thường dùng nhằm log lại cụ thể rộng lớn quá trình xử lý nhập phần mềm nhằm mục đích mục tiêu debug. Thông thông thường những log này tiếp tục dùng bên trên môi trường xung quanh develop và test, nhiều lúc log debug cũng sẽ tiến hành dùng nhập môi trường xung quanh product nhập quá trình đầu dự án công trình hoặc khi có vấn đề cần thiết thêm thắt vấn đề và được tắt lên đường khi phần mềm tiếp tục hoạt động và sinh hoạt ổn định ấn định.

Nên dùng giờ đồng hồ Anh khi ghi log.

Đây là khuyến nghị chứ không cần yêu cầu, thông thường ngôn từ ghi log tiếp tục theo gót quy ấn định doanh nghiệp.

Ghi log ngắn ngủi gọn gàng nhất sở hữu thể

Nếu ghi log vượt lên trước lâu năm rất có thể tác động cho tới vận tốc ghi log, tệp tin log tiếp tục nặng nề rộng lớn và rất có thể thực hiện hạn chế thời hạn rất có thể tàng trữ log. Vậy hãy nỗ lực ghi log ngắn ngủi gọn gàng và rõ rệt nghĩa.

Ghi log source (Vị trí log được ghi nhập code)

Khi hiểu log rất có thể xác lập được log ở hàm này (Class, hàm, loại này ghi rời khỏi log này)

Không trùng những câu thông báo

Nhiều các bạn hoặc copy những câu log dẫn cho tới bị sai sót hàm hoặc những log bị trùng như này.

12021-11-05 23:05:27 INFO - Request {some object}
22021-11-05 23:05:28 INFO - Response {some object}

Và copy cho tới toàn bộ từng hàm. Nếu log source thì vẫn tiếp tục tra cứu vớt được tuy vậy theo gót chủ ý cá thể từng hàm nên sở hữu log riêng rẽ đễ dễ dàng tra cứu vớt và kể từ log rất có thể lấy vấn đề tức thì tuy nhiên ko cần thiết nhập code.

12021-11-05 23:05:27 INFO - [000001] - UserController:23 - Create user with request {some object}
22021-11-05 23:05:28 INFO - [000001] - UserController:28 - Create user successfully. User info {some object}
12021-11-05 23:05:27 INFO - [000003] - UserController:23 - Update permission request {some object}
22021-11-05 23:05:28 ERROR - [000003] - UserController:28 - Update permission fail by blablabla

Ẩn những vấn đề nhạy bén cảm

Như nhập mục 3 tiếp tục nêu bạn cũng có thể mã hoá, mask hoặc vô hiệu trọn vẹn vấn đề nhạy bén ngoài log.

Với log error cần thiết ghi cụ thể

Ví dụ với log4j2 nhập Java: Thay vì thế ghi

Xem thêm: Cách tính tỉ lệ gia tăng dân số tự nhiên

log.error("Fail to lớn bởi something", ex.getMessage());

12021-11-05 23:05:28 ERROR - [000003] - UserController:28 - Fail to lớn bởi something NullPointerException

Thì tớ tiếp tục ghi rất đầy đủ stacktrace:

log.error("Fail to lớn bởi something", ex);

12021-11-05 23:05:28 ERROR - [000003] - UserController:28 - Fail to lớn bởi something java.lang.NullPointerException
2  at com.truongnq.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
3  at ...
4  at com.truongnq.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
5  at ...
6  at com.truongq.product.MyTest.test(MyTest.java:37)

Cấu hình cho tới log

  • Bật level log nào
  • Dung lượng tối nhiều cho 1 tệp tin log, số tệp tin log tối nhiều tàng trữ ...
  • Một số mặt mũi nhằm thuận tiện cho tới việc chú ý những tệp tin log Error sẽ tiến hành ghi riêng rẽ.