我正在try 将R Plumber测试API部署为停靠容器,因为我的主要目标是在每次API处理请求时成功创建一个日志(log)文件.我在当地测试了它,它很管用.

以下是我的测试文件:

利伯.R

# 利伯.R
# A simple API to illustrate logging with Plumber

library(plumber)

#* @apiTitle Logging Example

#* @apiDescription Simple example API for implementing logging with Plumber

#* Echo back the input
#* @param msg The message to echo
#* @get /echo
function(msg = "") {
  list(msg = paste0("The message is: '", msg, "'"))
}

Entrypoint.R

library(plumber)

# Config
#config <- config::get()

# logging
library(logger)
# Ensure glue is a specific dependency so it's avaible for logger
library(glue)

# Specify how logs are written 
log_dir <- "/app/logs"
if (!fs::dir_exists(log_dir)) fs::dir_create(log_dir)
log_appender(appender_tee(tempfile("plumber_", log_dir, ".log")))

convert_empty <- function(string) {
  if (string == "") {
    "-"
  } else {
    string
  }
}

pr <- plumb("利伯.R")

pr$registerHooks(
  list(
    preroute = function() {
      # Start timer for log info
      tictoc::tic()
    },
    postroute = function(req, res) {
      end <- tictoc::toc(quiet = TRUE)
      # Log details about the request and the response
      # TODO: Sanitize log details - perhaps in convert_empty
      log_info('{convert_empty(req$REMOTE_ADDR)} "{convert_empty(req$HTTP_USER_AGENT)}" {convert_empty(req$HTTP_HOST)} {convert_empty(req$REQUEST_METHOD)} {convert_empty(req$PATH_INFO)} {convert_empty(res$status)} {round(end$toc - end$tic, digits = getOption("digits", 5))}')
    }
  )
)

pr

文档文件

# Base image https://hub.docker.com/u/rocker/
FROM rstudio/plumber

# Install R libraries
RUN R -e "install.packages(c('odbc','glue','parsedate','tibble','dplyr','httr','RCurl','jsonlite','rjson','stringr','telegram','R.utils','logger','tictoc'))"

# Run plumber package
CMD ["/app/利伯.R"]

我的预期结果是能够将日志(log)存储在容器和主机之间的共享文件夹中.但到目前为止,我甚至还不能让水管工应用程序创建一个日志(log)文件,其中的日志(log)位于/app/Logs中.

docker build -t logger2 .

docker run -d -p 18001:8000 --rm \
-v /home/user/R/projects/logger2/:/app \
-v /tmp/log1:/app/logs \
logger2

推荐答案

这里的问题是入口点.您的入口点.R脚本将被忽略.

以下是这位管道工形象附带的default entrypoint:

ENTRYPOINT ["R", "-e", "pr <- plumber::plumb(rev(commandArgs())[1]); args <- list(host = '0.0.0.0', port = 8000); if (packageVersion('plumber') >= '1.0.0') { pr$setDocs(TRUE) } else { args$swagger <- TRUE }; do.call(pr$run, args)"]

这就是它的作用:

  • 载入管道工库.
  • 从dockerfile中的cmd行中,获取要加载的文件的文件名.
  • 把那份文件弄清楚.
  • 打开文档.
  • 侦听端口8000上的所有接口.

在本例中,它加载/app/plumber.R文件,而忽略/app/entrypoint.R文件.

你怎么能解决这个问题呢?在Docker文件中定义您自己的入口点.

FROM rstudio/plumber

# Install R libraries
RUN R -e "install.packages(c('odbc','glue','parsedate','tibble','dplyr','httr','RCurl','jsonlite','rjson','stringr','telegram','R.utils','logger','tictoc'))"

ENTRYPOINT ["Rscript", "/app/entrypoint.R"]

在这里,我仍然遇到了一些问题:

  1. 没有文件系统包.我加了RUN R -e "install.packages(c('fs'))"来安装它.
  2. 收到错误Error in plumb("plumber.R") : File does not exist: plumber.R.这是因为服务器在错误的目录中运行.我修复了这个问题,将WORKDIR /app添加到您的文档文件中.
  3. 必须将最后一行entrypoint.Rpr更改为pr$run(host='0.0.0.0', port=8000)才能真正运行.

完整文档文件:

FROM rstudio/plumber

# Install R libraries
RUN R -e "install.packages(c('odbc','glue','parsedate','tibble','dplyr','httr','RCurl','jsonlite','rjson','stringr','telegram','R.utils','logger','tictoc'))"
RUN R -e "install.packages(c('fs'))"

WORKDIR /app
ENTRYPOINT ["Rscript", "/app/entrypoint.R"]

完整的entrypoint.R个文件:

library(plumber)

# Config
#config <- config::get()

# logging
library(logger)
# Ensure glue is a specific dependency so it's avaible for logger
library(glue)

# Specify how logs are written 
log_dir <- "/app/logs"
if (!fs::dir_exists(log_dir)) fs::dir_create(log_dir)
log_appender(appender_tee(tempfile("plumber_", log_dir, ".log")))

convert_empty <- function(string) {
  if (string == "") {
    "-"
  } else {
    string
  }
}

pr <- plumb("plumber.R")

pr$registerHooks(
  list(
    preroute = function() {
      # Start timer for log info
      tictoc::tic()
    },
    postroute = function(req, res) {
      end <- tictoc::toc(quiet = TRUE)
      # Log details about the request and the response
      # TODO: Sanitize log details - perhaps in convert_empty
      log_info('{convert_empty(req$REMOTE_ADDR)} "{convert_empty(req$HTTP_USER_AGENT)}" {convert_empty(req$HTTP_HOST)} {convert_empty(req$REQUEST_METHOD)} {convert_empty(req$PATH_INFO)} {convert_empty(res$status)} {round(end$toc - end$tic, digits = getOption("digits", 5))}')
    }
  )
)

pr$run(host='0.0.0.0', port=8000)

R相关问答推荐

如果窗口在CLARME或集团之外,则有条件领先/滞后滚动总和返回NA

从R中的另一个包扩展S3类的正确方法是什么

在R中查找每个组不同时间段的总天数

基于不同组的列的相关性

多重RHS固定估计

然后根据不同的列值有条件地执行函数

RStudio中相关数据的分组箱形图

将饼图插入条形图

使用`Watch()`和`renderUI()`时,不再满足仍出现在SHILINY AFTER条件中的条件输入

如何通过匹配R中所有可能的组合来从宽到长旋转多个列?

如何识别倒排的行并在R中删除它们?

在R中创建连续的期间

循环遍历多个变量,并将每个变量插入函数R

如何在使用因子时获得Sankey图的Scale_Fill_Viridis的全范围

如何构建一个for循环来循环处理动物ID?

TidyVerse中长度不等的列结合向量

使用LAG和dplyr执行计算,以便按行和按组迭代

将Geojson保存为R中的shapefile

如果y中存在x中的值,则将y行中的多个值复制到相应的x行中

基于已有ID列创建唯一ID