I have followed the Rstudio example here for logging for logging requests in Plumber (R API package) and would like to add other variables to the log. However, the registerHooks
statement does not recognise global variables (<<-
).
# Enable CORS Filtering
#' @filter auth_filter
auth_filter <- function(req, res) {
req_user <<- req$HEADERS['authorization'] %>% as.character()
req_tenant <<- req$HTTP_TENANT
}
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
log_info('{convert_empty(req_user)} {convert_empty(req_tenant)} {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))}')
}))
In the above example, req_user
and req_tenant
change for every request. The above example gives an error message, stating that req_user
and req_tenant
do not exist. I have also tried preserialize
as an alternative to postroute
. How can these variables be logged? The don't need to be global, this was just an additional attempt to solve the problem.
I believe the error is produced because of the convert_empty
function not being able to handle null
's or na
's.
I adjusted this function to handle null's or na's in case they do occur:
convert_empty <- function(string) {
if (is.null(string) || is.na(string) || string == "") {
"-"
} else {
string
}
}
Using the sample plumber.R
code that's produced in RStudio, this should work:
#Plumber.R file
library(plumber)
library(logger)
# Specify how logs are written
log_dir <- "logs"
if (!fs::dir_exists(log_dir)) fs::dir_create(log_dir)
log_appender(appender_tee(tempfile("plumber_", log_dir, ".log")))
#* Return the sum of two numbers
#* @param a The first number to add
#* @param b The second number to add
#* @post /sum
function(a, b) {
as.numeric(a) + as.numeric(b)
}
Then we register the hooks as follows:
library(plumber)
pr <- plumb("plumber.R")
convert_empty <- function(string) {
if (is.null(string) || is.na(string) || string == "") {
"-"
} else {
string
}
}
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
log_info('{convert_empty(as.character(req$HEADERS["authorization"]))} {convert_empty(req$HTTP_TENANT)} {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
In the console, you can do:
pr$run()
so serve your API locally.
From there, go to the terminal in RStudio and do a curl. Assuming is your port, an example would be:
curl -H "Authorization: Bearer my_token" -H "TENANT: 123" -X POST "http://127.0.0.1:9520/sum?a=1&b=2"
You should see a return of 3
in the terminal, and if you look at the R console, you will see the Authorization and tenant headers logged