r-devel / r-project-sprint-2023

Material for the R project sprint
https://contributor.r-project.org/r-project-sprint-2023/
17 stars 3 forks source link

R Session Logging #77

Open hturner opened 1 year ago

hturner commented 1 year ago

When a person uses a screenreader with the Windows GUI or the terminal (presumably also macOS GUI), they can only read what can be viewed within the console window. While they can page up and down, it is not easy to navigate the output.

This motivates the wish to create a log of the R session - both input and output - that could be viewed in a text editor or browser, allowing the user to rely on general accessibility support (e.g. better screen reader navigation, browser extensions that change the font or colours, zoom, etc). It would also provide additional tools such as search, without requiring the user to install and become familiar with an IDE. (While tools like R markdown could be used for the same end result, this issue is motivated by new R users that are using R very interactively).

There are a couple of ways this might be implemented:

eliocamp commented 1 year ago

I got my hands dirty on this one and created a possible minimal prototype using addTaskCallback() to create an automatic logger. Putting this on your .Rprofile and setting the LOG_FILE_PREFIX environmental variable will automatically every expression and result into a log file with the time and date of the start of the session in the name.

log_file_prefix <- Sys.getenv("LOG_FILE_PREFIX", unset = "")

if (interactive() & log_file_prefix != "") {
  file <- paste0(log_file_prefix, format(Sys.time()), ".txt")
  addTaskCallback(function(expr, value, ok, visible, data) {
    write(paste0("> ", capture.output(print(expr))), data(), append = TRUE)
    write(capture.output(print(value)), data(), append = TRUE)
    TRUE
  }, data = \() file.path(getwd(), file)
  )
}

rm(log_file_prefix)

One thing to note about this is that the logfile actually "follows" the current working directory. This is just a POC that this can be done, but I don't know if it's the most desired behaviour. A more complete implementation might make this configurable in some way, either with environmental variables or by running functions interactively. Of note, I'm not sure if this could lead to slightly reduced performance as the results are printed twice (once in the console and once for the log file). It shouldn't be a big hit unless the print method is particularly onerous.

In any case, it would be great if Jonathan kicked in the tires a bit so we can iterate.

daroczig commented 1 year ago

I've just heard about this project at the morning kickoff, and it reminded me that @nfultz has implemented something very similar at https://github.com/nfultz/stlogging -- I hope there might be a good fit/collaboration.

deepayan commented 1 year ago

I haven't looked at stlogging, but a couple of things to watch out for in Elio's suggestion:

z = rnorm(10)

will actually print z even though it's an assignment. This may not be desirable.

Also, errors / warnings are not captured.

ajrgodfrey commented 1 year ago

First impressions…

Looks like we solve ¾ problems.

  1. Very proactive user: always logs sessions
  2. Semi proactive user: decides to diarise upcoming work.
  3. Reactive user who wants the outcome of the last command issued
  4. NOT the user who wants to grab the entire session.

¾ si great 😊

USE: User must create log_file_prefix via .Rprofile or .Renviron

creates constantly updating log file(s)s which appends output; a change of owrking directory creates a new log file with the same filename as the one started when opening a new R session.

log_file_prefix <- Sys.getenv("LOG_FILE_PREFIX", unset = "")

must be actively set ot have an impact

need to watch happenings in Rmd file rendering while in an interactive setting

if (interactive() & log_file_prefix != "") { file <- paste0(log_file_prefix, format(Sys.time()), ".txt")

fix spaces in filenames

addTaskCallback(function(expr, value, ok, visible, data) { write(paste0("> ", capture.output(print(expr))), data(), append = TRUE) write(capture.output(print(value)), data(), append = TRUE)

replace with cat(paste0(..., collapse="\n"), file=..., append=TRUE)

return(invisible( TRUE))

}, data = () file.path(getwd(), file) ) }

rm(log_file_prefix)

good to have but perhaps hide as well with leading . on variable names

if we want diaryOn() and diaryOff() what do we do?

need to extract multiple purpose functions from above.

diaryOn() needs to make new filename so filename creation is another internal function to pull out

diaryOn() is proactive

can we make a grabLast() command that dumps the function call and its evaluation into a file in a reactive context.

ltierney commented 1 year ago

A couple of other things to keep an eye on if you haven't already:

On Thu, 31 Aug 2023, Deepayan Sarkar wrote:

I haven't looked at stlogging, but a couple of things to watch out for in Elio's suggestion:

z = rnorm(10)

will actually print z even though it's an assignment. This may not be desirable.

Also, errors / warnings are not captured.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to thisthread.[AA55UVHA2BV6MVC4ODIGEOLXYBLYDA5CNFSM6AAAAAA4FPANKCWGG33NNVSW45C7OR4 XAZNMJFZXG5LFINXW23LFNZ2KUY3PNVWWK3TUL5UWJTTFL24CW.gif] Message ID: @.***>

-- Luke Tierney Ralph E. Wareham Professor of Mathematical Sciences University of Iowa Phone: 319-335-3386 Department of Statistics and Fax: 319-335-3017 Actuarial Science 241 Schaeffer Hall email: @.*** Iowa City, IA 52242 WWW: http://www.stat.uiowa.edu --0-2984904-1693479316=:2392--

nfultz commented 1 year ago

I left a couple other notes / known issues with trying to use task callbacks for this use case on my projects' readme - notably it ignores any expression that fails. In the vignette on tasks from early 2000s, it sounds like a more complete task system was planned but never finished.

I think it would be worth thinking about whether implementing "session logging" makes more sense as user code in R, which might require changes to the task system and sink(), or directly in the application in C (like the debugger is).

ajrgodfrey commented 1 year ago

A working solution has been incorporated into the BrailleR package The script file you want is called Callback.R There are two (exported) functions for users, and then a bunch of (internalised) workhorse functions below these.

The desired result for my use case is very close to completion. If other use cases become apparent, then the workhorse functions are able to be lifted and shifted elsewhere.

I still need to ensure the logging is only done in interactive sessions, and some paranoia-checking across platforms should be done once I find a (blind) Mac user. The former is a fairly trivial adjustment while the latter feels low risk so is a low priority at the moment. I will share the outcome of this work and the other outcomes of the R Project Sprint with the Blind RUG sometime this month.