Skip to Main Content
☕ Ủng hộ cafe

☕ Mời mình một ly cafe

Nếu tài liệu này hữu ích, bạn có thể ủng hộ mình một ly cafe để mình có thêm động lực viết tiếp ❤️

QR Support
Ngân hàng: VC Bank
Chủ tài khoản: DO KHAC LAM
Số tài khoản: 7906077097
Nội dung: Ung ho Dokhala
Cảm ơn bạn đã ủng hộ Dokhala 🙏
💬 Liên hệ

💬 Kết nối với mình

Bạn cần hỏi thêm về Oracle APEX, góp ý nội dung, hoặc muốn trao đổi dự án? Có thể nhắn mình qua các kênh dưới đây.

← Quay lại bài viết

Sử dụng APEX_DEBUG để troubleshooting trong Oracle APEX

Tìm hiểu cách dùng APEX_DEBUG để troubleshooting trong Oracle APEX: bật debug, ghi log message, kiểm tra session state, debug Page Process, Dynamic Action, PL/SQL package và performance.

Khi xây dựng ứng dụng Oracle APEX, sẽ có những lúc page không chạy đúng như mong đợi: process không được gọi, item không nhận giá trị mới, report không ra dữ liệu, Dynamic Action không hoạt động, hoặc PL/SQL package trả kết quả khác với suy nghĩ ban đầu.

Trong các tình huống đó, đoán lỗi bằng cảm giác thường rất mất thời gian. Cách làm tốt hơn là bật debug và ghi lại các thông tin quan trọng trong quá trình page chạy. Đây là lúc APEX_DEBUG trở thành công cụ rất hữu ích cho lập trình viên APEX.

APEX_DEBUG giúp bạn ghi message vào APEX Debug Log, theo dõi luồng xử lý, kiểm tra giá trị page items, biết process nào chạy, SQL nào mất nhiều thời gian, và phát hiện các điểm bất thường trong runtime của ứng dụng.

APEX_DEBUG là gì?

APEX_DEBUG là package có sẵn trong Oracle APEX, dùng để ghi thông tin debug trong quá trình ứng dụng chạy. Các message do bạn ghi sẽ nằm chung trong APEX Debug Log, cùng với các message do APEX engine tự tạo.

Điều này rất tiện vì bạn không phải tự tạo bảng log riêng chỉ để debug các lỗi ngắn hạn. Khi debug mode được bật, bạn có thể ghi message từ Page Process, Dynamic Content, Validation, Authorization, PL/SQL package hoặc các đoạn code chạy trong ngữ cảnh APEX session.

Ví dụ đơn giản:

begin
  apex_debug.message('Start submit order process. Order ID = %s', :P10_ORDER_ID);
end;

Khi page chạy ở debug mode, message này sẽ xuất hiện trong debug log. Nếu debug mode không bật, các message debug thông thường sẽ không làm rối log runtime.

Lược đồ troubleshooting với APEX_DEBUG

APEX_DEBUG troubleshooting flow

Enable Debug

Bật debug từ Developer Toolbar, URL parameter hoặc code khi cần.

Log Context

Ghi page item, user, process, branch, SQL parameter và business state.

Analyze Log

Xem Debug Messages, tìm lỗi, thời gian chạy, session state và process flow.

Debug tốt không phải là ghi thật nhiều message. Debug tốt là ghi đúng ngữ cảnh, đúng thời điểm và đủ thông tin để bạn tái hiện được luồng xử lý.

Bật Debug trong Oracle APEX

Cách dễ nhất để bật debug là dùng Developer Toolbar khi đang chạy ứng dụng từ App Builder. Bạn bấm nút Debug, sau đó chạy lại thao tác cần kiểm tra.

Ngoài ra, bạn có thể bật debug bằng URL parameter. Ví dụ:

f?p=100:10:123456789:::::YES

Hoặc dùng mức debug chi tiết hơn nếu môi trường hỗ trợ:

f?p=100:10:123456789:::::LEVEL4

Sau khi thao tác xong, bạn có thể vào phần Debug Messages để xem log.

App Builder
→ Monitor Activity
→ Debug Messages

Hoặc trong một số giao diện APEX:

App Builder
→ Utilities
→ Debug

Các mức log thường dùng

APEX_DEBUG hỗ trợ nhiều mức message khác nhau. Trong thực tế, bạn thường dùng các loại sau:

  • apex_debug.error: ghi lỗi nghiêm trọng.
  • apex_debug.warn: ghi cảnh báo, lỗi có thể xử lý được.
  • apex_debug.info: ghi thông tin nghiệp vụ hoặc trạng thái quan trọng.
  • apex_debug.message: ghi message debug thông thường.
  • apex_debug.trace: ghi chi tiết hơn, phù hợp khi cần theo dõi sâu.

Không phải lúc nào cũng nên dùng mức chi tiết cao. Debug càng nhiều thì page càng có thể chậm hơn, log càng dài và việc đọc log càng khó. Vì vậy, hãy chọn mức log phù hợp với mục tiêu troubleshooting.

Ghi message cơ bản bằng APEX_DEBUG.MESSAGE

Cách dùng phổ biến nhất là ghi message kèm biến. Ví dụ:

begin
  apex_debug.message(
    p_message => 'Customer ID = %s, Status = %s',
    p0        => :P20_CUSTOMER_ID,
    p1        => :P20_STATUS
  );
end;

Cách ghi này giúp bạn biết tại thời điểm process chạy, item đang có giá trị gì. Đây là kỹ thuật rất hữu ích khi debug lỗi session state.

Ví dụ, trên màn hình bạn thấy item đã đổi, nhưng PL/SQL vẫn nhận giá trị cũ. Khi đó debug message sẽ giúp bạn phát hiện có thể bạn đã quên cấu hình Items to Submit trong Dynamic Action.

Dùng APEX_DEBUG.INFO cho thông tin nghiệp vụ

Với các bước quan trọng trong luồng xử lý, bạn có thể dùng apex_debug.info.

begin
  apex_debug.info('Start approving expense. Expense ID = %s', :P30_EXPENSE_ID);

  expense_pkg.approve_expense(
    p_expense_id => :P30_EXPENSE_ID,
    p_user       => :APP_USER
  );

  apex_debug.info('Expense approved successfully. Expense ID = %s', :P30_EXPENSE_ID);
end;

Khi đọc log, bạn sẽ thấy rõ process bắt đầu ở đâu, gọi package nào và kết thúc ra sao. Nếu lỗi xảy ra ở giữa, bạn dễ khoanh vùng hơn.

Dùng APEX_DEBUG.WARN cho tình huống bất thường

Không phải tình huống bất thường nào cũng là lỗi nghiêm trọng. Ví dụ, user mở một bản ghi không còn tồn tại, dữ liệu tùy chọn bị thiếu, hoặc API bên ngoài trả response chậm nhưng hệ thống vẫn có fallback.

begin
  if :P10_CUSTOMER_ID is null then
    apex_debug.warn('Customer ID is null before loading customer details.');
  end if;
end;

Warning giúp bạn phát hiện các tình huống cần chú ý mà không nhất thiết làm page dừng ngay.

Dùng APEX_DEBUG.ERROR khi bắt lỗi

Khi bắt exception trong PL/SQL, bạn nên ghi lại thông tin đủ rõ để debug.

begin
  order_pkg.submit_order(
    p_order_id => :P10_ORDER_ID,
    p_user     => :APP_USER
  );

exception
  when others then
    apex_debug.error(
      p_message => 'Submit order failed. Order ID = %s, Error = %s',
      p0        => :P10_ORDER_ID,
      p1        => sqlerrm
    );

    raise;
end;

Lưu ý: ghi debug không có nghĩa là nuốt lỗi. Nếu lỗi cần hiển thị hoặc rollback, bạn vẫn nên raise lại hoặc xử lý theo cơ chế error handling phù hợp.

Debug Page Process

Page Process là nơi thường có nhiều logic quan trọng: lưu dữ liệu, gọi package, gửi email, ghi log, tạo đơn hàng hoặc cập nhật trạng thái.

Khi debug Page Process, bạn nên ghi:

  • Process bắt đầu khi nào.
  • Request hiện tại là gì.
  • Các item chính có giá trị gì.
  • Package/procedure nào được gọi.
  • Kết quả hoặc lỗi trả về là gì.

Ví dụ:

begin
  apex_debug.info('Process SAVE_ORDER started. REQUEST = %s', :REQUEST);
  apex_debug.message('P10_ORDER_ID = %s', :P10_ORDER_ID);
  apex_debug.message('P10_CUSTOMER_ID = %s', :P10_CUSTOMER_ID);

  order_pkg.save_order(
    p_order_id    => :P10_ORDER_ID,
    p_customer_id => :P10_CUSTOMER_ID
  );

  apex_debug.info('Process SAVE_ORDER completed.');
end;

Khi process không chạy, debug log cũng có thể cho bạn biết do condition sai, request không khớp hoặc button không submit đúng như mong đợi.

Debug Dynamic Action

Dynamic Action dễ gây nhầm vì có phần chạy ở browser và có phần có thể gọi server-side code. Nếu dùng action Execute Server-side Code, bạn cần đặc biệt chú ý Items to SubmitItems to Return.

Ví dụ:

apex_debug.message('Quantity = %s', :P10_QUANTITY);
apex_debug.message('Unit Price = %s', :P10_UNIT_PRICE);

:P10_TOTAL := nvl(:P10_QUANTITY, 0) * nvl(:P10_UNIT_PRICE, 0);

apex_debug.message('Total = %s', :P10_TOTAL);

Nếu log cho thấy P10_QUANTITY hoặc P10_UNIT_PRICE vẫn là giá trị cũ, khả năng cao là bạn chưa thêm item đó vào Items to Submit.

Debug PL/SQL Package được gọi từ APEX

Nhiều ứng dụng tốt sẽ đưa business logic vào package PL/SQL. Khi package được gọi trong ngữ cảnh APEX session, bạn vẫn có thể dùng APEX_DEBUG bên trong package.

procedure submit_order(
  p_order_id in orders.order_id%type,
  p_user     in varchar2
) is
begin
  apex_debug.info('submit_order started. order_id=%s, user=%s', p_order_id, p_user);

  -- Business logic here

  apex_debug.info('submit_order completed. order_id=%s', p_order_id);

exception
  when others then
    apex_debug.error('submit_order failed. order_id=%s, error=%s', p_order_id, sqlerrm);
    raise;
end;

Cách này giúp debug log hiển thị liền mạch từ Page Process đến package bên dưới. Bạn sẽ không bị mất dấu khi logic đi qua nhiều lớp.

Debug Session State

Rất nhiều lỗi APEX liên quan đến session state. Trên màn hình user thấy một giá trị, nhưng PL/SQL lại nhận giá trị khác. Điều này thường xảy ra khi:

  • Dynamic Action gọi server-side code nhưng quên Items to Submit.
  • Item bị set bằng JavaScript nhưng chưa submit về server.
  • Process chạy trước khi item được tính lại.
  • Branch hoặc redirect làm mất context.
  • Item source hoặc default value ghi đè giá trị.

Bạn có thể ghi lại giá trị item:

apex_debug.message('Session state P20_STATUS = %s', v('P20_STATUS'));
apex_debug.message('Bind value P20_STATUS = %s', :P20_STATUS);

Nếu cần kiểm tra sâu hơn, hãy xem Session State trong Developer Toolbar hoặc trong Debug Messages.

Debug SQL Query và Report không ra dữ liệu

Khi report không ra dữ liệu, đừng chỉ nhìn giao diện. Hãy kiểm tra:

  • SQL source có đúng không?
  • Bind variables có giá trị không?
  • Authorization hoặc condition có chặn region không?
  • Where clause có quá chặt không?
  • LOV hoặc item filter có trả giá trị như mong đợi không?

Bạn có thể log giá trị filter trước khi report chạy bằng process phù hợp, hoặc test query trong SQL Workshop với cùng giá trị bind.

apex_debug.message('Report filter customer_id = %s', :P10_CUSTOMER_ID);
apex_debug.message('Report filter status = %s', :P10_STATUS);

Với query phức tạp, một cách tốt là đưa query vào view, rồi test view riêng trong SQL Workshop. Sau đó APEX region chỉ cần filter thêm bằng page item.

Debug Performance

Debug log không chỉ giúp tìm lỗi logic, mà còn giúp bạn thấy page mất thời gian ở đâu. Khi bật debug, APEX có thể hiển thị thời gian render region, chạy process, execute query hoặc các bước runtime khác.

Nếu một page chậm, hãy xem:

  • Region nào mất nhiều thời gian nhất.
  • Query nào chạy lâu.
  • Process nào xử lý quá nhiều dữ liệu.
  • Dynamic Action nào gọi AJAX nhiều lần.
  • Plugin nào làm page render chậm.

Sau khi xác định điểm chậm, bạn có thể tối ưu SQL, thêm index, giảm số dòng trả về, lazy load region hoặc tách logic nặng sang background job/automation nếu phù hợp.

Debug JavaScript bằng apex.debug

Ngoài server-side APEX_DEBUG, phía client bạn có thể dùng apex.debug trong JavaScript để ghi log khi debug client-side.

apex.debug.info("Button clicked");
apex.debug.warn("Item value is empty", $v("P10_CUSTOMER_ID"));

Điều này hữu ích khi debug Dynamic Action, custom JavaScript, event binding hoặc logic UI. Với lỗi JavaScript, bạn cũng nên dùng Browser Developer Tools để xem Console, Network và DOM.

Không nên log dữ liệu nhạy cảm

Debug log có thể chứa dữ liệu runtime. Vì vậy, không nên ghi thông tin nhạy cảm như:

  • Mật khẩu.
  • OTP.
  • Token/API key.
  • Số tài khoản ngân hàng.
  • Dữ liệu cá nhân nhạy cảm.
  • Thông tin tài chính không cần thiết.

Ví dụ không nên:

apex_debug.message('User password = %s', :P101_PASSWORD);

Thay vào đó, nếu cần debug, chỉ log trạng thái:

apex_debug.message('Password item is not null = %s',
                   case when :P101_PASSWORD is not null then 'Y' else 'N' end);

Debug giúp tìm lỗi, nhưng không được biến thành nơi rò rỉ dữ liệu nhạy cảm.

Không nên bật debug mức cao trong production quá lâu

Debug level cao có thể làm page chậm hơn và tạo nhiều log hơn. Trong production, nếu cần debug một lỗi khó tái hiện, hãy bật có kiểm soát, giới hạn thời gian, giới hạn user/session nếu có thể, rồi tắt sau khi thu thập đủ thông tin.

Một nguyên tắc tốt:

  • Bật debug chi tiết trong dev/test.
  • Chỉ bật debug production khi thật sự cần.
  • Không bật debug rộng cho toàn bộ user nếu không cần.
  • Không log dữ liệu nhạy cảm.
  • Dọn hoặc kiểm soát retention của debug logs theo chính sách hệ thống.

Truy vấn Debug Messages bằng SQL

Trong một số trường hợp, bạn có thể muốn xem debug messages bằng SQL. APEX có các view metadata/log phù hợp tùy version và quyền truy cập. Một ví dụ thường gặp là xem từ view debug messages:

select *
from apex_debug_messages
where application_id = :APP_ID
order by message_timestamp desc;

Tùy môi trường và quyền schema, tên view hoặc quyền truy cập có thể khác nhau. Nếu không query được, bạn có thể xem trực tiếp trong App Builder thông qua màn hình Debug Messages.

Pattern debug trong package PL/SQL

Một pattern đơn giản là ghi log ở đầu và cuối procedure, đồng thời ghi log ở các nhánh quan trọng.

procedure process_payment(
  p_payment_id in payments.payment_id%type
) is
begin
  apex_debug.info('process_payment started. payment_id=%s', p_payment_id);

  -- Validate
  apex_debug.message('Validating payment...');

  -- Business logic
  apex_debug.message('Calling payment gateway...');

  -- Finish
  apex_debug.info('process_payment completed. payment_id=%s', p_payment_id);

exception
  when others then
    apex_debug.error('process_payment failed. payment_id=%s, error=%s',
                     p_payment_id,
                     sqlerrm);
    raise;
end;

Pattern này không quá phức tạp nhưng giúp bạn rất nhiều khi debug lỗi trong flow dài.

Checklist khi troubleshooting bằng APEX_DEBUG

Khi gặp lỗi trong APEX, bạn có thể đi theo checklist sau:

  1. Bật debug mode.
  2. Tái hiện lỗi bằng cùng user và cùng dữ liệu.
  3. Ghi log các page item quan trọng.
  4. Kiểm tra process/validation/branch có chạy đúng thứ tự không.
  5. Kiểm tra Dynamic Action có submit đúng items không.
  6. Kiểm tra SQL query và bind variables.
  7. Kiểm tra exception trong PL/SQL package.
  8. Xem thời gian chạy của region/process nếu page chậm.
  9. Tắt debug sau khi đã thu thập đủ thông tin.

Best practice khi dùng APEX_DEBUG

Một số nguyên tắc nên áp dụng:

  • Log message có ngữ cảnh rõ ràng, không ghi chung chung.
  • Ghi ID bản ghi, request, user, trạng thái nghiệp vụ khi cần.
  • Không log dữ liệu nhạy cảm.
  • Ghi log ở đầu, cuối và các nhánh quan trọng của process.
  • Dùng error, warn, info đúng mục đích.
  • Không bật debug level cao trong production quá lâu.
  • Đưa debug vào package quan trọng để theo dõi flow xuyên suốt.
  • Kết hợp với Browser Developer Tools khi debug client-side.

Kết luận

APEX_DEBUG là một công cụ rất quan trọng khi phát triển và vận hành ứng dụng Oracle APEX. Nó giúp bạn nhìn thấy ứng dụng đang chạy như thế nào ở runtime: page item có giá trị gì, process nào chạy, package nào được gọi, lỗi xảy ra ở đâu và bước nào mất nhiều thời gian.

Khi dùng đúng cách, debug log giúp giảm thời gian đoán lỗi, tăng khả năng phân tích nguyên nhân và làm cho quá trình troubleshooting có hệ thống hơn.

Điều quan trọng là debug phải có kỷ luật: log đúng ngữ cảnh, không log dữ liệu nhạy cảm, không bật debug mức cao quá lâu trong production và luôn tắt khi không còn cần thiết. Với những thói quen này, APEX_DEBUG sẽ trở thành một phần không thể thiếu trong quy trình phát triển Oracle APEX chuyên nghiệp.