Skip to content

Commit

Permalink
version 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
gogonzo authored and cran-robot committed Mar 25, 2024
1 parent c71c387 commit 3993d64
Show file tree
Hide file tree
Showing 21 changed files with 512 additions and 86 deletions.
28 changes: 18 additions & 10 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
Package: teal.logger
Title: Logging Setup for the 'teal' Family of Packages
Version: 0.1.3
Date: 2023-09-05
Version: 0.2.0
Date: 2024-03-20
Authors@R: c(
person("Dawid", "Kaledkowski", , "dawid.kaledkowski@roche.com", role = c("aut", "cre")),
person("Konrad", "Pagacz", role = "aut"),
person("F. Hoffmann-La Roche AG", role = c("cph", "fnd"))
)
Description:
Utilizing the 'logger' framework to record events within a package, specific to 'teal' family of packages.
Supports logging namespaces, hierarchical logging, various log destinations, vectorization, and more.
Description: Utilizing the 'logger' framework to record events within a
package, specific to 'teal' family of packages. Supports logging
namespaces, hierarchical logging, various log destinations,
vectorization, and more.
License: Apache License 2.0
URL: https://insightsengineering.github.io/teal.logger/,
https://github.com/insightsengineering/teal.logger/
BugReports: https://github.com/insightsengineering/teal.logger/issues
Depends: R (>= 3.6)
Imports: glue, lifecycle, logger (>= 0.2.0), shiny, withr
Suggests: knitr, rmarkdown, testthat (>= 2.0)
Imports: glue (>= 1.0.0), lifecycle (>= 0.2.0), logger (>= 0.2.0),
methods, shiny (>= 1.6.0), withr (>= 2.1.0)
Suggests: knitr (>= 1.42), rmarkdown (>= 2.19), testthat (>= 3.1.5)
VignetteBuilder: knitr
RdMacros: lifecycle
Config/Needs/verdepcheck: tidyverse/glue, r-lib/lifecycle,
daroczig/logger, rstudio/shiny, r-lib/withr, yihui/knitr,
rstudio/rmarkdown, r-lib/testthat
Config/Needs/website: insightsengineering/nesttemplate
Encoding: UTF-8
Language: en-US
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
NeedsCompilation: no
Packaged: 2023-09-05 17:59:33 UTC; unardid
Packaged: 2024-03-22 19:06:04 UTC; unardid
Author: Dawid Kaledkowski [aut, cre],
Konrad Pagacz [aut],
F. Hoffmann-La Roche AG [cph, fnd]
Maintainer: Dawid Kaledkowski <dawid.kaledkowski@roche.com>
Repository: CRAN
Date/Publication: 2023-09-08 06:40:02 UTC
Date/Publication: 2024-03-24 23:10:02 UTC
34 changes: 20 additions & 14 deletions MD5
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
8aac0484f14224ed1118f369749b44d7 *DESCRIPTION
346ff2a4686d632d4cd4adb3478bc732 *NAMESPACE
f437bf5308a68abbb3e5a885a1f1a4f9 *NEWS.md
9c81c8c66f7df75597d8627429992f02 *R/register_logger.R
3ecf1d93d8b51d24349f84b3cba62bb1 *DESCRIPTION
21b011755cfc177bb78861abe0014452 *NAMESPACE
da001ece1667e8c91d4ceb88237c65ad *NEWS.md
1452fdf86c08b7fc7471b7d2db00dd67 *R/register_handlers.R
c9bbd74674e5bf7795b9c13237d92b9f *R/register_logger.R
41309da5a0e6b0c2d15994dba455e427 *R/supress_logs.R
5b752c53088baae6db056b93ab6a2e2e *R/teal.logger-package.R
b10c512afddc91afc9cc2d71717f9f65 *R/utils.R
78700804ed8413b0ad603e9c08eb9add *R/zzz.R
44a274e4cdffb5d1c345345cb6f4454a *README.md
b4373d78847032c61f170b56a96e5e25 *build/vignette.rds
84889b90598d2683f24b93304ff952e0 *R/utils.R
5e2e083656f62c135658a8d86956c33e *R/zzz.R
8113f78c9d091c72c59e2d7ab52e8a73 *README.md
093f3e1cadacdbac53d599ecb9f109a9 *build/vignette.rds
5a110f2b7582ff433659c0bf85ce9f84 *inst/WORDLIST
4485e9faea3a2bc533194712d54140dc *inst/doc/teal-logger.Rmd
802c58e4b1f3042ec698bd5a07d3f637 *inst/doc/teal-logger.html
de23bcd6a56cac6c4347c1f935d7cc47 *inst/doc/teal-logger.Rmd
c9fab79f50c60006dc569a45591f0a81 *inst/doc/teal-logger.html
cb1e46f469cfbbbde29c8b5113e1d789 *man/figures/lifecycle-archived.svg
c0d2e5a54f1fa4ff02bf9533079dd1f7 *man/figures/lifecycle-defunct.svg
a1b8c987c676c16af790f563f96cbb1f *man/figures/lifecycle-deprecated.svg
Expand All @@ -20,11 +21,16 @@ c3978703d8f40f2679795335715e98f4 *man/figures/lifecycle-experimental.svg
6902bbfaf963fbc4ed98b86bda80caa2 *man/figures/lifecycle-soft-deprecated.svg
53b3f893324260b737b3c46ed2a0e643 *man/figures/lifecycle-stable.svg
1c1fe7a759b86dc6dbcbe7797ab8246c *man/figures/lifecycle-superseded.svg
289c0e9ae9962bba7ea9bd9f28d35933 *man/get_val.Rd
9b93cf7f7b46395b65a156ffbae95548 *man/layout_teal_glue_generator.Rd
88e172c9bbb203bfa96674948c23d7fd *man/log_system_info.Rd
4faf6ce2a3b622f771c5b540cea2c69a *man/register_logger.Rd
46ca679cb1e63c3907f723fa05119526 *man/register_handlers.Rd
0603300110b1f94f1fe84b29e14e15b6 *man/register_logger.Rd
4909df4d0ff1e3ecabce46b0f808db86 *man/suppress_logs.Rd
4f2303722e4a2370d0a2e5f0e56de8aa *man/teal.logger-package.Rd
90b31f511e8a4f3e65c8daac563b1421 *man/teal.logger-package.Rd
51f235687662ac0bb11b6fa3aedc69e5 *tests/testthat.R
08e22a159c278b732ac30d15d8187ea9 *tests/testthat/test-register_logger.R
4485e9faea3a2bc533194712d54140dc *vignettes/teal-logger.Rmd
e1eebf1cf7fc0822e4b4e5c8a56eb09f *tests/testthat/setup-options.R
198e973385afdb28e5628753e2f70b6d *tests/testthat/test-register_handlers.R
532732311710d3b234f3ca167bf8e24a *tests/testthat/test-register_logger.R
37d52cc7b822af26f4a907281e337c45 *tests/testthat/test-utils.R
de23bcd6a56cac6c4347c1f935d7cc47 *vignettes/teal-logger.Rmd
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Generated by roxygen2: do not edit by hand

export(log_system_info)
export(register_handlers)
export(register_logger)
export(suppress_logs)
importFrom(lifecycle,badge)
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# teal.logger 0.2.0

* New function `register_handlers` to register global handlers for logging messages, warnings and errors.
* Specified minimal version of package dependencies.
* Update installation instructions in `README`.

# teal.logger 0.1.3

* Fixed CRAN requirements for the first CRAN submission.
Expand Down
142 changes: 142 additions & 0 deletions R/register_handlers.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#' Register handlers for logging messages, warnings and errors
#'
#' @param namespace (`character(1)`) the logger namespace
#' @param package (`character(1)`) the package name
#'
#' @return `NULL` invisibly. Called for its side effects.
#'
#' @details
#' This function registers global handlers for messages, warnings and errors.
#' The handlers will investigate the call stack and if it contains a function
#' from the package, the message, warning or error will be logged into the respective
#' namespace.
#'
#' The handlers are registered only once per package and type. Consecutive calls will no effect.
#' Registering handlers for package `base` is not supported.
#'
#' Use `TEAL.LOG_MUFFLE` environmental variable or `teal.log_muffle` R option to optionally
#' control recover strategies. If `TRUE` (a default value) then the handler will jump to muffle
#' restart for a given type of condition and doesn't continue (with output to the console).
#' Applicable for message and warning types only. The errors won't be suppressed.
#'
#' @note Registering handlers is forbidden within `tryCatch()` or `withCallingHandlers()`.
#' Because of this, handlers are registered only if it is possible.
#'
#' @seealso [globalCallingHandlers()]
#'
#' @export
#'
#' @examples
#' \dontrun{
#' register_handlers("teal.logger")
#' # see the outcome
#' globalCallingHandlers()
#' }
register_handlers <- function(namespace, package = namespace) {
if (register_handlers_possible()) {
register_handler_type(namespace = namespace, package = package, type = "message")
register_handler_type(namespace = namespace, package = package, type = "warning")
register_handler_type(namespace = namespace, package = package, type = "error")
}

invisible(NULL)
}

register_handler_type <- function(
namespace,
package = namespace,
type = c("error", "warning", "message")) {
if (!(is.character(namespace) && length(namespace) == 1 && !is.na(namespace))) {
stop("namespace argument must be a single string.")
}
if (!(namespace %in% logger::log_namespaces())) {
stop("namespace argument must be a pre-registered logger namespace.")
}
if (!(is.character(package) && length(package) == 1 && !is.na(package))) {
stop("package argument must be a single string.")
}
match.arg(type)

registered_handlers_namespaces[[package]] <- namespace

# avoid re-registering handlers
gch <- globalCallingHandlers()[names(globalCallingHandlers()) == type]
if (length(gch) > 0 && any(sapply(gch, attr, "type") == "teal.logger_handler")) {
return(invisible(NULL))
}

# create a handler object
# loop through the call stack starting from the bottom (the last call)
# if a function is from pre-registered package then log using pre-specified namespace
logger_fun <- switch(type,
error = logger::log_error,
warning = logger::log_warn,
message = logger::log_info
)
# nocov start
handler_fun <- function(m) {
i <- sys.nframe() - 1L # loop starting from the bottom of the stack and go up
while (i > 0L) { # exclude 0L as this value will detect the current `handler_fun()` function
env_sys_fun_i <- environment(sys.function(i))
pkg_sys_fun_i <- if (!is.null(env_sys_fun_i)) { # primitive functions don't have environment
methods::getPackageName(env_sys_fun_i)
} else {
""
}
if (pkg_sys_fun_i %in% ls(envir = registered_handlers_namespaces)) {
msg <- parse_logger_message(m)

log_namespace <- registered_handlers_namespaces[[pkg_sys_fun_i]]
logger_fun(msg, namespace = log_namespace)

# muffle restart
if (isTRUE(as.logical(get_val("TEAL.LOG_MUFFLE", "teal.log_muffle", TRUE)))) {
if (type == "message") {
invokeRestart("muffleMessage")
}
if (type == "warning") {
invokeRestart("muffleWarning")
}
}

break
}
i <- i - 1L
}
m
}
# nocov end
# add attributes to enable checking if the handler is already registered
handler_obj <- structure(
handler_fun,
type = "teal.logger_handler"
)

# construct & eval the call - globalCallingHandlers() requires named arguments
do.call(
globalCallingHandlers,
stats::setNames(list(handler_obj), type)
)

invisible(NULL)
}

parse_logger_message <- function(m) {
stopifnot(inherits(m, "condition"))

type <- class(m)[2]
msg <- m$message
if (type %in% c("error", "warning") && !is.null(m$call)) {
msg <- sprintf("In %s: %s", sQuote(paste0(format(m$call), collapse = "")), msg)
}
return(msg)
}

register_handlers_possible <- function() {
for (i in seq_len(sys.nframe())) {
if (identical(sys.function(i), tryCatch) || identical(sys.function(i), withCallingHandlers)) {
return(FALSE)
}
}
return(TRUE) # nocov: impossible to cover because testthat introduces it's own handlers and we want to return FALSE
}
18 changes: 10 additions & 8 deletions R/register_logger.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#'
#' @seealso The package vignettes for more help: `browseVignettes("teal.logger")`.
#'
#' @param namespace (`character(1)` or `NA`)\cr
#' @param namespace (`character(1)` or `NA_character_`)\cr
#' the name of the logging namespace
#' @param layout (`character(1)`)\cr
#' the log layout. Alongside the standard logging variables provided by the `logging` package
Expand All @@ -52,11 +52,12 @@ register_logger <- function(namespace = NA_character_,
layout = NULL,
level = NULL) {
if (!((is.character(namespace) && length(namespace) == 1) || is.na(namespace))) {
stop("namespace argument to register_logger must be a scalar character or NA.")
stop("namespace argument to register_logger must be a single string or NA.")
}

if (is.null(level)) level <- Sys.getenv("TEAL.LOG_LEVEL")
if (is.null(level) || level == "") level <- getOption("teal.log_level", default = "INFO")
if (is.null(level)) {
level <- get_val("TEAL.LOG_LEVEL", "teal.log_level", "INFO")
}

tryCatch(
logger::log_threshold(level, namespace = namespace),
Expand All @@ -69,13 +70,14 @@ register_logger <- function(namespace = NA_character_,
}
)

if (is.null(layout)) layout <- Sys.getenv("TEAL.LOG_LAYOUT")
if (is.null(layout) || layout == "") {
layout <- getOption(
if (is.null(layout)) {
layout <- get_val(
"TEAL.LOG_LAYOUT",
"teal.log_layout",
default = "[{level}] {format(time, \"%Y-%m-%d %H:%M:%OS4\")} pid:{pid} token:[{token}] {ans} {msg}"
"[{level}] {format(time, \"%Y-%m-%d %H:%M:%OS4\")} pid:{pid} token:[{token}] {ans} {msg}"
)
}

tryCatch(
expr = {
logger::log_layout(layout_teal_glue_generator(layout), namespace = namespace)
Expand Down
12 changes: 12 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ log_system_info <- function() {
pasted_names_and_versions <- paste(paste_pkgs_name_with_version(names(info$loadedOnly)), collapse = ", ")
logger::log_trace("Loaded packages: { pasted_names_and_versions }")
}

#' Get value from environmental variable or R option or default in that order if the previous one is missing.
#' @param env_var_name (`character(1)`) name of the system variable
#' @param option_name (`character(1)`) name of the option
#' @param default optional, default value if both `Sys.getenv(env_var_name)` and `getOption(option_name)` are empty
#' @return an object of any class
#' @keywords internal
get_val <- function(env_var_name, option_name, default = NULL) {
value <- Sys.getenv(env_var_name)
if (is.null(value) || value == "") value <- getOption(option_name, default = default)
return(value)
}
4 changes: 4 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# create an object to store the information of registered handlers
registered_handlers_namespaces <- new.env()

.onLoad <- function(libname, pkgname) { # nolint
# Set up the teal logger instance
register_logger("teal.logger")
register_handlers("teal.logger")
invisible()
}
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,19 @@

## Installation

From July 2023 `insightsengineering` packages are available on [r-universe](https://r-universe.dev/).

```r
# stable versions
install.packages('teal.logger', repos = c('https://insightsengineering.r-universe.dev', 'https://cloud.r-project.org'))
install.packages('teal.logger')

# install.packages("pak")
pak::pak("insightsengineering/teal.logger@*release")
```

Alternatively, you might also use the development version.
Alternatively, you might want to use the development version available on [r-universe](https://r-universe.dev/).

```r
# beta versions
install.packages('teal.logger', repos = c('https://pharmaverse.r-universe.dev', 'https://cloud.r-project.org'))
install.packages('teal.logger', repos = c('https://pharmaverse.r-universe.dev', getOption('repos')))

# install.packages("pak")
pak::pak("insightsengineering/teal.logger")
Expand Down Expand Up @@ -85,8 +83,8 @@ If you encounter a bug or you have a feature request - please file an issue. For

### Stargazers

[![Stargazers repo roster for @insightsengineering/teal.logger](https://reporoster.com/stars/insightsengineering/teal.logger)](https://github.com/insightsengineering/teal.logger/stargazers)
[![Stargazers repo roster for @insightsengineering/teal.logger](http://reporoster.com/stars/insightsengineering/teal.logger)](https://github.com/insightsengineering/teal.logger/stargazers)

### Forkers

[![Forkers repo roster for @insightsengineering/teal.logger](https://reporoster.com/forks/insightsengineering/teal.logger)](https://github.com/insightsengineering/teal.logger/network/members)
[![Forkers repo roster for @insightsengineering/teal.logger](http://reporoster.com/forks/insightsengineering/teal.logger)](https://github.com/insightsengineering/teal.logger/network/members)
Binary file modified build/vignette.rds
Binary file not shown.

0 comments on commit 3993d64

Please sign in to comment.