R:使用 tryCatchLog 进行错误处理 - 为控制台创建可自定义的结果代码并将详细的回溯写入日志文件
R: Errorhandling with tryCatchLog - create a customizable result code for the console and write a detailled traceback to log file
我的代码包含对不同参数值的多个初始检查。该代码是一个更大项目的一部分,该项目涉及多个 R 脚本以及来自其他环境的调用。如果一个参数值没有通过其中一个检查,我想
- 生成可自定义的结果代码
- 跳过剩余的代码(如果参数错误,无论如何都不会工作)
- 使用抛出错误的行创建一个日志条目(它告诉我参数未通过哪个测试)
- 将我的自定义结果代码打印到控制台(没有更详细的解释/从错误中追溯)
否则,剩下的代码应该是运行。如果还有其他错误(不是我抛出的),我还需要一个错误处理来生成可自定义的一般结果代码(表示有错误,但不是我抛出的)和更详细的日志。
结果代码是与更大环境通信的一部分,只是区分错误的参数值(即我抛出的错误)和其他内部问题(脚本稍后可能发生)。
我想使用 tryCatchLog 因为它允许我记录详细的回溯,包括脚本名称(我正在采购我自己的代码)和行号。然而,我还没有想出如何生成我自己的错误代码(目前我正在通过基本函数 stop() 执行此操作)并使用 tryCatchLog 传递它(同时还写日志)。
例子
在以下示例中,我的 parameter_check() 通过 stop() 抛出错误,结果代码为“400”。使用 tryCatchLog 我可以捕获错误并获得包含回溯的详细错误消息。但是,我想分开我自己的错误代码(只是“400”),它应该打印到控制台,以及更详细的错误消息,它应该进入日志文件。
library(tryCatchLog)
parameter_check <- function(error) {
if (error){
stop("400")
print("This line should not appear")
}
}
print("Beginning")
tryCatchLog(parameter_check(error = TRUE),
error = function(e) {print(e)}
)
print("End")
目前,结果是:
[1] "Beginn"
ERROR [2021-12-08 11:43:38] 400
Compact call stack:
1 tryCatchLog(parameter_check(0), error = function(e) {
2 #3: stop("400")
Full call stack:
1 tryCatchLog(parameter_check(0), error = function(e) {
print(e)
2 tryCatch(withCallingHandlers(expr, condition =
cond.handler), ..., finall
3 tryCatchList(expr, classes, parentenv, handlers)
4 tryCatchOne(expr, names, parentenv, handlers[[1]])
5 doTryCatch(return(expr), name, parentenv, handler)
6 withCallingHandlers(expr, condition = cond.handler)
7 parameter_check(0)
8 #3: stop("400")
9 .handleSimpleError(function (c)
{
if (inherits(c, "condition")
<simpleError in parameter_check(0): 400>
我想获得自己的结果代码(“400”),以便在将完整的错误消息记录到文件中时将其打印到控制台。有没有不用写代码解析错误信息等的方法呢?
使用 tryCatch 的解决方案
根据 R Yoda and this answers 的提示,这是一个使用 tryCatch 和调用处理程序的解决方案。
### Parameters
log_file_location <- "./logs/log.txt"
### Defining functions
parameter_check_1 <- function(error) {
if (error){
stop("400")
}
}
parameter_check_2 <- function(error) {
if (error){
stop("400")
}
}
write_to_log <- function(file_location, message) {
if (file.exists(file_location))
{write(message, file_location, append = TRUE)}
else
{write(message, file_location, append = FALSE)}
}
parameter_check <- function(){
print("Beginning of parameter check")
print("First check")
parameter_check_1(error = TRUE)
print("Second check")
parameter_check_2(error = FALSE)
print("End of parameter check")
}
main<- function() {
print("Beginning of main function")
log(-1) # throws warning
log("error") # throws error
print("End of main function")
}
### Setting parameters
result_code_no_error <- "200"
result_code_bad_request <- "400"
result_code_internal_error <- "500"
# initial value for result_code
result_code <- result_code_no_error
print("Beginning of program")
### Execute parameter check with tryCatch and calling handlers
# Error in parameter checking functions should result in result_code_bad_request
tryCatch(withCallingHandlers(parameter_check(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_bad_request
}
)
### Execute main section with tryCatch and calling handlers
# Error in main section should result in result_code_internal_error
# main section should only be excecuted if there is no error (internal or bad request) in the previous section
if (result_code == result_code_no_error) {
tryCatch(withCallingHandlers(main(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_internal_error
}
)
}
print("End of program")
print(result_code)
如 vignette for tryCatchLog 中所述,这样做的缺点是无法记录错误的准确位置。我没有传递来自 stop("400") 的错误消息,因为现在所有参数检查函数都在一个函数调用中,但这可以使用 condition$message.
解决方案是(完全独立于使用 tryCatchLog
或标准 R tryCatch
):
...
error = function(e) {print(e$message)}
..
背景(R 错误如何工作):它们创建类型(错误)condition
:
的对象
e <- simpleError("400") # same "condition" object as created by stop("400")
str(e)
# List of 2
# $ message: chr "400"
# $ call : NULL
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
print(e$message)
[1] "400"
我的代码包含对不同参数值的多个初始检查。该代码是一个更大项目的一部分,该项目涉及多个 R 脚本以及来自其他环境的调用。如果一个参数值没有通过其中一个检查,我想
- 生成可自定义的结果代码
- 跳过剩余的代码(如果参数错误,无论如何都不会工作)
- 使用抛出错误的行创建一个日志条目(它告诉我参数未通过哪个测试)
- 将我的自定义结果代码打印到控制台(没有更详细的解释/从错误中追溯)
否则,剩下的代码应该是运行。如果还有其他错误(不是我抛出的),我还需要一个错误处理来生成可自定义的一般结果代码(表示有错误,但不是我抛出的)和更详细的日志。
结果代码是与更大环境通信的一部分,只是区分错误的参数值(即我抛出的错误)和其他内部问题(脚本稍后可能发生)。
我想使用 tryCatchLog 因为它允许我记录详细的回溯,包括脚本名称(我正在采购我自己的代码)和行号。然而,我还没有想出如何生成我自己的错误代码(目前我正在通过基本函数 stop() 执行此操作)并使用 tryCatchLog 传递它(同时还写日志)。
例子
在以下示例中,我的 parameter_check() 通过 stop() 抛出错误,结果代码为“400”。使用 tryCatchLog 我可以捕获错误并获得包含回溯的详细错误消息。但是,我想分开我自己的错误代码(只是“400”),它应该打印到控制台,以及更详细的错误消息,它应该进入日志文件。
library(tryCatchLog)
parameter_check <- function(error) {
if (error){
stop("400")
print("This line should not appear")
}
}
print("Beginning")
tryCatchLog(parameter_check(error = TRUE),
error = function(e) {print(e)}
)
print("End")
目前,结果是:
[1] "Beginn" ERROR [2021-12-08 11:43:38] 400 Compact call stack: 1 tryCatchLog(parameter_check(0), error = function(e) { 2 #3: stop("400") Full call stack: 1 tryCatchLog(parameter_check(0), error = function(e) { print(e) 2 tryCatch(withCallingHandlers(expr, condition =
cond.handler), ..., finall 3 tryCatchList(expr, classes, parentenv, handlers) 4 tryCatchOne(expr, names, parentenv, handlers[[1]]) 5 doTryCatch(return(expr), name, parentenv, handler) 6 withCallingHandlers(expr, condition = cond.handler) 7 parameter_check(0) 8 #3: stop("400") 9 .handleSimpleError(function (c) { if (inherits(c, "condition") <simpleError in parameter_check(0): 400>
我想获得自己的结果代码(“400”),以便在将完整的错误消息记录到文件中时将其打印到控制台。有没有不用写代码解析错误信息等的方法呢?
使用 tryCatch 的解决方案
根据 R Yoda and this answers 的提示,这是一个使用 tryCatch 和调用处理程序的解决方案。
### Parameters
log_file_location <- "./logs/log.txt"
### Defining functions
parameter_check_1 <- function(error) {
if (error){
stop("400")
}
}
parameter_check_2 <- function(error) {
if (error){
stop("400")
}
}
write_to_log <- function(file_location, message) {
if (file.exists(file_location))
{write(message, file_location, append = TRUE)}
else
{write(message, file_location, append = FALSE)}
}
parameter_check <- function(){
print("Beginning of parameter check")
print("First check")
parameter_check_1(error = TRUE)
print("Second check")
parameter_check_2(error = FALSE)
print("End of parameter check")
}
main<- function() {
print("Beginning of main function")
log(-1) # throws warning
log("error") # throws error
print("End of main function")
}
### Setting parameters
result_code_no_error <- "200"
result_code_bad_request <- "400"
result_code_internal_error <- "500"
# initial value for result_code
result_code <- result_code_no_error
print("Beginning of program")
### Execute parameter check with tryCatch and calling handlers
# Error in parameter checking functions should result in result_code_bad_request
tryCatch(withCallingHandlers(parameter_check(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_bad_request
}
)
### Execute main section with tryCatch and calling handlers
# Error in main section should result in result_code_internal_error
# main section should only be excecuted if there is no error (internal or bad request) in the previous section
if (result_code == result_code_no_error) {
tryCatch(withCallingHandlers(main(),
error = function(condition){},
warning = function(condition){
write_to_log(log_file_location, condition$message)
invokeRestart("muffleWarning")
}
),
error = function(condition) {
write_to_log(log_file_location, condition$message)
result_code <<- result_code_internal_error
}
)
}
print("End of program")
print(result_code)
如 vignette for tryCatchLog 中所述,这样做的缺点是无法记录错误的准确位置。我没有传递来自 stop("400") 的错误消息,因为现在所有参数检查函数都在一个函数调用中,但这可以使用 condition$message.
解决方案是(完全独立于使用 tryCatchLog
或标准 R tryCatch
):
...
error = function(e) {print(e$message)}
..
背景(R 错误如何工作):它们创建类型(错误)condition
:
e <- simpleError("400") # same "condition" object as created by stop("400")
str(e)
# List of 2
# $ message: chr "400"
# $ call : NULL
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
print(e$message)
[1] "400"