2009-09-18 11 views
78

Si estoy ejecutando un largo guión R desde la línea de comandos (R --slave script.R), ¿cómo puedo obtener los números de línea en los errores?R ¿Números de línea de scripts al error?

no quiero añadir comandos de depuración a la secuencia de comandos si es posible - sólo quiero R comportarse como la mayoría de otros lenguajes de script ...

+20

¿Alguna actualización? Cuatro 4 años más tarde, parece que el problema persiste, a pesar de la adopción generalizada de R. –

+0

También tengo un guión R muy largo con muchos pequeños resultados, quiero imprimir (subrayado) (guión bajo) LINE/FILE (guión bajo) (guión bajo) (números de línea y nombre del guión) como el de C, en lugar de codificar números de línea en el código fuente. – mosh

+0

No sé si R internamente realmente tiene una noción de 'números de línea'. Sin embargo, tiene una noción de tareas completas, es decir, tareas de nivel superior. Uno podría, por ejemplo, definir fácilmente un manejador de tareas para decirle a uno qué tarea de nivel superior falló. Por supuesto, eso no es una gran comodidad para aquellos con cadenas grandes o grandes declaraciones condicionales. – russellpierce

Respuesta

33

Esto no le dará el número de línea, pero le dirá si la falta ocurre en la pila de llamadas que es muy útil:

traceback() 

[Editar:] Cuando se ejecuta un script desde la línea de comandos que tendrá que saltar una o dos llamadas, ver traceback() for interactive and non-interactive R sessions

No estoy al tanto de otra manera de hacer esto sin los sospechosos habituales de depuración:

  1. de depuración()
  2. navegador()
  3. opciones (error = recuperarse) [seguido de opciones (error = NULL) para revertirla]

You might want to look at this related post.

[Editar:] lo sentimos ... acaba de ver que se está ejecutando esto desde la línea de comandos. En ese caso, sugeriría trabajar con la funcionalidad de opciones (error). Aquí está un ejemplo sencillo:

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

Se puede crear un guión tan elaborado como desee en una condición de error, por lo que sólo debe decidir qué información necesita para la depuración.

De lo contrario, si hay áreas específicas que le preocupan (por ejemplo, conectarse a una base de datos), envuélvalas en una función tryCatch().

10

El soporte para esto estará disponible en R 2.10 y posterior. Duncan Murdoch acaba de publicar a r-devel el 10 sep 2009 Sobre findLineNum and setBreapoint:

I've just added a couple of functions to R-devel to help with 
debugging. findLineNum() finds which line of which function corresponds 
to a particular line of source code; setBreakpoint() takes the output of 
findLineNum, and calls trace() to set a breakpoint there. 

These rely on having source reference debug information in the code. 
This is the default for code read by source(), but not for packages. To 
get the source references in package code, set the environment variable 
R_KEEP_PKG_SOURCE=yes, or within R, set options(keep.source.pkgs=TRUE), 
then install the package from source code. Read ?findLineNum for 
details on how to 
tell it to search within packages, rather than limiting the search to 
the global environment. 

For example, 

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=) 

This will print 

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

and you can use 

setBreakpoint("<text>#3") 

to set a breakpoint there. 

There are still some limitations (and probably bugs) in the code; I'll 
be fixing thos 
+0

Hay una fuente diaria de r-devel (y binarios para Windoze) ... –

+0

Gracias. Acaba de registrarse para la lista de correo r-devel también. He estado evitando la ayuda de r en la suposición de que bloquearía mi bandeja de entrada (r-sig-finance ya lo hace). – Shane

+1

realmente no entiendo cómo funciona esto desde la línea de comandos sin hurgar en el guión R –

10

Haciendo options(error=traceback) proporciona un poco más de información sobre el contenido de las líneas que conducen al error. Hace que aparezca un traceback si hay un error, y para algunos errores tiene el número de línea, con el prefijo #. Pero es impredecible, muchos errores no obtendrán números de línea.

+0

No funciona para mí. Solo tengo un archivo y no muestra el número de línea, solo dice 'No hay rastreo disponible 'después del error. –

+0

@MarkLakata tenga en cuenta que esta es una respuesta de 2012, que es hace 5 años ... –

0

Lo hace mediante el establecimiento de

options(show.error.locations = TRUE) 

Me pregunto por qué este ajuste no es un defecto en R? Debería ser, como lo es en cualquier otro idioma.

+1

Para obtener información de antecedentes sobre esta opción, consulte https://stat.ethz.ch/R-manual/R-devel/library/base /html/options.html –

+0

Esto solía funcionar, pero estaba deshabilitado porque no es confiable. Creo que es un intento de forzarte a usar el RStudio, que eventualmente no será gratuito. –

+6

lo dudo. R core y RStudio son organizaciones muy diferentes, y R core en particular son firmes proveedores de código abierto. –

1

Especificar la opción R global para el manejo de errores no catastróficos funcionó para mí, junto con un flujo de trabajo personalizado para retener información sobre el error y examinar esta información después de la falla. Actualmente estoy ejecutando R versión 3.4.1. A continuación, he incluido una descripción del flujo de trabajo que me funcionó, así como algún código que utilicé para establecer la opción de manejo de errores global en R.

Como lo tengo configurado, el manejo de errores también crea una RData archivo que contiene todos los objetos en la memoria de trabajo en el momento del error.Esta basura puede ser leído de nuevo en R utilizando load() y luego los diversos entornos que existían en el momento del error pueden ser inspeccionados de forma interactiva utilizando debugger(errorDump).

me cuenta que yo era capaz de obtener los números de línea en el traceback() salida de cualquiera de las funciones personalizadas dentro de la pila, pero sólo si utiliza la opción keep.source=TRUE al llamar source() de las funciones personalizadas se utilizan en mi guión. Sin esta opción, la configuración de la opción de manejo de errores global de la siguiente manera envió la salida completa del traceback() a un registro de errores llamado error.log, pero los números de línea no estaban disponibles.

Aquí están los pasos generales que tomé en mi flujo de trabajo y la forma en que era capaz de acceder al volcado de memoria y registro de errores después de un fallo R no interactivo.

  1. puse lo siguiente en la parte superior de la secuencia de comandos principal que estaba llamando desde la línea de comandos. Esto establece la opción de manejo de error global para la sesión R. Mi guion principal se llamaba myMainScript.R. Las diversas líneas en el código tienen comentarios después de ellos que describen lo que hacen. Básicamente, con esta opción, cuando R encuentra un error que provoca stop(), se creará un rdata (* .rda) archivo de volcado de memoria de trabajo en todos los entornos activos en el directorio ~/myUsername/directoryForDump y también escribirá un registro de errores llamado error.log con algún útil información al mismo directorio. Puede modificar este fragmento para agregar otro tratamiento en caso de error (por ejemplo, agregar una marca de tiempo al archivo de volcado y nombres de archivo de registro de errores, etc.).

    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. Asegúrese de que a partir de la secuencia de comandos principal y las llamadas a funciones siguientes, en cualquier momento una función se obtiene, se usa la opción keep.source=TRUE. Es decir, para generar una función, usaría source('~/path/to/myFunction.R', keep.source=TRUE). Esto es necesario para que la salida traceback() contenga números de línea. Parece que también puede establecer esta opción globalmente usando options(keep.source=TRUE), pero no he probado esto para ver si funciona. Si no necesita números de línea, puede omitir esta opción.

  3. Desde la terminal (fuera de R), llame a la secuencia de comandos principal en el modo por lotes utilizando Rscript myMainScript.R. Esto inicia una nueva sesión R no interactiva y ejecuta el script myMainScript.R. El fragmento de código dado en el paso 1 que se ha colocado en la parte superior de myMainScript.R establece la opción de manejo de errores para la sesión R no interactiva.
  4. se produzca un error en algún lugar dentro de la ejecución de myMainScript.R. Esto puede estar en el script principal en sí mismo o anidado varias funciones en profundidad. Cuando se encuentra el error, el manejo se realizará como se especifica en el paso 1, y la sesión R terminará.
  5. Se ha creado un archivo de volcado de RData llamado errorDump.rda y un registro de errores llamado error.log en el directorio especificado por '~/myUsername/directoryForDump' en la configuración de opción de manejo de errores global.
  6. En su tiempo libre, inspeccione error.log para revisar la información sobre el error, incluyendo el mensaje de error en sí y la traza completa que conduce al error. Aquí hay un ejemplo del registro que se genera por error; en cuenta los números después del carácter # son los números de línea del error en varios puntos de la pila de llamadas:

    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. En su tiempo libre, se puede cargar errorDump.rda en una sesión interactiva usando R load('~/path/to/errorDump.rda'). Una vez cargado, llame al debugger(errorDump) para buscar todos los objetos R en la memoria en cualquiera de los entornos activos. Consulte la ayuda de R en debugger() para obtener más información.

Este flujo de trabajo es de gran ayuda cuando se ejecuta R en algún tipo de entorno de producción donde hay sesiones R no interactivos que se inician en la línea de comandos y que quieren que la información retenida sobre los errores inesperados. La capacidad de volcar la memoria a un archivo que puede usar para inspeccionar la memoria operativa en el momento del error, junto con los números de línea del error en la pila de llamadas, facilita la depuración rápida post mortem de lo que causó el error.

Cuestiones relacionadas