Получите все R-коды, которые запускаются при запуске
Предположим, что у меня есть куча R-кода в script, и я хочу записать весь R-код, который запускается из .GlobalEnv, в плоский файл или базу данных вместе с ошибками и предупреждениями.
Я мог бы написать простую функцию logme следующим образом или сделать ее более сложной, чтобы также получить ошибки, изменив options(error = mylogginfunction)
mylogfile <- tempfile()
logme <- function(x){
mode <- "at"
if(!file.exists(mylogfile)){
mode <- "wt"
}
myconn <- file(mylogfile, mode)
writeLines(x, myconn)
close(myconn)
invisible()
}
logme(sprintf("%s: started some yadayada, ", Sys.time()))
x <- 10
x * 7
logme(sprintf("%s: done with yadayada", Sys.time()))
## Get the log
cat(readLines(mylogfile))
Журнал печатает:
2015-05-14 17:24:31: началось какое-то yadayada, 2015-05-14 17:24:31: сделано с yadayada
Но я бы хотел, чтобы файл журнала записывал выражения, которые были выполнены без необходимости писать обертку вокруг каждого оператора.
Я бы хотел, чтобы журнал выглядел так.
2015-05-14 17:24:31: началось какое-то yadayada, x < - 10, x * 7 2015-05-14 17:24:31: сделано с yadayada
Итак, мой вопрос: как мне получить то, что выполняется R, чтобы я мог хранить выполненные выражения в журнале/базе данных. И без необходимости писать вызов функции перед каждым выражением (как в myhandler (x < - 10); myhandler (x * 10)).
Любая помощь по этому поводу?
Ответы
Ответ 1
Для поиска входных команд вы можете использовать addTaskCallback
mylogfile <- tempfile()
addTaskCallback(
function(...) {
expr <- deparse(as.expression(...)[[1]]) # it could handled better...
cat(expr, file=mylogfile, append=TRUE, sep="\n")
# or cat(sprintf("[%s] %s", Sys.time(), expr),...) if you want timestamps
TRUE
}
,name="logger"
)
x <- 10
x * 7
removeTaskCallback("logger")
Тогда результат:
cat(readLines(mylogfile), sep="\n")
... addTaskCallback definition ...
x <- 10
x * 7
Но вы получаете выражение parsed, что означает, что строка
x+1;b<-7;b==2
будет зарегистрирован как
x + 1
b <- 7
b == 2
Кроме того:
- вывод не будет зарегистрирован, в частности
message
или warning
, показанный на консоли
- в случае
error
запись не будет запущена, поэтому вам потребуется отдельная функция для ее обработки.
Ответ 2
Это, вероятно, просто для работы в каждом случае, но вы можете попробовать:
Определите myhandler как:
myhandler <- function(x, file = stdout()) {
expr <- substitute(x)
for(e_line in as.list(expr)) {
cat( file = file, as.character(Sys.time()), capture.output(e_line), "\n")
eval(e_line, envir = parent.frame())
}
}
Используйте его с кодом внутри скобок:
myhandler({
a <- 1
a <- a + 1
print(a)
})
Результат:
# 2015-05-14 18:46:34 `{`
# 2015-05-14 18:46:34 a <- 1
# 2015-05-14 18:46:34 a <- a + 1
# 2015-05-14 18:46:34 print(a)
# [1] 2
Ответ 3
Я признаюсь, что я действительно не понимаю, что "иметь текущие выражения в том же процессе, что и в случае, когда выполняются команды R", означает, что мы немного поболтали в комментариях. Однако я расширил то, что имел в виду. Вы можете создать файл logGenerator.R
со следующими строками:
logGenerator<-function(sourcefile,log) {
..zz <- file(log, open = "at")
sink(..zz)
sink(..zz, type = "message")
on.exit({
sink(type="message")
sink()
close(..zz)
})
..x<-parse(sourcefile)
for (..i in 1:length(..x)) {
cat(as.character(Sys.time()),"\n")
cat(as.character(..x[..i]),"\n")
..y<-eval(..x[..i])
}
}
Эта функция принимает в качестве аргументов исходный файл и имена файлов журнала. Этот script будет принимать R файл и будет регистрировать время выполнения каждой команды. Затем он записывает выражение в один и тот же файл журнала. Каждый вывод, направленный на stdout()
и сообщения об ошибках, направляется в файл журнала. Вам, очевидно, не нужно каким-либо образом изменять исходный файл.