2012-10-29 14 views
22

Ich beobachtete eine andere zwischen einer interaktiven und nicht-Interaktion R-Sitzung über traceback(), die ich nicht verstehe. Für den folgenden Code wird ein Fehler erzeugt, aber in einer interaktiven R-Sitzung kann ich die Traceback-Informationen sehen. Wenn ich den Code unter test.R hinter Rscript test.R oder R -f test.R abspeichere, kann ich den Traceback nicht mehr sehen:traceback() für interaktive und nicht interaktive R-Sitzungen

f = function() { 
    on.exit(traceback()) 
    1 + 'a' 
} 
f() 

In einer interaktiven R Sitzung:

> f = function() { 
+ on.exit(traceback()) 
+ 1 + 'a' 
+ } 
> f() 
Error in 1 + "a" : non-numeric argument to binary operator 
1: f() 

Nicht interaktive Ausführung:

$ Rscript test.R 
Error in 1 + "a" : non-numeric argument to binary operator 
Calls: f 
No traceback available 
Execution halted 

I habe keine Erklärung in ?traceback gesehen, und ich frage mich, ob es eine Möglichkeit gibt, Traceback für nicht interaktive R-Sitzungen zu aktivieren. Vielen Dank!

+0

'traceback' für ein Objekt sieht namens '.traceback' in' basenv() '. Es sieht so aus (aus 'src/main/errors.c'), dass es nur erstellt wird, wenn unter anderem' R_Interactive || haveHandler'. Ohne '.traceback' erhalten Sie die Meldung" Keine Traceback verfügbar ". Es gibt auch eine Warnung unter "Traceback", die "Traceback" erwähnt. – BenBarnes

+0

Wenn Sie in Ihrem Skript nur Optionen (error = traceback) setzen und Ihren on.exit-Aufruf entfernen, haben Sie den gewünschten Effekt. Obwohl es aufgrund des "Schritts" des Fehlers zu einer Duplizierung kommt. –

+0

@BrandonBertelsen, Soweit ich das beurteilen kann, gibt es immer noch keinen Zugriff auf Traceback-Informationen, obwohl der Aufruf-Stack im Falle eines Fehlers in einer nicht-interaktiven Sitzung trotzdem zurückgegeben wird. – BenBarnes

Antwort

20

Mit Standardwerten seiner Argumente sucht traceback() nach einem Objekt mit dem Namen .Traceback im baseenv() für Informationen über den Aufruf-Stack. Es sieht aus (src/main/errors.c) wie .Traceback wird nur erstellt, wenn unter anderem R_Interactive || haveHandler, was darauf hindeutet, dass dieses Objekt nicht in nicht interaktiven Sitzungen erstellt wird. Wenn kein Objekt mit dem Namen .Traceback vorhanden ist, wird die Meldung "Keine Rückverfolgung verfügbar" angezeigt.

Durch die Übergabe eines Nicht-NULL-Werts an das x-Argument von traceback() kann jedoch Informationen über den Aufrufstapel von einer nicht interaktiven Sitzung abgerufen werden. Mit einem von Null verschiedenen ganzzahligen Wert (der die Anzahl der im Stapel zu überspringenden Aufrufe angibt) werden c-level Funktionen (R_GetTraceback) aufgerufen, um den Aufrufstapel zu untersuchen, anstatt in .Traceback zu suchen.

So gibt es ein paar Möglichkeiten, Zurückverfolgungsinformationen in einem nicht-interaktiven Sitzung zu erhalten:

f = function() { 
    on.exit(traceback(1)) 
    1 + 'a' 
} 
f() 

Oder options als Brandon Elsen Einstellung vorschlug

options(error=function()traceback(2)) 

Die unterschiedlichen Werte zu x übergeben die zwei Beispiele berücksichtigen die unterschiedliche Anzahl von zu überspringenden Funktionen.

  1. In dem on.exit Beispiel überspringt traceback(1) den Anruf zu traceback().

  2. In der Beispieleinstellung options gibt es eine zusätzliche anonyme Funktion, die traceback() aufruft, die auch übersprungen werden sollte/könnten.

Im Beispiel im OP, gibt es nicht viel mehr Informationen gewonnen durch traceback() im Vergleich zur automatischen Rückverfolgung im Fall eines Fehlers in einer nicht-interaktiven Sitzung zur Verfügung gestellt werden. Mit Funktionen, die Argumente übernehmen (und übergeben werden), ist die Verwendung von traceback() jedoch viel informativer als die Standardpräsentation des Aufruf-Stacks in der nicht interaktiven Sitzung.

+0

Vielen Dank! Ich habe nicht bemerkt, dass das Setzen von "x" auf eine Nummer auch für nicht interaktive R-Sitzungen funktioniert. –

+4

Beachten Sie, dass die Verwendung von 'options (error = function() traceback (2))' dazu führt, dass Skripts erfolgreich beendet werden, auch wenn ein Fehler auftritt! Eine Lösung ist die Verwendung von 'error = function() {traceback (2); if (! interactive()) quit ("no", status = 1, runLast = FALSE)} '(die hier verwendeten Stoppargumente stammen aus dem [default error behavior] (https://stat.ethz.ch/R -manual/R-devel/Bibliothek/base/html/stop.html)). – dshepherd

2

Es besteht auch die Möglichkeit, Debugging-Informationen zu speichern und später zu laden.(Siehe gute ?debugger Hilfeseiten und Kommentare zum Thema)

über zB:

options(error = quote(dump.frames("testdump", TRUE))) 

...

load("testdump.rda") 
debugger(testdump) 

oder

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