Określono globalną opcję R do obsługi błędów niekrytycznych dla mnie, wraz z niestandardowym przepływem pracy dla zachowania informacji o błędzie i sprawdzeniu tych informacji po awarii. Aktualnie korzystam z wersji R 3.4.1. Poniżej zamieściłem opis przepływu pracy, który działał dla mnie, a także kod, który ustawiłem opcję globalnej obsługi błędów w R.
Jak już skonfigurowałem, obsługa błędów tworzy również Plik RData zawierający wszystkie obiekty w pamięci roboczej w momencie wystąpienia błędu.Ten zrzut można odczytywać z powrotem do R za pomocą load()
, a następnie różne środowiska, które istniały w momencie wystąpienia błędu, można kontrolować interaktywnie za pomocą debugger(errorDump)
.
będę pamiętać, że udało mi się uzyskać numery linii w traceback()
wyjściu z jakichkolwiek funkcji niestandardowych w stosie, ale tylko wtedy, gdy użyłem opcji keep.source=TRUE
Dzwoniąc source()
dla wszelkich niestandardowych funkcji wykorzystywanych w moim skrypcie. Bez tej opcji ustawienie opcji globalnej obsługi błędów, jak poniżej, wysłało pełne wyjście traceback()
do dziennika błędów o nazwie error.log
, ale numery linii nie były dostępne.
Oto ogólne kroki, które podjąłem w moim obiegu pracy i jak mogłem uzyskać dostęp do zrzutu pamięci i dziennika błędów po nieinteraktywnym niepowodzeniu R.
W górnej części skryptu głównego, który wywoływałam z wiersza poleceń, umieściłem następujący kod: Ustawia globalną opcję obsługi błędów dla sesji R. Mój główny skrypt nazywa się myMainScript.R
. Poszczególne wiersze w kodzie mają komentarze po tym, jak opisują, co robią. Zasadniczo, przy tej opcji, gdy R napotka błąd, który wyzwala stop()
, utworzy plik zrzutu RData (* .rda) pamięci roboczej we wszystkich aktywnych środowiskach w katalogu ~/myUsername/directoryForDump
i zapisze również dziennik błędów o nazwie error.log
z pewnymi przydatnymi informacje do tego samego katalogu. Możesz zmodyfikować ten fragment, aby dodać inne sposoby obsługi po błędzie (np. Dodać sygnaturę czasową do plików zrzutu i nazw plików dziennika błędów itp.).
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()}))
Upewnij się, że z głównego scenariusza i wszystkich kolejnych wywołań funkcji, w dowolnym momencie funkcja jest pozyskiwane, opcja keep.source=TRUE
służy. Oznacza to, że do źródła funkcji użyłbyś source('~/path/to/myFunction.R', keep.source=TRUE)
. Jest to wymagane, aby dane wyjściowe traceback()
zawierały numery linii. Wygląda na to, że możesz również ustawić tę opcję globalnie, używając options(keep.source=TRUE)
, ale nie testowałem tego, aby sprawdzić, czy działa. Jeśli nie potrzebujesz numerów linii, możesz pominąć tę opcję.
- Z terminalu (poza R) wywołaj główny skrypt w trybie wsadowym, używając
Rscript myMainScript.R
. Spowoduje to uruchomienie nowej nieinteraktywnej sesji R i uruchomi skrypt myMainScript.R
. Fragment kodu podany w kroku 1, który został umieszczony na górze myMainScript.R
, ustawia opcję obsługi błędów dla nieinteraktywnej sesji R.
- Napotkać błąd w trakcie wykonywania
myMainScript.R
. Może to być główny skrypt lub zagnieżdżone kilka funkcji. Po napotkaniu błędu obsługa zostanie wykonana zgodnie z opisem w kroku 1, a sesja R zostanie zakończona.
- Plik zrzutu RData o nazwie
errorDump.rda
i dziennik błędów o nazwie error.log
są tworzone w katalogu określonym przez '~/myUsername/directoryForDump'
w ustawieniu globalnej opcji obsługi błędów.
W czasie wolnym przejrzyj error.log
, aby przejrzeć informacje o błędzie, w tym sam komunikat o błędzie i pełny ślad stosu prowadzący do błędu. Oto przykład dziennika wygenerowanego w wyniku błędu; Uwaga numery po znaku #
są numery linii błędu w różnych punktach w stos wywołań:
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)
w swoim czasie wolnym, można załadować errorDump.rda
w sesji interaktywnej R używając load('~/path/to/errorDump.rda')
. Po załadowaniu, zadzwoń pod numer debugger(errorDump)
, aby przeglądać wszystkie obiekty R w pamięci w dowolnym z aktywnych środowisk. Aby uzyskać więcej informacji, zobacz pomoc R na stronie debugger()
.
Ten przepływ pracy jest niezwykle pomocne podczas uruchamiania R w pewnego rodzaju środowisku produkcyjnym, gdzie trzeba non-interaktywne sesje R są inicjowane w linii poleceń i chcesz zachowane informacje o nieoczekiwanych błędów. Możliwość zrzucenia pamięci do pliku, którego można użyć do sprawdzenia pamięci roboczej w momencie wystąpienia błędu, wraz z numerem linii błędu w stosie wywołań, ułatwia szybkie, pośmiertne debugowanie przyczyny błędu.
Jakieś aktualizacje? Cztery cztery lata później, wydaje się, że problem nadal występuje, pomimo całego popularnego przyjęcia R. –
Mam również bardzo długi skrypt R z dużą ilością małych wydruków, chcę wydrukować (podkreślenie) (podkreślenie) LINE/FILE (podkreślenie) (podkreślenie) (numery wierszy i nazwa skryptu), takie jak w C, zamiast kodów kreskowych w źródle. – mosh
Nie wiem, czy R wewnętrznie naprawdę ma pojęcie "numerów linii". Jednak ma on pojęcie kompletnych zadań, tj. Zadań na najwyższym poziomie. Można na przykład łatwo zdefiniować procedurę obsługi zadania, aby określić, które zadanie najwyższego poziomu nie powiodło się. Oczywiście nie jest to wielka pociecha dla osób z dużymi sieciami lub dużymi oświadczeniami warunkowymi. – russellpierce