From b82dc79608daa095e3016efd21ad3d4c08b9e0d6 Mon Sep 17 00:00:00 2001 From: wlandau Date: Tue, 8 Oct 2024 09:29:55 -0400 Subject: [PATCH] metrics logging options --- NAMESPACE | 3 +- R/crew_launcher_local.R | 2 +- R/crew_options.R | 9 -- R/crew_options_local.R | 9 +- R/crew_options_metrics.R | 118 +++++++++++++++++++++ _pkgdown.yml | 1 - man/crew_options_local.Rd | 2 +- man/crew_options_metrics.Rd | 64 +++++++++++ man/crew_options_validate.Rd | 20 ---- tests/testthat/test-crew_options_local.R | 4 +- tests/testthat/test-crew_options_metrics.R | 9 ++ 11 files changed, 202 insertions(+), 39 deletions(-) delete mode 100644 R/crew_options.R create mode 100644 R/crew_options_metrics.R create mode 100644 man/crew_options_metrics.Rd delete mode 100644 man/crew_options_validate.Rd create mode 100644 tests/testthat/test-crew_options_metrics.R diff --git a/NAMESPACE b/NAMESPACE index 2e9084a4..d7896160 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method(crew_options_validate,crew_options_local) export(all_of) export(any_of) export(contains) @@ -28,7 +27,7 @@ export(crew_launcher) export(crew_launcher_local) export(crew_monitor_local) export(crew_options_local) -export(crew_options_validate) +export(crew_options_metrics) export(crew_random_name) export(crew_relay) export(crew_retry) diff --git a/R/crew_launcher_local.R b/R/crew_launcher_local.R index 33d677e5..5558932d 100644 --- a/R/crew_launcher_local.R +++ b/R/crew_launcher_local.R @@ -228,7 +228,7 @@ crew_class_launcher_local <- R6::R6Class( #' @return `NULL` (invisibly). validate = function() { super$validate() - crew_options_validate(private$.options_local) + crew_options_local_validate(private$.options_local) }, #' @description Launch a local process worker which will #' dial into a socket. diff --git a/R/crew_options.R b/R/crew_options.R deleted file mode 100644 index a4332d4b..00000000 --- a/R/crew_options.R +++ /dev/null @@ -1,9 +0,0 @@ -#' @title Validate options. -#' @export -#' @family options -#' @description Validate a `crew` options list. -#' @return `NULL` (invisibly) on success, throws an error if there is -#' something wrong with the options list. -crew_options_validate <- function(options) { - UseMethod("crew_options_validate") -} diff --git a/R/crew_options_local.R b/R/crew_options_local.R index 6150fdf8..4de94e62 100644 --- a/R/crew_options_local.R +++ b/R/crew_options_local.R @@ -26,12 +26,15 @@ crew_options_local = function( ), class = c("crew_options_local", "crew_options") ) - crew_options_validate(out) + crew_options_local_validate(out) out } -#' @export -crew_options_validate.crew_options_local <- function(options) { +crew_options_local_validate <- function(options) { + crew_assert( + inherits(options, "crew_options_local"), + message = "options_local object must come from crew_options_local()." + ) crew_assert( options$log_directory %|||% "x", is.character(.), diff --git a/R/crew_options_metrics.R b/R/crew_options_metrics.R new file mode 100644 index 00000000..742d07f7 --- /dev/null +++ b/R/crew_options_metrics.R @@ -0,0 +1,118 @@ +#' @title Options for logging resource usage metrics. +#' @export +#' @family options +#' @description If a [crew_options_metrics()] object is +#' supplied to the `options_metrics` argument of a `crew` +#' controller function, then the `autometric` R package will +#' record resource usage metrics (such as CPU and memory usage) +#' as the controller and workers are running. Logging happens in +#' the background (through a detached POSIX) so as not to disrupt +#' the R session. On Unix-like systems, [crew_options_metrics()] +#' can specify `/dev/stdout` or `/dev/stderr` as the log files, which will +#' redirect output to existing logs you are already using. Then, +#' even if those logs are mixed with other messages, you can use functions +#' [autometric::log_read()] and [autometric::log_plot()] to read and +#' visualize resource usage data. +#' @param path_local Where to write resource metric log entries for the +#' local R session and `mirai` dispatcher process. +#' If `NULL`, resource metric logging is turned off for these processes. +#' If `"/dev/stdout"` or `"/dev/stderr"`, resource usage metrics +#' are printed to standard output or standard error, +#' respectively. If a different character string, that string is the +#' directory path for writing logs to files on disk, and each +#' controller instance gets a different log file. +#' [autometric::log_read()] and [autometric::log_plot()] can read and +#' visualize data from logs, even if the logs files are mixed +#' with other kinds of messages. +#' @param path_workers Like `path_local`, but for the `crew` worker processes. +#' On Unix-like systems, it is recommended to set `path_workers` +#' equal to `"/dev/stdout"` or `"/dev/stderr"` to automatically write +#' resource log messages to the existing log files generated on your +#' platform (for example, the logs configured with +#' [crew_options_local()] in the case of [crew_controller_local()]). +#' [autometric::log_read()] and [autometric::log_plot()] can read and +#' visualize data from logs, even if the logs files are mixed +#' with other kinds of messages. +#' @param seconds_local Positive number, seconds between resource metric log +#' entries written to `path_local`. +#' @param seconds_workers Positive number, seconds between resource metric log +#' entries written to `seconds_workers`. +#' @examples +#' crew_options_metrics() +crew_options_metrics = function( + path_local = NULL, + path_workers = NULL, + seconds_local = 5, + seconds_workers = 5 +) { + out <- structure( + list( + path_local = path_local, + path_workers = path_workers, + seconds_local = seconds_local, + seconds_workers = seconds_workers + ), + class = c("crew_options_metrics", "crew_options") + ) + crew_options_metrics_validate(out) + out +} + +crew_options_metrics_validate <- function(options) { + crew_assert( + inherits(options, "crew_options_metrics"), + message = "options_metrics object must come from crew_options_metrics()." + ) + crew_assert( + options$path_local %|||% "x", + is.character(.), + length(.) == 1L, + !anyNA(.), + nzchar(.), + message = paste( + "path_local must be NULL, \"/dev/stdout\", ", + "\"/dev/stderr\", or a valid directory path." + ) + ) + crew_assert( + options$path_workers %|||% "x", + is.character(.), + length(.) == 1L, + !anyNA(.), + nzchar(.), + message = paste( + "path_workers must be NULL, \"/dev/stdout\", ", + "\"/dev/stderr\", or a valid directory path." + ) + ) + on_windows <- identical(unname(tolower(Sys.info()[["sysname"]])), "windows") + streams <- file.path("/dev", c("stdout", "stderr")) + crew_assert( + !(on_windows && options$path_local %in% streams), + message = paste( + "path_local cannot be \"/dev/stdout\" or \"/dev/stderr\" on Windows." + ) + ) + crew_assert( + !(on_windows && options$path_workers %in% streams), + message = paste( + "path_workers cannot be \"/dev/stdout\" or \"/dev/stderr\" on Windows." + ) + ) + crew_assert( + options$seconds_local, + is.numeric(.), + length(.) == 1, + is.finite(.), + . > 0, + message = "seconds_local must be a positive number." + ) + crew_assert( + options$seconds_workers, + is.numeric(.), + length(.) == 1, + is.finite(.), + . > 0, + message = "seconds_workers must be a positive number." + ) +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 9b9533be..2fea054d 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -51,7 +51,6 @@ reference: contents: - crew_options_local - crew_options_metrics - - crew_options_validate - title: TLS configuration contents: - crew_tls diff --git a/man/crew_options_local.Rd b/man/crew_options_local.Rd index 75ac1544..d43d29f9 100644 --- a/man/crew_options_local.Rd +++ b/man/crew_options_local.Rd @@ -28,6 +28,6 @@ Options for the local \code{crew} launcher. } \seealso{ Other options: -\code{\link{crew_options_validate}()} +\code{\link{crew_options_metrics}()} } \concept{options} diff --git a/man/crew_options_metrics.Rd b/man/crew_options_metrics.Rd new file mode 100644 index 00000000..614f6262 --- /dev/null +++ b/man/crew_options_metrics.Rd @@ -0,0 +1,64 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/crew_options_metrics.R +\name{crew_options_metrics} +\alias{crew_options_metrics} +\title{Options for logging resource usage metrics.} +\usage{ +crew_options_metrics( + path_local = NULL, + path_workers = NULL, + seconds_local = 5, + seconds_workers = 5 +) +} +\arguments{ +\item{path_local}{Where to write resource metric log entries for the +local R session and \code{mirai} dispatcher process. +If \code{NULL}, resource metric logging is turned off for these processes. +If \code{"/dev/stdout"} or \code{"/dev/stderr"}, resource usage metrics +are printed to standard output or standard error, +respectively. If a different character string, that string is the +directory path for writing logs to files on disk, and each +controller instance gets a different log file. +\code{\link[autometric:log_read]{autometric::log_read()}} and \code{\link[autometric:log_plot]{autometric::log_plot()}} can read and +visualize data from logs, even if the logs files are mixed +with other kinds of messages.} + +\item{path_workers}{Like \code{path_local}, but for the \code{crew} worker processes. +On Unix-like systems, it is recommended to set \code{path_workers} +equal to \code{"/dev/stdout"} or \code{"/dev/stderr"} to automatically write +resource log messages to the existing log files generated on your +platform (for example, the logs configured with +\code{\link[=crew_options_local]{crew_options_local()}} in the case of \code{\link[=crew_controller_local]{crew_controller_local()}}). +\code{\link[autometric:log_read]{autometric::log_read()}} and \code{\link[autometric:log_plot]{autometric::log_plot()}} can read and +visualize data from logs, even if the logs files are mixed +with other kinds of messages.} + +\item{seconds_local}{Positive number, seconds between resource metric log +entries written to \code{path_local}.} + +\item{seconds_workers}{Positive number, seconds between resource metric log +entries written to \code{seconds_workers}.} +} +\description{ +If a \code{\link[=crew_options_metrics]{crew_options_metrics()}} object is +supplied to the \code{options_metrics} argument of a \code{crew} +controller function, then the \code{autometric} R package will +record resource usage metrics (such as CPU and memory usage) +as the controller and workers are running. Logging happens in +the background (through a detached POSIX) so as not to disrupt +the R session. On Unix-like systems, \code{\link[=crew_options_metrics]{crew_options_metrics()}} +can specify \verb{/dev/stdout} or \verb{/dev/stderr} as the log files, which will +redirect output to existing logs you are already using. Then, +even if those logs are mixed with other messages, you can use functions +\code{\link[autometric:log_read]{autometric::log_read()}} and \code{\link[autometric:log_plot]{autometric::log_plot()}} to read and +visualize resource usage data. +} +\examples{ + crew_options_metrics() +} +\seealso{ +Other options: +\code{\link{crew_options_local}()} +} +\concept{options} diff --git a/man/crew_options_validate.Rd b/man/crew_options_validate.Rd deleted file mode 100644 index 81f25440..00000000 --- a/man/crew_options_validate.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/crew_options.R -\name{crew_options_validate} -\alias{crew_options_validate} -\title{Validate options.} -\usage{ -crew_options_validate(options) -} -\value{ -\code{NULL} (invisibly) on success, throws an error if there is -something wrong with the options list. -} -\description{ -Validate a \code{crew} options list. -} -\seealso{ -Other options: -\code{\link{crew_options_local}()} -} -\concept{options} diff --git a/tests/testthat/test-crew_options_local.R b/tests/testthat/test-crew_options_local.R index 8d4cc701..231e397d 100644 --- a/tests/testthat/test-crew_options_local.R +++ b/tests/testthat/test-crew_options_local.R @@ -2,7 +2,7 @@ crew_test("crew_options_local", { out <- crew_options_local(log_directory = "x", log_join = FALSE) expect_equal(out$log_directory, "x") expect_false(out$log_join) - expect_silent(crew_options_validate(out)) + expect_silent(crew_options_local_validate(out)) out$log_directory <- 123 - expect_crew_error(crew_options_validate(out)) + expect_crew_error(crew_options_local_validate(out)) }) diff --git a/tests/testthat/test-crew_options_metrics.R b/tests/testthat/test-crew_options_metrics.R new file mode 100644 index 00000000..544d4c67 --- /dev/null +++ b/tests/testthat/test-crew_options_metrics.R @@ -0,0 +1,9 @@ +crew_test("crew_options_metrics()", { + out <- crew_options_metrics( + path_local = "x", + path_workers = "y", + seconds_local = 10, + seconds_workers = 11 + ) + expect_silent(crew_options_metrics_validate(out)) +})