Giảm thiểu thời gian sữa lỗi với stack trace trong java

Chắc hẳn các lập trình viên Java đã quen với việc nhìn màn console trong lúc chạy chương trình, nó sẽ ghi lên những thông tin gì đó trong rất dài dòng, khó hiểu và thường với những người bắt đầu học Java thì thường bỏ qua chúng, và mình cũng vậy chẳng biết nó có ích gì nữa :lol:.

Và bạn sẽ làm gì khi chương trình của bạn bỗng nhiên bị crash? Với mình thì mình sẽ đi đến source code nơi mà nó thực thi chương trình bị lỗi và cố gắng tìm xem chỗ nào gây nên lỗi và thông thường công việc này rất mất thời gian! 

Thật may nếu chúng ta biết tận dụng Stack Trace trong trường hợp này có lẽ bug sẽ được giải quyết nhanh hơn nhiều! Vậy Stack Trace là gì vậy ta? 

Stack Trace trong java

Stack trace hay còn gọi là backtrace hoặc là backtrace là một danh sách các stack frame. Mỗi stack frame đại diện cho một đoạn chương trình được thực thi, chúng chứa các thông tin của một method và method gọi đến chúng.

Như vậy Stack trace là một danh sách các stack frame chứa danh sách các method được gọi ở thời điểm hiện tại cho đến lúc chúng bắt đầu.

Tại sao lại vậy? Nếu bạn biết đến Stack thì chúng hoạt đông theo nguyên lý First in last out (vào trước ra sau). Stack trace cũng hoạt động tương tự như vậy, các method đầu tiên sẽ nằm ở đầu stack frame, các method được gọi sau sẽ thêm vào cuối stack frame, một stack frame sẽ bị xoá khi method được gọi thực thi xong hoặc trả về kết quả.

Ví dụ


public class Main {

    public static void main(String[] args) {
        a();
    }

    static void a() {
        b();
    }

    static void b() {
        c();
    }

    static void c() {
        d();
    }

    static void d() {
        new Exception("Stack trace").printStackTrace();
    }
}

Output

java.lang.Exception: Stack trace
at Main.d(Main.java:22)
at Main.c(Main.java:18)
at Main.b(Main.java:14)
at Main.a(Main.java:10)
at Main.main(Main.java:6)

Sau khi mình in stack trace hiện hành tại d() thì có kết quả như trên, chúng ta thấy được rằng d() nằm đầu stack trace vì nó là method được gọi cuối cùng tiếp đến là c(), b()a() là method tại thời điểm bắt đầu chương trình.

Hum! thật là hay ho nếu một stack trace được in ra khi chương trình của mình bị lỗi từ đó mình có thể biết chính xác chỗ nào gây ra lỗi và nó được gọi từ đâu. Stack trace giống như bản đồ cho dev khi mù được vậy đó các bạn.

Thật may là khi xảy ra các exception trong java thì chúng đều được xuất ra màn hình console và bạn cũng có thể ghi chúng vào file log khi ứng dụng của bạn đã được deloy lên server, sau đó chúng ta có kiểm tra các file log và xem các stack trace được ghi vào để biết được ứng dụng của mình có đang hoạt động tốt hay không. Ngoài ra stack trace còn được sử dụng trong rất nhiều tình huống nữa đấy mà ở phần tiếp theo chúng ta sẽ đi tìm hiểu.

Sử dụng stack trace trong java

Java exceptions

Stack trace và exception thường đi liền với nhau trong java. Khi ứng dụng của bạn ném ra một exception đồng thời java cũng sẽ tạo một bản ghi stack trace lên màn hình console.

Điều trên là do cơ chết hoạt động của exception trong java, khi Java code ném ra một exception tại một method (chứa trong stack frame hiện tại – nằm ở đỉnh stack frame), bộ thực thi sẽ tìm kiếm một method xử lý chúng bằng cách đi ngược lên method gọi nó, nếu method này không xử lý thì tiếp tục đi lên cho đến hết stack frame, nếu duyệt hết stack frame mà không tìm thấy code xử lý exception thì chương trình bạn sẽ bị dừng, nếu có thì bộ thực thi sẽ giao cho chúng xử lý.

Ví dụ


public class Main {
    public static void main(String[] args)
    {
        try {
            a();
        } catch (NullPointerException ice) {
            System.err.println(ice.getMessage());
        }
    }

    static void a() throws NullPointerException
    {
        throw new NullPointerException("OOPs");
    }

}

Output: OOPs

Method a() đã ném ra NullpointerException method main đã bắt và xử lý chúng. Tuy nhiên cách làm trên vẫn chưa ổn lắm. Đặt trường hợp ứng dụng của bạn đã deloy, bạn kiểm tra log và thấy một dòng log OOPs như trên thì bạn có biết chuyện gì đang xảy ra với nó không? Ở các công ty lớn nếu bạn làm như trên thì trong khâu review code họ sẽ đánh cho bạn một lỗi critical đấy nhé.

Nên nhớ rằng khi bạn xử lý một exception hay log một exception gì đó bạn đã xử lý thì hãy nhớ kèm theo stack trace để đồng đội còn biết đường mà mò nhé.


public class Main {
    public static void main(String[] args)
    {
        try {
            a();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }

    static void a() throws NullPointerException
    {
        throw new NullPointerException("OOPs");
    }

}

Output:

java.lang.NullPointerException: OOPs
at Main.a(Main.java:15)
at Main.main(Main.java:7)

Note: Khi chương trình bị crash hãy nhanh chân xem stack trace trong màn hình console và xem stack frame đầu tiên để biết được dòng nào đang gây ra lỗi và dựa vào đó để kiểm tra các nguyên nhân gây ra lỗi như tham số đầu vào bị null etc. 

Logging Java stack trace

Như đã đề cập nhiều ở trên, trong quá trình ứng dụng của bạn được triển khai cho người dùng, bạn cần phải bảo trì chúng. Log các lỗi xảy ra vào file và tiến hành kiểm tra và sữa lỗi là một quy trình hầu như mọi dự án đều thực hiện để kịp thời sữa chữa các lỗi nghiêm trọng ảnh hưởng đến user và doanh thu cho doanh nghiệp. 

Trong Java bạn đã có các thư viện hỗ trợ logging mạnh mẽ như Log4jLogBack. Tuy nhiên các file log thường sẽ log rất nhiều và kích thước của chúng sẽ ngày càng phìm to bạn nên có cách quản lý chúng hiệu qua. Như mình thì mỗi file log mình chỉ cho tối đa dung lượng 5MB, nếu nhiều hơn sẽ tách ra ghi file mới. Sau mỗi 15 ngày kể từ khi chúng được ra sẽ bị xoá. Nên các bạn nó kiểm tra file log định kỳ và xoá chúng đi nhé. 

Java debug 

Debug là một trong những điều bắt buộc mà lập trình viên Java nào cũng phải thành thạo để có thể phát triển ứng dụng Java nhanh và hiệu quả. 

Khi bạn đặt một breakpoint tại một dòng code, trình debug dừng lại ở đó và nó cũng cho phép mình coi stack trace để biết cội nguồn của nó bắt đầu từ đâu.

stack trace in java

Như hình trên stack trace cho chúng ta biết hiện tại đang ở hàm a() và nó được gọi từ main(). Bạn có thể double click để vào thẳng dòng code đó trong intellij hoặc các IDE khác cũng tương tự.

Kết

Stack trace là một phần rất quan trọng cho những người mới học java, mà đa số mình thấy các bạn mới đầu học không quá quan trọng mà chỉ quan tâm đến các vấn đề technical. Vô tình làm cho các bạn học chậm hơn vì khi gặp lỗi các bạn chẳng biết làm gì để sữa lỗi cho nhanh ngoài việc ngồi đoán mò có khi mất đến máy ngày để sữa xong một lỗi bé tí. 

Đây là kinh nghiệm của mình vì trước đây mình cũng vậy, không qua giờ quan tâm mà thật ra cũng không biết stack trace là gì luôn cho nên sữa lỗi khá là lâu. Và nó cũng là một trong những bài training đầu tiên khi mình bước chân vào một công ty lớn làm về java. 

Nguồn tham khảo

https://www.scalyr.com/blog/java-stack-trace-understanding/

Understanding and Leveraging the Java Stack Trace

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x