diff --git a/NAMESPACE b/NAMESPACE index b13fd3e..1209d88 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(convert_to_csv) +export(debuginfo) export(get_call_options) export(get_echo) export(get_log_level) diff --git a/NEWS.md b/NEWS.md index 4b12219..e8213ce 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ ## New Features * `set_call_options()` offers new option to log condition calls or even the full call stack. `get_call_options()` returns the current settings. +* All condition log handlers e.g. `warning()` and `with_loggit()` now support call logging. +* Added `debuginfo()` as an additional log handler for debugging purposes. ## Minor Changes * `loggit()` now checks the `...` arguments for use of reserved names, currently `log_call` and `timestamp`. diff --git a/R/handlers_non_base.R b/R/handlers_non_base.R new file mode 100644 index 0000000..5ca986e --- /dev/null +++ b/R/handlers_non_base.R @@ -0,0 +1,32 @@ +#' Debug Log Handler +#' +#' This function works like base R's [`warning`][base::warning] , +#' but is silent, includes logging of the exception message via `loggit()` and does not allow conditions as input. +#' +#' @inherit base::warning params +#' @inherit message params +#' @inheritParams loggit +#' +#' @return No return value. +#' +#' @family handlers +#' +#' @examples +#' \dontrun{ +#' debuginfo("This is a completely false condition") +#' +#' debuginfo("This is a completely false condition", echo = FALSE) +#' } +#' +#' @details This function is more than just a wrapper around `loggit()` with a log level of "DEBUG". +#' It has the ability to track the call stack and log it if `call.` is set to `TRUE` and to automatically +#' translate the input into a message using `.makeMessage()`, like `warning()` does. +#' +#' @export +debuginfo <- function(..., call. = TRUE, .loggit = NA, echo = get_echo()) { + # The call of the error must be set manually for loggit_internal + call <- if (call.) find_call() + if (isTRUE(.loggit) || (!isFALSE(.loggit) && get_log_level() >= 4L)) { + loggit_internal(log_lvl = "DEBUG", log_msg = .makeMessage(..., domain = NULL), log_call = call, echo = echo) + } +} diff --git a/man/call_2_string.Rd b/man/call_2_string.Rd index f5046b0..dc8c8ca 100644 --- a/man/call_2_string.Rd +++ b/man/call_2_string.Rd @@ -20,7 +20,7 @@ Deparsed call as string. Converts a call object to a string and optionally determines the full call stack. } \details{ -The full call stack can only be determined if the call is in the current context. -The default cutoff is 4 because the only known case is an primitive error in \code{with_loggit()} which adds 4 calls to the stack. +The full call stack can only be determined if the call is in the current context. The default cutoff is 4 +because the only known case is an primitive error in \code{with_loggit()} which adds 4 calls to the stack. } \keyword{internal} diff --git a/man/debuginfo.Rd b/man/debuginfo.Rd new file mode 100644 index 0000000..16d5c7e --- /dev/null +++ b/man/debuginfo.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/handlers_non_base.R +\name{debuginfo} +\alias{debuginfo} +\title{Debug Log Handler} +\usage{ +debuginfo(..., call. = TRUE, .loggit = NA, echo = get_echo()) +} +\arguments{ +\item{...}{zero or more objects which can be coerced to character + (and which are pasted together with no separator) or a single + condition object.} + +\item{call.}{logical, indicating if the call should become part of the + warning message.} + +\item{.loggit}{Should the condition message be added to the log? +If \code{NA} the log level set by \code{set_log_level()} is used to determine if the condition should be logged.} + +\item{echo}{Should the log entry (json) be echoed to \code{stdout} as well?} +} +\value{ +No return value. +} +\description{ +This function works like base R's \code{\link[base:warning]{warning}} , +but is silent, includes logging of the exception message via \code{loggit()} and does not allow conditions as input. +} +\details{ +This function is more than just a wrapper around \code{loggit()} with a log level of "DEBUG". +It has the ability to track the call stack and log it if \code{call.} is set to \code{TRUE} and to automatically +translate the input into a message using \code{.makeMessage()}, like \code{warning()} does. +} +\examples{ +\dontrun{ + debuginfo("This is a completely false condition") + + debuginfo("This is a completely false condition", echo = FALSE) +} + +} +\seealso{ +Other handlers: +\code{\link{message}()}, +\code{\link{stop}()}, +\code{\link{stopifnot}()}, +\code{\link{warning}()} +} +\concept{handlers} diff --git a/man/message.Rd b/man/message.Rd index 3a747ef..9206ac3 100644 --- a/man/message.Rd +++ b/man/message.Rd @@ -38,6 +38,7 @@ but it includes logging of the exception message via \code{loggit()}. } \seealso{ Other handlers: +\code{\link{debuginfo}()}, \code{\link{stop}()}, \code{\link{stopifnot}()}, \code{\link{warning}()} diff --git a/man/stop.Rd b/man/stop.Rd index 193aeef..0d6c016 100644 --- a/man/stop.Rd +++ b/man/stop.Rd @@ -39,6 +39,7 @@ but it includes logging of the exception message via \code{loggit()}. } \seealso{ Other handlers: +\code{\link{debuginfo}()}, \code{\link{message}()}, \code{\link{stopifnot}()}, \code{\link{warning}()} diff --git a/man/stopifnot.Rd b/man/stopifnot.Rd index aff5726..add14ff 100644 --- a/man/stopifnot.Rd +++ b/man/stopifnot.Rd @@ -51,6 +51,7 @@ but it includes logging of the exception message via \code{loggit()}. } \seealso{ Other handlers: +\code{\link{debuginfo}()}, \code{\link{message}()}, \code{\link{stop}()}, \code{\link{warning}()} diff --git a/man/warning.Rd b/man/warning.Rd index a149e7e..c138896 100644 --- a/man/warning.Rd +++ b/man/warning.Rd @@ -53,6 +53,7 @@ but it includes logging of the exception message via \code{loggit()}. } \seealso{ Other handlers: +\code{\link{debuginfo}()}, \code{\link{message}()}, \code{\link{stop}()}, \code{\link{stopifnot}()} diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 14adf84..aa7b355 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -21,6 +21,9 @@ reference: - "warning" - "stop" - "stopifnot" + - title: Non-base log handlers + - contents: + - "debuginfo" - title: Log functions - contents: - "loggit" diff --git a/tests/testthat/test-handlers_non_base.R b/tests/testthat/test-handlers_non_base.R new file mode 100644 index 0000000..3191db3 --- /dev/null +++ b/tests/testthat/test-handlers_non_base.R @@ -0,0 +1,47 @@ +test_that("debuginfo echos", { + expect_output(debuginfo("This is a debug test", echo = TRUE), "This is a debug test") +}) +cleanup() + +test_that("debuginfo logs message at DEBUG level", { + # silent output + expect_silent(debuginfo("This is a debug test", echo = FALSE)) + + logdata <- read_logs() + logdata <- logdata[nrow(logdata),] + + expect_identical(logdata[["log_lvl"]], "DEBUG") + expect_identical(logdata[["log_msg"]], "This is a debug test") +}) +cleanup() + +test_that("debuginfo concatenates multiple arguments", { + expect_silent(debuginfo("This ", "is ", "a debug test", echo = FALSE)) + + logdata <- read_logs() + logdata <- logdata[nrow(logdata),] + + expect_identical(logdata[["log_lvl"]], "DEBUG") + expect_identical(logdata[["log_msg"]], "This is a debug test") +}) +cleanup() + +test_that("debuginfo respects call. argument without error", { + # call. = TRUE should not error + f <- function() debuginfo("call test", call. = TRUE, echo = FALSE) + expect_silent(f()) + + # call. = FALSE should not error and still log + expect_silent(debuginfo("no call", call. = FALSE, echo = FALSE)) + logdata <- read_logs() + expect_identical(logdata[["log_lvl"]], c("DEBUG", "DEBUG")) + expect_identical(logdata[["log_msg"]], c("call test", "no call")) +}) +cleanup() + +test_that("debuginfo does not log on log level below DEBUG", { + old_level <- set_log_level(3L, confirm = FALSE) + expect_silent(debuginfo("This should not log")) + expect_error(read_logs(), "Log file does not exist", fixed = TRUE) + set_log_level(old_level, confirm = FALSE) +}) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 8be6f92..6439d1f 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -209,3 +209,14 @@ test_that("call_2_string (full_stack=TRUE) handels call not in current context", endsWith(call_2_string(ext_call, full_stack = TRUE), "Original Call: some_function(1L, 2L)") ) }) + +test_that("test call_2_string (cut off) via condition handler", { + old <- set_call_options(log_call = TRUE, full_stack = TRUE, confirm = FALSE) + # Function is needed to create a predictable call stack and a call to cut off + f <- function() warning("This is a warning", echo = FALSE) + expect_warning(f(), "This is a warning") + logdata <- read_logs() + expect_true(grepl(logdata[["log_call"]], pattern = "f()")) + set_call_options(.arg_list = old, confirm = FALSE) +}) +cleanup()