Title: | Record Everything that Happens in a 'Shiny' Application |
---|---|
Description: | Track and record the use of applications and the user's interactions with 'Shiny' inputs. Allows to trace the inputs with which the user interacts, the outputs generated, as well as the errors displayed in the interface. |
Authors: | Fanny Meyer [aut], Victor Perrier [aut, cre], Silex Technologies [fnd] (https://www.silex-ip.com) |
Maintainer: | Victor Perrier <[email protected]> |
License: | GPL-3 |
Version: | 0.2.1.9000 |
Built: | 2024-11-15 06:11:37 UTC |
Source: | https://github.com/dreamrs/shinylogs |
Read a directory containing JSON logs
read_json_logs(path)
read_json_logs(path)
path |
Path of the directory containing JSON files or a vector of path to JSON files. |
a list
of data.table
# Read all JSON in a directory path_directory <- system.file("extdata/json", package = "shinylogs") logs <- read_json_logs(path = path_directory) # Read a single file single_file <- dir( path = system.file("extdata/json", package = "shinylogs"), full.names = TRUE )[1] logs <- read_json_logs(path = single_file)
# Read all JSON in a directory path_directory <- system.file("extdata/json", package = "shinylogs") logs <- read_json_logs(path = path_directory) # Read a single file single_file <- dir( path = system.file("extdata/json", package = "shinylogs"), full.names = TRUE )[1] logs <- read_json_logs(path = single_file)
Read a directory containing RDS logs
read_rds_logs(path)
read_rds_logs(path)
path |
Path of the directory containing RDS files or a vector of path to RDS files. |
a list
of data.table
## Not run: # Read all RDS in a directory logs <- read_rds_logs(path = "path/to/directory") # Read a single file logs <- read_rds_logs(path = "path/to/log.rds") ## End(Not run)
## Not run: # Read all RDS in a directory logs <- read_rds_logs(path = "path/to/directory") # Read a single file logs <- read_rds_logs(path = "path/to/log.rds") ## End(Not run)
Store logs tracked where you want by providing a custom function to write them in your prefered location.
store_custom(FUN, ...)
store_custom(FUN, ...)
FUN |
A |
... |
Extra parameters that will be passed to |
A list that can be used in track_usage()
.
library(shiny) library(shinylogs) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Just take a look at what is generated track_usage( storage_mode = store_custom(FUN = function(logs) { str(logs, max.level = 3) invisible() }) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
library(shiny) library(shinylogs) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Just take a look at what is generated track_usage( storage_mode = store_custom(FUN = function(logs) { str(logs, max.level = 3) invisible() }) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
All logs will be written in the same file.
store_googledrive(path)
store_googledrive(path)
path |
Path to folder on Drive where to send logs. |
A list that can be used in track_usage()
.
See the gargle package to manage authentication, and especially this vignette from gargle package to manage the process.
## Not run: # In your global, manage Google Drive access drive_auth(path = "/path/to/your/service-account-token.json") # see https://gargle.r-lib.org/articles/articles/managing-tokens-securely.html # to manage your token securely # Then in server, use: track_usage(storage_mode = store_googledrive(path = "my-logs/")) # you may have to share my-logs/ folder with your service account ## End(Not run)
## Not run: # In your global, manage Google Drive access drive_auth(path = "/path/to/your/service-account-token.json") # see https://gargle.r-lib.org/articles/articles/managing-tokens-securely.html # to manage your token securely # Then in server, use: track_usage(storage_mode = store_googledrive(path = "my-logs/")) # you may have to share my-logs/ folder with your service account ## End(Not run)
One JSON will be written for each session of the application.
store_json(path)
store_json(path)
path |
Path where to write JSON files. |
A list that can be used in track_usage()
.
library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store JSON with logs in the temp dir track_usage( storage_mode = store_json(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store JSON with logs in the temp dir track_usage( storage_mode = store_json(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
Doesn't write anything, special inputs created by track_usage()
are available in server and optionally logs are printed in console.
store_null(console = TRUE)
store_null(console = TRUE)
console |
Print logs in R console. |
A list that can be used in track_usage()
.
library(shiny) library(shinylogs) ui <- fluidPage( tags$h2("Record inputs change"), fluidRow( column( width = 3, selectInput( inputId = "select", label = "Select input", choices = month.name ), numericInput( inputId = "numeric", label = "Numerci input", value = 4, min = 0, max = 20 ), checkboxGroupInput( inputId = "checkboxGroup", label = "Checkbox group input", choices = LETTERS[1:5] ), sliderInput( inputId = "slider", label = "Slider input", min = 0, max = 100, value = 50 ) ), column( width = 9, tags$b("Last input:"), verbatimTextOutput(outputId = "last_input"), tags$b("All inputs:"), verbatimTextOutput(outputId = "all_inputs") ) ) ) server <- function(input, output, session) { track_usage( storage_mode = store_null() # dont store on disk ) output$last_input <- renderPrint({ input$.shinylogs_lastInput # last input triggered }) output$all_inputs <- renderPrint({ input$.shinylogs_input # all inputs that have changed }) } if (interactive()) shinyApp(ui, server)
library(shiny) library(shinylogs) ui <- fluidPage( tags$h2("Record inputs change"), fluidRow( column( width = 3, selectInput( inputId = "select", label = "Select input", choices = month.name ), numericInput( inputId = "numeric", label = "Numerci input", value = 4, min = 0, max = 20 ), checkboxGroupInput( inputId = "checkboxGroup", label = "Checkbox group input", choices = LETTERS[1:5] ), sliderInput( inputId = "slider", label = "Slider input", min = 0, max = 100, value = 50 ) ), column( width = 9, tags$b("Last input:"), verbatimTextOutput(outputId = "last_input"), tags$b("All inputs:"), verbatimTextOutput(outputId = "all_inputs") ) ) ) server <- function(input, output, session) { track_usage( storage_mode = store_null() # dont store on disk ) output$last_input <- renderPrint({ input$.shinylogs_lastInput # last input triggered }) output$all_inputs <- renderPrint({ input$.shinylogs_input # all inputs that have changed }) } if (interactive()) shinyApp(ui, server)
One RDS will be written for each session of the application.
store_rds(path)
store_rds(path)
path |
Path where to write RDS files. |
A list that can be used in track_usage()
.
library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classir Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store RDS with logs in the temp dir track_usage( storage_mode = store_rds(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classir Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store RDS with logs in the temp dir track_usage( storage_mode = store_rds(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } if (interactive()) shinyApp(ui, server)
All logs will be written in the same file.
store_sqlite(path)
store_sqlite(path)
path |
Path to the SQLite file or a directory where to create one. |
A list that can be used in track_usage()
.
if (interactive()) { library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classir Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store RDS with logs in the temp dir track_usage( storage_mode = store_sqlite(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } shinyApp(ui, server) }
if (interactive()) { library(shiny) library(shinylogs) # temp directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classir Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store RDS with logs in the temp dir track_usage( storage_mode = store_sqlite(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } shinyApp(ui, server) }
Used in Shiny server
it will record all inputs and
output changes and errors that occurs through an output.
track_usage( storage_mode, what = c("session", "input", "output", "error"), exclude_input_regex = NULL, exclude_input_id = NULL, on_unload = FALSE, app_name = NULL, exclude_users = NULL, get_user = NULL, dependencies = TRUE, session = getDefaultReactiveDomain() )
track_usage( storage_mode, what = c("session", "input", "output", "error"), exclude_input_regex = NULL, exclude_input_id = NULL, on_unload = FALSE, app_name = NULL, exclude_users = NULL, get_user = NULL, dependencies = TRUE, session = getDefaultReactiveDomain() )
storage_mode |
Storage mode to use : |
what |
Elements to record between |
exclude_input_regex |
Regular expression to exclude inputs from tracking. |
exclude_input_id |
Vector of |
on_unload |
Logical, save log when user close the browser window or tab,
if |
app_name |
Name of the app as a character string.
If |
exclude_users |
Character vectors of user for whom it is not necessary to save the log. |
get_user |
A |
dependencies |
Load dependencies in client, can be set to |
session |
The shiny session. |
The following input
s will be accessible in the server:
.shinylogs_lastInput : last input
used by the user
.shinylogs_input : all input
s send from the browser to the server
.shinylogs_error : all errors generated by output
s elements
.shinylogs_output : all output
s generated from the server
.shinylogs_browserData : information about the browser where application is displayed.
# Save logs on disk ---------------------------------- if (interactive()) { # temporary directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store JSON with logs in the temp dir track_usage( storage_mode = store_json(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } shinyApp(ui, server) } # Logs in console & special inputs ------------------------ if (interactive()) { library(shiny) library(shinylogs) ui <- fluidPage( tags$h2("Record inputs change"), fluidRow( column( width = 3, selectInput( inputId = "select", label = "Select input", choices = month.name ), numericInput( inputId = "numeric", label = "Numerci input", value = 4, min = 0, max = 20 ), checkboxGroupInput( inputId = "checkboxGroup", label = "Checkbox group input", choices = LETTERS[1:5] ), sliderInput( inputId = "slider", label = "Slider input", min = 0, max = 100, value = 50 ) ), column( width = 9, tags$b("Last input triggered:"), verbatimTextOutput(outputId = "last_input"), tags$b("All inputs:"), verbatimTextOutput(outputId = "all_inputs") ) ) ) server <- function(input, output, session) { # dont store on disk, just show in R console track_usage( storage_mode = store_null() ) # last input triggered output$last_input <- renderPrint({ input$.shinylogs_lastInput }) # all inputs that have changed output$all_inputs <- renderPrint({ input$.shinylogs_input }) } shinyApp(ui, server) }
# Save logs on disk ---------------------------------- if (interactive()) { # temporary directory for writing logs tmp <- tempdir() # when app stop, # navigate to the directory containing logs onStop(function() { browseURL(url = tmp) }) # Classic Iris clustering with Shiny ui <- fluidPage( headerPanel("Iris k-means clustering"), sidebarLayout( sidebarPanel( selectInput( inputId = "xcol", label = "X Variable", choices = names(iris) ), selectInput( inputId = "ycol", label = "Y Variable", choices = names(iris), selected = names(iris)[[2]] ), numericInput( inputId = "clusters", label = "Cluster count", value = 3, min = 1, max = 9 ) ), mainPanel( plotOutput("plot1") ) ) ) server <- function(input, output, session) { # Store JSON with logs in the temp dir track_usage( storage_mode = store_json(path = tmp) ) # classic server logic selectedData <- reactive({ iris[, c(input$xcol, input$ycol)] }) clusters <- reactive({ kmeans(selectedData(), input$clusters) }) output$plot1 <- renderPlot({ palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) par(mar = c(5.1, 4.1, 0, 1)) plot(selectedData(), col = clusters()$cluster, pch = 20, cex = 3) points(clusters()$centers, pch = 4, cex = 4, lwd = 4) }) } shinyApp(ui, server) } # Logs in console & special inputs ------------------------ if (interactive()) { library(shiny) library(shinylogs) ui <- fluidPage( tags$h2("Record inputs change"), fluidRow( column( width = 3, selectInput( inputId = "select", label = "Select input", choices = month.name ), numericInput( inputId = "numeric", label = "Numerci input", value = 4, min = 0, max = 20 ), checkboxGroupInput( inputId = "checkboxGroup", label = "Checkbox group input", choices = LETTERS[1:5] ), sliderInput( inputId = "slider", label = "Slider input", min = 0, max = 100, value = 50 ) ), column( width = 9, tags$b("Last input triggered:"), verbatimTextOutput(outputId = "last_input"), tags$b("All inputs:"), verbatimTextOutput(outputId = "all_inputs") ) ) ) server <- function(input, output, session) { # dont store on disk, just show in R console track_usage( storage_mode = store_null() ) # last input triggered output$last_input <- renderPrint({ input$.shinylogs_lastInput }) # all inputs that have changed output$all_inputs <- renderPrint({ input$.shinylogs_input }) } shinyApp(ui, server) }
If used in UI of an application,
this will create new input
s available in the server.
Set dependencies = FALSE
in track_usage()
server-side to load dependencies only once.
use_tracking( what = c("session", "input", "output", "error"), exclude_input_regex = NULL, exclude_input_id = NULL, on_unload = FALSE, app_name = NULL )
use_tracking( what = c("session", "input", "output", "error"), exclude_input_regex = NULL, exclude_input_id = NULL, on_unload = FALSE, app_name = NULL )
what |
Elements to record between |
exclude_input_regex |
Regular expression to exclude inputs from tracking. |
exclude_input_id |
Vector of |
on_unload |
Logical, save log when user close the browser window or tab,
if |
app_name |
Name of the app as a character string.
If |
The following input
s will be accessible in the server (according to what is used in record
argument):
.shinylogs_lastInput : last input
used by the user
.shinylogs_input : all input
s send from the browser to the server
.shinylogs_error : all errors generated by output
s elements
.shinylogs_output : all output
s generated from the server
.shinylogs_browserData : information about the browser where application is displayed.
if (interactive()) { library(shiny) library(shinylogs) ui <- fluidPage( # Load tracking dependencies use_tracking(), splitLayout( cellArgs = list(style = "height: 250px"), radioButtons("radio", "Radio:", names(iris)), checkboxGroupInput("checkbox", "Checkbox:", names(iris)), selectInput("select", "Select:", names(iris)) ), tags$p("Last input used, the 'name' slot correspond to inputId:"), verbatimTextOutput("last") ) server <- function(input, output, session) { output$last <- renderPrint({ input$.shinylogs_lastInput }) } shinyApp(ui, server) }
if (interactive()) { library(shiny) library(shinylogs) ui <- fluidPage( # Load tracking dependencies use_tracking(), splitLayout( cellArgs = list(style = "height: 250px"), radioButtons("radio", "Radio:", names(iris)), checkboxGroupInput("checkbox", "Checkbox:", names(iris)), selectInput("select", "Select:", names(iris)) ), tags$p("Last input used, the 'name' slot correspond to inputId:"), verbatimTextOutput("last") ) server <- function(input, output, session) { output$last <- renderPrint({ input$.shinylogs_lastInput }) } shinyApp(ui, server) }