mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-07 22:24:02 -05:00
137 lines
4.7 KiB
R
137 lines
4.7 KiB
R
#' Temporarily set OpenTelemetry collection level
|
|
#'
|
|
#' @description
|
|
#' `withOtelCollect()` temporarily sets the OpenTelemetry collection level for
|
|
#' the duration of evaluating `expr`. `localOtelCollect()` sets the collection
|
|
#' level for the remainder of the current function scope.
|
|
#'
|
|
#' These functions are useful for temporarily controlling telemetry collection
|
|
#' during reactive expression creation. Only the following levels are allowed:
|
|
#' * `"none"` - No telemetry data collected
|
|
#' * `"reactivity"` - Collect reactive execution spans (includes session and
|
|
#' reactive update events)
|
|
#' * `"all"` - All available telemetry (currently equivalent to `"reactivity"`)
|
|
#'
|
|
#' Note that `"session"` and `"reactive_update"` levels are not permitted as
|
|
#' these are runtime-specific levels that should only be set permanently via
|
|
#' `options(shiny.otel.collect = ...)` or the `SHINY_OTEL_COLLECT` environment
|
|
#' variable, not temporarily during reactive expression creation.
|
|
#'
|
|
#' @section Intended Usage:
|
|
#'
|
|
#' These functions are designed to perform sweeping changes to telemetry
|
|
#' collection, such as enabling or disabling OpenTelemetry for an entire module
|
|
#' or section of code where reactive expressions are being **created**:
|
|
#'
|
|
#' ```r
|
|
#' # Enable telemetry for an entire module
|
|
#' withOtelCollect("all", {
|
|
#' my_result <- my_module("my_id")
|
|
#' })
|
|
#'
|
|
#' # Disable telemetry for expensive development-only reactives
|
|
#' withOtelCollect("none", {
|
|
#' debug_reactive <- reactive({ expensive_debug_computation() })
|
|
#' })
|
|
#' ```
|
|
#'
|
|
#' @section Pipe Usage (Not Recommended):
|
|
#'
|
|
#' While using `withOtelCollect()` as a pipe-able method, it is not recommended due to the use case where the reactive object is created before the `withOtelCollect()` call. In such cases, the reactive object will not inherit the intended OpenTelemetry settings.
|
|
#'
|
|
#' Therefore, to avoid this hard-to-debug situation, we recommend that you only create your reactive objects within the `withOtelCollect()` call or after setting the local collection level with `localOtelCollect()`.
|
|
#'
|
|
#' ```r
|
|
#' # Technically works, but not recommended
|
|
#' x <- reactive({ ... }) %>% withOtelCollect(collect = "all")
|
|
#' x <- reactive({ ... }) |> withOtelCollect(collect = "all")
|
|
#' # Equivalent to:
|
|
#' x <- withOtelCollect("all", reactive({ ... }))
|
|
#'
|
|
#' # Does NOT work as intended
|
|
#' x <- reactive({ ... })
|
|
#' # `x` was created outside of `withOtelCollect()`,
|
|
#' # therefore no OTel settings are applied
|
|
#' x_no_otel <- withOtelCollect("all", x)
|
|
#'
|
|
#' # Best practice: Create the reactive object within `expr=`
|
|
#' withOtelCollect("all", {
|
|
#' x_with_otel <- reactive({ ... })
|
|
#' y_with_otel <- reactive({ ... })
|
|
#' })
|
|
#' ```
|
|
#'
|
|
#' @param collect Character string specifying the OpenTelemetry collection level.
|
|
#' Must be one of `"none"`, `"reactivity"`, or `"all"`.
|
|
#' @param expr Expression to evaluate with the specified collection level
|
|
#' (for `withOtelCollect()`).
|
|
#' @param envir Environment where the collection level should be set
|
|
#' (for `localOtelCollect()`). Defaults to the parent frame.
|
|
#'
|
|
#' @return
|
|
#' * `withOtelCollect()` returns the value of `expr`.
|
|
#' * `localOtelCollect()` is called for its side effect and returns the previous
|
|
#' `collect` value invisibly.
|
|
#'
|
|
#' @seealso See the `shiny.otel.collect` option within [`shinyOptions`]. Setting
|
|
#' this value will globally control OpenTelemetry collection levels.
|
|
#'
|
|
#' @examples
|
|
#' \dontrun{
|
|
#' # Temporarily disable telemetry collection
|
|
#' withOtelCollect("none", {
|
|
#' # Code here won't generate telemetry
|
|
#' reactive({ input$x + 1 })
|
|
#' })
|
|
#'
|
|
#' # Collect reactivity telemetry but not other events
|
|
#' withOtelCollect("reactivity", {
|
|
#' # Reactive execution will be traced
|
|
#' observe({ print(input$x) })
|
|
#' })
|
|
#'
|
|
#' # Use local variant in a function
|
|
#' my_function <- function() {
|
|
#' localOtelCollect("none")
|
|
#' # Rest of function executes without telemetry
|
|
#' reactive({ input$y * 2 })
|
|
#' }
|
|
#' }
|
|
#'
|
|
#' @rdname withOtelCollect
|
|
#' @export
|
|
withOtelCollect <- function(collect, expr) {
|
|
collect <- as_otel_collect_with(collect)
|
|
|
|
withr::with_options(
|
|
list(shiny.otel.collect = collect),
|
|
expr
|
|
)
|
|
}
|
|
|
|
#' @rdname withOtelCollect
|
|
#' @export
|
|
localOtelCollect <- function(collect, envir = parent.frame()) {
|
|
collect <- as_otel_collect_with(collect)
|
|
|
|
old <- withr::local_options(
|
|
list(shiny.otel.collect = collect),
|
|
.local_envir = envir
|
|
)
|
|
|
|
invisible(old)
|
|
}
|
|
|
|
# Helper function to validate collect levels for with/local functions
|
|
# Only allows "none", "reactivity", and "all" - not "session" or "reactive_update"
|
|
as_otel_collect_with <- function(collect) {
|
|
if (!is.character(collect)) {
|
|
stop("`collect` must be a character vector.")
|
|
}
|
|
|
|
allowed_levels <- c("none", "reactivity", "all")
|
|
collect <- match.arg(collect, allowed_levels, several.ok = FALSE)
|
|
|
|
return(collect)
|
|
}
|