将shinylogs生成的日志上传至WebDAV服务器的问题求助
问题:shinylogs日志无法上传至WebDAV服务器
我们在shinyapps.io上运行多个教育用途的Shiny应用,使用shinylogs包追踪应用使用情况,本地测试shinylogs功能正常。但尝试将shinylogs生成的日志上传至WebDAV服务器时,无报错但日志始终无法上传。
已实现单个文件上传及封装函数(运行正常):
username <- "xxx" password <- "yyy" # 单个文件上传测试 file <- upload_file("test.txt") PUT("https://fernuni-hagen.sciebo.de/public.php/webdav/test.txt", authenticate(username, password), body = file) # 封装上传函数 upload <- function(filename){ body <- upload_file(filename) PUT(paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", filename), authenticate(username, password), body = body) } upload("test.txt")
但结合shinylogs的track_usage时失败,演示应用代码如下:
library(shiny) library(shinylogs) library(httr) ui <- fluidPage( titlePanel("Old Faithful Geyser Data"), fluidRow( sidebarLayout( sidebarPanel( sliderInput("bins1", "Number of bins:", min = 1, max = 50, value = 30)), mainPanel(plotOutput("distPlot1")))), fluidRow( sidebarLayout( sidebarPanel( sliderInput("bins2", "Number of bins:", min = 1, max = 50, value = 30), actionButton("go", "Update Plot")), mainPanel(plotOutput("distPlot2")))) ) server <- function(input, output) { username <- "xxx" password <- "yyy" track_usage(storage_mode = store_custom(FUN = function(logs){ body <- upload_file(logs) url <- paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", logs) PUT(url, authenticate(username, password), body = body) })) output$distPlot1 <- renderPlot({ x <- faithful[, 2] bins <- seq(min(x), max(x), length.out = input$bins1 + 1) hist(x, breaks = bins, col = 'darkgray', border = 'white') }) output$distPlot2 <- renderPlot({ input$go x <- faithful[, 2] bins <- seq(min(x), max(x), length.out = isolate(input$bins2) + 1) hist(x, breaks = bins, col = 'darkgray', border = 'white') }) } shinyApp(ui = ui, server = server)
问题根源
store_custom传入的FUN函数参数logs是日志数据的data.frame对象,而非本地文件路径字符串。直接使用upload_file(logs)会失效,因为upload_file要求传入的是文件路径,不是数据框。
修正方案
需要先将logs数据框写入临时文件,再上传该文件,上传完成后可删除临时文件避免占用空间。使用tempfile()生成安全的临时文件路径,适配shinyapps.io的文件系统权限:
server <- function(input, output) { username <- "xxx" password <- "yyy" track_usage(storage_mode = store_custom(FUN = function(logs){ # 生成临时文件路径,格式为csv(也可换为其他格式) temp_log_file <- tempfile(fileext = ".csv") # 将日志数据框写入临时文件 write.csv(logs, temp_log_file, row.names = FALSE) # 构造WebDAV上传路径(加时间戳避免文件覆盖) upload_filename <- paste0("shiny_log_", gsub("[^0-9]", "", Sys.time()), ".csv") upload_url <- paste0("https://fernuni-hagen.sciebo.de/public.php/webdav/", upload_filename) # 执行上传 PUT(upload_url, authenticate(username, password), body = upload_file(temp_log_file)) # 删除临时文件(节省空间) file.remove(temp_log_file) })) # 以下绘图代码保持不变 output$distPlot1 <- renderPlot({ x <- faithful[, 2] bins <- seq(min(x), max(x), length.out = input$bins1 + 1) hist(x, breaks = bins, col = 'darkgray', border = 'white') }) output$distPlot2 <- renderPlot({ input$go x <- faithful[, 2] bins <- seq(min(x), max(x), length.out = isolate(input$bins2) + 1) hist(x, breaks = bins, col = 'darkgray', border = 'white') }) }
额外建议
- 凭据安全:不要硬编码用户名和密码,在shinyapps.io中通过环境变量存储,用
Sys.getenv("WEBDAV_USER")和Sys.getenv("WEBDAV_PWD")读取 - 错误排查:添加
tryCatch捕获上传错误,输出具体信息便于调试:tryCatch({ PUT(upload_url, authenticate(username, password), body = upload_file(temp_log_file)) }, error = function(e){ cat("上传失败:", e$message, "\n") }) - 网络权限:确认shinyapps.io服务器能访问目标WebDAV地址,若存在防火墙限制需联系管理员开通
内容的提问来源于stack exchange,提问作者Eric Berkmann
相关产品推荐
相关产品推荐

