shiny::devmode and writing logs ( sink()?)

Hello all,
I'm often here helping others but the tables have turned and I would benefit from help from the community. :slight_smile:

I would like to understand a best practice way to log a shiny app, so as to track the console, which will also include shiny error traces from shiny::devmode.

Here is a reprex, I have two issues regarding it, but first the code:

library(shiny)
shiny::devmode()
ui <- fluidPage(
  actionButton("simple", "Just to add something normal to the log"),
  actionButton("force_error_button", "Force an Error")
)
close_sink_and_quit <- function(){
  sink(file = NULL,type = "message") 
  sink(file = NULL,type = "output") 
  close(con = flog)
  stopApp()
}

options(error = close_sink_and_quit)
options(shiny.error = close_sink_and_quit)


flog <- file("my_shiny_log", open = "wt")
sink(file = flog, split = TRUE)
sink(file = flog, type = "message")

server <- function(input, output, session) {

  onStop(function() {cat("Session stopped\n") ;close_sink_and_quit()})
  

  observeEvent(input$simple,
               cat("\npressed for",input$simple))

  
  observeEvent(input$force_error_button, {
    stop(paste("Error Forced at ", Sys.time()))
  })
}

shinyApp(ui, server)

if I refrain from pressing my force error button, but hit the simple button a few times,
I happily get the corresponding message in my console, and in "my_shiny_log" file .

if I force an error, although I see a useful stack trace in the console, this is not represented in the "my_shiny_log" file.
i.e.

Warning: Error in <observer:observeEvent(input$force_error_button)>: Error Forced at  2022-07-26 12:43:12
  76: h
  75: .handleSimpleError
  74: stop
  73: <observer:observeEvent(input$force_error_button)> [#11]
  72: valueFunc
  71: ..stacktraceon..
  70: contextFunc

Can anyone advise me of my options here ?
how to get the warning stacktrace to be sinked ? (or some alternative to sink which will have the required effect ?)

Not sure if this is an option for you, but I like using library(callr) / library(processx) for similar scenarios.

An example:

# app.R -------------------------------------------------------------------

library(shiny)

devmode()

ui <- fluidPage(
  actionButton("error", "error")
)

server <- function(input, output, session) {
  observeEvent(input$error, {
    1*"a"
  })
}

shinyApp(ui, server)

# run_app.R ---------------------------------------------------------------

library(shiny)
library(callr)

# ?processx::process
# stderr
# What to do with the standard error. Possible values:
#   
# NULL: discard it.
# 
# A string, redirect it to this file. Note that if you specify a relative path, it will be relative to the current working directory, even if you specify another directory in the wd argument. (See issue 324.)
# 
# "|": create a connection for it.
# 
# "2>&1": redirect it to the same connection (i.e. pipe or file) as stdout. "2>&1" is a way to keep standard output and error correctly interleaved.
# 
# "" (empty string): inherit it from the main R process. If the main R process does not have a standard error stream, e.g. in RGui on Windows, then an error is thrown.

shinyapp_process <- r_bg(function(){
  shiny::runApp(
    appDir = ".",
    port = 80,
    launch.browser = FALSE,
    host = "127.0.0.1"
  )}, supervise = TRUE, stdout = "myshinyapp.log", stderr = "2>&1") # , stdout = "", stderr = "2>&1"

shinyapp_process$is_alive()
shinyapp_process$get_pid()
# shinyapp_process$kill()
2 Likes

Thank you very much for your suggestion , I will be sure to try it and report back.

Furthermore, library(tryCatchLog) might be of interest.

1 Like

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.