shiny icon indicating copy to clipboard operation
shiny copied to clipboard

Add additional hooks for Websocket and HTTP traffic inspection

Open atheriel opened this issue 3 years ago • 1 comments

Shiny exposes various "hooks" to run user code when various events occur -- onFlush(), onSessionEnded(), and so on. One notable omission from the existing hooks is the ability to capture individual Websocket messages and HTTP requests. These are available in other packages that use httpuv, notably Plumber.

The main reason I'm interested in this is to improve the Prometheus metrics we can expose for Shiny in the openmetrics package. Websocket and HTTP traffic is one of the main ways to measure load on a Shiny app, and without a way to hook into these events I don't have a way to effectively monitor them.

Ideally, I'd like to see a Websocket hook expose the same binary and message parameters used in the Websocket message handler: https://github.com/rstudio/shiny/blob/b52b9e4520ad8d1e976299d5dec5e4ba3096bd04/R/server.R#L294-L297

so that we could measure binary vs. JSON traffic and the number of bytes sent/received. In order to capture messages sent, a hook would also have to be added for Websocket writes on the ShinySession object: https://github.com/rstudio/shiny/blob/b52b9e4520ad8d1e976299d5dec5e4ba3096bd04/R/shiny.R#L393-L402

For HTTP requests, we'd need hooks for before and after the request was handled, ideally exposing the Rook/httpuv req and res objects.

Although I'm primarily interested in metrics, other uses for these hooks that come to mind for these hooks include ad-hoc debugging (say, stick a browser() in a hook) or custom logging. It's possible that there are scenarios where users might actually want to modify the incoming/outgoing messages, too, though I doubt that would be effective for Websockets without additional changes on the Javascript side.

atheriel avatar May 16 '22 20:05 atheriel

FYI: for the HTTP requests in particular, many of these are going to be handled using httpuv's staticPath feature (in particular, all of the JS/CSS assets). The whole point of staticPath is to handle the entire HTTP transaction in C++ on a background thread, so there's no way to add an R callback without drastically affecting performance. However, those are also probably the least interesting requests from a monitoring perspective, since they represent almost no load compared to anything we handle in R.

jcheng5 avatar May 16 '22 21:05 jcheng5