R số dòng tập lệnh bị lỗi?


105

Nếu tôi đang chạy một tập lệnh R dài từ dòng lệnh (R --slave script.R), làm cách nào để tôi có thể đưa ra số dòng khi có lỗi?

Tôi không muốn thêm lệnh gỡ lỗi vào script nếu có thể - tôi chỉ muốn R hoạt động giống như hầu hết các ngôn ngữ script khác ...


31
Bất cứ cập nhập nào? Bốn 4 năm sau đó, dường như vẫn còn tồn tại vấn đề vẫn còn, mặc dù tất cả việc thông qua dòng chính của R.
Gui Ambros

Tôi cũng có một tập lệnh R rất dài với nhiều đầu ra nhỏ, tôi muốn in (gạch dưới) (gạch dưới) LINE / FILE (gạch dưới) (gạch dưới) (số dòng và tên tập lệnh) như vậy trong C, thay vì mã hóa số dòng vào nguồn.
mosh

Tôi không biết bên trong R có thực sự có khái niệm về 'số dòng' hay không. Tuy nhiên, nó có khái niệm về các nhiệm vụ hoàn thành, tức là các nhiệm vụ cấp cao nhất. Ví dụ, người ta có thể dễ dàng xác định một trình xử lý tác vụ để cho biết tác vụ cấp cao nhất nào không thành công. Tất nhiên, đó không phải là sự thoải mái tuyệt vời cho những người có chuỗi lớn hoặc các câu lệnh điều kiện lớn.
russellpierce

Câu trả lời:


45

Điều này sẽ không cung cấp cho bạn số dòng, nhưng nó sẽ cho bạn biết lỗi xảy ra ở đâu trong ngăn xếp cuộc gọi, điều này rất hữu ích:

traceback()

[Chỉnh sửa:] Khi chạy tập lệnh từ dòng lệnh, bạn sẽ phải bỏ qua một hoặc hai lệnh gọi, hãy xem traceback () cho các phiên R tương tác và không tương tác

Tôi không biết cách khác để thực hiện việc này mà không cần gỡ lỗi thông thường:

  1. gỡ lỗi ()
  2. trình duyệt ()
  3. tùy chọn (lỗi = khôi phục) [theo sau là tùy chọn (lỗi = NULL) để hoàn nguyên]

Bạn có thể muốn xem bài đăng liên quan này.

[Chỉnh sửa:] Xin lỗi ... chỉ thấy rằng bạn đang chạy cái này từ dòng lệnh. Trong trường hợp đó, tôi khuyên bạn nên làm việc với chức năng tùy chọn (lỗi). Đây là một ví dụ đơn giản:

options(error = quote({dump.frames(to.file=TRUE); q()}))

Bạn có thể tạo một tập lệnh phức tạp như bạn muốn với một điều kiện lỗi, vì vậy bạn chỉ nên quyết định thông tin nào bạn cần để gỡ lỗi.

Ngược lại, nếu có các khu vực cụ thể mà bạn lo ngại (ví dụ: kết nối với cơ sở dữ liệu), thì hãy bọc chúng trong một hàm tryCatch ().


Giải pháp được liên kết trong khối [Chỉnh sửa:] đầu tiên phù hợp với tôi. Cách tiếp cận tốt nhất dường như là nhận xét của @dshepherd, tức là thêm options(error=function() { traceback(2); if(!interactive()) quit("no", status = 1, runLast = FALSE) })(xem nhận xét của câu trả lời được chấp nhận). Tôi nghĩ sẽ có ý nghĩa nếu thêm nó vào câu trả lời ở đây thay vì chỉ cung cấp một liên kết đến một chủ đề khác.
cryo111

1
một tùy chọn mới cho phép của bạn có được những con số dòng trong traceback github.com/aryoda/tryCatchLog
lunguini

13

Việc làm options(error=traceback)cung cấp thêm một chút thông tin về nội dung của các dòng dẫn đến lỗi. Nó làm cho một dấu vết xuất hiện nếu có lỗi và đối với một số lỗi, nó có số dòng, có tiền tố là #. Nhưng nó trúng hoặc trượt, nhiều lỗi sẽ không lấy được số dòng.


2
Không hoàn toàn phù hợp với tôi. Tôi chỉ có một tệp và nó không hiển thị số dòng, chỉ cho biết No traceback availablesau lỗi.
Mark Lakata

11

Hỗ trợ cho điều này sẽ ra mắt trong phiên bản R 2.10 trở lên. Duncan Murdoch vừa đăng lên r-devel vào ngày 10 tháng 9 năm 2009 về findLineNum và setBreapoint :

Tôi vừa thêm một vài hàm vào R-devel để giúp gỡ lỗi. findLineNum()tìm dòng nào của hàm nào tương ứng với một dòng mã nguồn cụ thể; setBreakpoint()lấy đầu ra của findLineNumvà gọi trace()để thiết lập một điểm ngắt ở đó.

Chúng dựa vào việc có thông tin gỡ lỗi tham chiếu nguồn trong mã. Đây là mặc định cho mã được đọc bởi source(), nhưng không phải cho các gói. Để lấy các tham chiếu nguồn trong mã gói, hãy đặt biến môi trường R_KEEP_PKG_SOURCE=yeshoặc trong R, đặt options(keep.source.pkgs=TRUE), sau đó cài đặt gói từ mã nguồn. Đọc ?findLineNumđể biết chi tiết về cách yêu cầu nó tìm kiếm trong các gói, thay vì giới hạn tìm kiếm trong môi trường toàn cầu.

Ví dụ,

x <- " f <- function(a, b) {
             if (a > b)  {
                 a
             } else {
                 b
             }
         }"


eval(parse(text=x))  # Normally you'd use source() to read a file...

findLineNum("<text>#3")   # <text> is a dummy filename used by
parse(text=)

Điều này sẽ in

 f step 2,3,2 in <environment: R_GlobalEnv>

và bạn có thể sử dụng

setBreakpoint("<text>#3")

để thiết lập một điểm ngắt ở đó.

Vẫn còn một số hạn chế (và có thể là lỗi) trong mã; Tôi sẽ sửa lỗi


Cảm ơn. Cũng vừa đăng ký danh sách gửi thư r-devel. Tôi đã tránh r-help với giả định rằng nó sẽ làm tắc nghẽn hộp thư đến của tôi (r-sig-Finance đã làm điều đó).
Shane

1
không thực sự hiểu cách điều này hoạt động từ dòng lệnh mà không cần xem xét trong tập lệnh R
Herman Toothrot

1
@hirse: Đây là câu trả lời cũ gần mười của bạn. Tại sao bạn định dạng lại nó để giả vờ như tôi đang trích dẫn? Tôi đã không, và thay đổi của bạn không phản ánh ý định của tôi.
Dirk Eddelbuettel

"Duncan Murdoch vừa đăng:" nghe rất giống một câu trích dẫn, nhưng nếu điều đó không chính xác, vui lòng hoàn nguyên bản chỉnh sửa. Tôi muốn làm cho nó dễ đọc hơn cho chính mình và đã không kiểm tra ngày cho đến khi tôi hoàn thành. Nếu toàn bộ câu trả lời đã quá lỗi thời, bạn cũng có thể xóa nó để loại bỏ sự nhầm lẫn cho người đọc trong tương lai.
hirse

Bạn có thể vui lòng hoàn nguyên nó được không? Cảm ơn bạn.
Dirk Eddelbuettel

6

Bạn làm điều đó bằng cách thiết lập

options(show.error.locations = TRUE)

Tôi chỉ thắc mắc tại sao cài đặt này không phải là cài đặt mặc định trong R? Nó phải như vậy, như mọi ngôn ngữ khác.


1
Để biết thông tin cơ bản về tùy chọn này, hãy xem stat.ethz.ch/R-manual/R-devel/library/base/html/options.html
R Yoda

1
Tính năng này từng hoạt động nhưng đã bị vô hiệu hóa vì không đáng tin cậy. Tôi nghĩ đó là một nỗ lực để buộc bạn sử dụng RStudio mà cuối cùng sẽ không miễn phí.
Eric Leschinski

6
Tôi nghi ngờ điều đó. R core và RStudio là những tổ chức rất khác nhau, và R core nói riêng là những nguồn mở trung thực.
Ben Bolker

Làm việc trên CentOS 6.9, R-3.4.2
provable_phd_syndrom

Có lẽ điều đáng nói là bạn nên thiết lập các tùy chọn trước khi tìm nguồn cung cấp bất kỳ mã nào.
JAponte

3

Việc chỉ định tùy chọn R chung để xử lý các lỗi không nghiêm trọng đã phù hợp với tôi, cùng với quy trình làm việc tùy chỉnh để giữ lại thông tin về lỗi và kiểm tra thông tin này sau khi lỗi. Tôi hiện đang chạy phiên bản R 3.4.1. Dưới đây, tôi đã bao gồm mô tả về quy trình làm việc phù hợp với tôi, cũng như một số mã tôi đã sử dụng để đặt tùy chọn xử lý lỗi chung trong R.

Như tôi đã định cấu hình, việc xử lý lỗi cũng tạo ra một tệp RData chứa tất cả các đối tượng trong bộ nhớ đang hoạt động tại thời điểm xảy ra lỗi. Kết xuất này có thể được đọc lại thành R bằng cách sử dụng load()và sau đó các môi trường khác nhau như chúng tồn tại tại thời điểm xảy ra lỗi có thể được kiểm tra tương tác bằng cách sử dụng debugger(errorDump).

Tôi sẽ lưu ý rằng tôi có thể lấy số dòng trong traceback()đầu ra từ bất kỳ hàm tùy chỉnh nào trong ngăn xếp, nhưng chỉ khi tôi sử dụng keep.source=TRUEtùy chọn khi gọi source()bất kỳ hàm tùy chỉnh nào được sử dụng trong tập lệnh của tôi. Nếu không có tùy chọn này, việc đặt tùy chọn xử lý lỗi chung như bên dưới đã gửi toàn bộ kết quả đầu ra của tệp traceback()đến một nhật ký lỗi có tên error.log, nhưng số dòng không khả dụng.

Đây là các bước chung mà tôi đã thực hiện trong quy trình làm việc của mình và cách tôi có thể truy cập kết xuất bộ nhớ và nhật ký lỗi sau lỗi R không tương tác.

  1. Tôi đặt phần sau ở đầu tập lệnh chính mà tôi đang gọi từ dòng lệnh. Điều này đặt tùy chọn xử lý lỗi chung cho phiên R. Kịch bản chính của tôi đã được gọi myMainScript.R. Các dòng khác nhau trong mã có các chú thích sau khi chúng mô tả những gì chúng làm. Về cơ bản, với tùy chọn này, khi R gặp lỗi kích hoạt stop(), nó sẽ tạo tệp kết xuất RData (* .rda) của bộ nhớ đang hoạt động trên tất cả các môi trường hoạt động trong thư mục ~/myUsername/directoryForDumpvà cũng sẽ ghi nhật ký lỗi có tên error.logvới một số thông tin hữu ích cho cùng một thư mục. Bạn có thể sửa đổi đoạn mã này để thêm các xử lý khác khi gặp lỗi (ví dụ: thêm dấu thời gian vào tệp kết xuất và tên tệp nhật ký lỗi, v.v.).

    options(error = quote({
      setwd('~/myUsername/directoryForDump'); # Set working directory where you want the dump to go, since dump.frames() doesn't seem to accept absolute file paths.
      dump.frames("errorDump", to.file=TRUE, include.GlobalEnv=TRUE); # First dump to file; this dump is not accessible by the R session.
      sink(file="error.log"); # Specify sink file to redirect all output.
      dump.frames(); # Dump again to be able to retrieve error message and write to error log; this dump is accessible by the R session since not dumped to file.
      cat(attr(last.dump,"error.message")); # Print error message to file, along with simplified stack trace.
      cat('\nTraceback:');
      cat('\n');
      traceback(2); # Print full traceback of function calls with all parameters. The 2 passed to traceback omits the outermost two function calls.
      sink();
      q()}))
  2. Đảm bảo rằng từ tập lệnh chính và bất kỳ lệnh gọi hàm nào tiếp theo, bất cứ khi nào một hàm được lấy nguồn, tùy chọn keep.source=TRUEsẽ được sử dụng. Đó là, để tạo nguồn một hàm, bạn sẽ sử dụng source('~/path/to/myFunction.R', keep.source=TRUE). Điều này là bắt buộc để traceback()đầu ra chứa số dòng. Có vẻ như bạn cũng có thể đặt tùy chọn này trên toàn cầu bằng cách sử dụng options( keep.source=TRUE ), nhưng tôi chưa thử nghiệm tùy chọn này để xem nó có hoạt động hay không. Nếu bạn không cần số dòng, bạn có thể bỏ qua tùy chọn này.

  3. Từ đầu cuối (bên ngoài R), sử dụng tập lệnh chính ở chế độ hàng loạt Rscript myMainScript.R. Điều này bắt đầu một phiên R không tương tác mới và chạy tập lệnh myMainScript.R. Đoạn mã được đưa ra ở bước 1 đã được đặt ở đầu myMainScript.Rthiết lập tùy chọn xử lý lỗi cho phiên R không tương tác.
  4. Gặp lỗi ở đâu đó trong quá trình thực thi myMainScript.R. Điều này có thể nằm trong chính tập lệnh chính hoặc được lồng vào một số hàm sâu. Khi gặp lỗi, việc xử lý sẽ được thực hiện như đã chỉ định ở bước 1 và phiên R sẽ kết thúc.
  5. Một tệp kết xuất RData có tên errorDump.rdavà và nhật ký lỗi có tên error.logđược tạo trong thư mục được chỉ định bởi '~/myUsername/directoryForDump'cài đặt tùy chọn xử lý lỗi chung.
  6. Khi rảnh rỗi, hãy kiểm tra error.logđể xem xét thông tin về lỗi, bao gồm cả thông báo lỗi và dấu vết ngăn xếp đầy đủ dẫn đến lỗi. Đây là một ví dụ về nhật ký được tạo do lỗi; lưu ý các số sau #ký tự là số dòng của lỗi tại các điểm khác nhau trong ngăn xếp cuộc gọi:

    Error in callNonExistFunc() : could not find function "callNonExistFunc"
    Calls: test_multi_commodity_flow_cmd -> getExtendedConfigDF -> extendConfigDF
    
    Traceback:
    3: extendConfigDF(info_df, data_dir = user_dir, dlevel = dlevel) at test_multi_commodity_flow.R#304
    2: getExtendedConfigDF(config_file_path, out_dir, dlevel) at test_multi_commodity_flow.R#352
    1: test_multi_commodity_flow_cmd(config_file_path = config_file_path, 
    spot_file_path = spot_file_path, forward_file_path = forward_file_path, 
    data_dir = "../", user_dir = "Output", sim_type = "spot", 
    sim_scheme = "shape", sim_gran = "hourly", sim_adjust = "raw", 
    nsim = 5, start_date = "2017-07-01", end_date = "2017-12-31", 
    compute_averages = opt$compute_averages, compute_shapes = opt$compute_shapes, 
    overwrite = opt$overwrite, nmonths = opt$nmonths, forward_regime = opt$fregime, 
    ltfv_ratio = opt$ltfv_ratio, method = opt$method, dlevel = 0)
  7. Khi rảnh rỗi, bạn có thể tải errorDump.rdavào phiên R tương tác bằng cách sử dụng load('~/path/to/errorDump.rda'). Sau khi được tải, hãy gọi debugger(errorDump)để duyệt tất cả các đối tượng R trong bộ nhớ trong bất kỳ môi trường hoạt động nào. Xem phần trợ giúp R debugger()để biết thêm thông tin.

Quy trình làm việc này cực kỳ hữu ích khi chạy R trong một số loại môi trường sản xuất nơi bạn có các phiên R không tương tác được khởi chạy tại dòng lệnh và bạn muốn lưu giữ thông tin về các lỗi không mong muốn. Khả năng kết xuất bộ nhớ vào một tệp mà bạn có thể sử dụng để kiểm tra bộ nhớ đang hoạt động tại thời điểm xảy ra lỗi, cùng với việc có số dòng của lỗi trong ngăn xếp cuộc gọi, tạo điều kiện gỡ lỗi nhanh chóng sau khám nghiệm về nguyên nhân gây ra lỗi.


0

Đầu tiên, options(show.error.locations = TRUE)và sau đó traceback(). Số dòng lỗi sẽ được hiển thị sau #

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.