Title: | A Fully Featured Logging Framework |
---|---|
Description: | A flexible, feature-rich yet light-weight logging framework based on 'R6' classes. It supports hierarchical loggers, custom log levels, arbitrary data fields in log events, logging to plaintext, 'JSON', (rotating) files, memory buffers. For extra appenders that support logging to databases, email and push notifications see the the package lgr.app. |
Authors: | Stefan Fleck [aut, cre] |
Maintainer: | Stefan Fleck <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.4.5.9000 |
Built: | 2024-11-07 05:28:11 UTC |
Source: | https://github.com/s-fleck/lgr |
An Appender that Buffers LogEvents in-memory and and redirects them to other Appenders once certain conditions are met.
appenders
, set_appenders()
Like for a Logger. Buffered events will be passed on to these Appenders once a flush is triggered
flush_on_exit, set_flush_on_exit(x)
TRUE
or FALSE
: Whether the
buffer should be flushed when the Appender is garbage collected (f.e when
you close R)
flush_on_rotate, set_flush_on_rotate
TRUE
or FALSE
: Whether
the buffer should be flushed when the Buffer is full (f.e when you close
R). Setting this to off can have slightly negative performance impacts.
lgr::Filterable
-> lgr::Appender
-> lgr::AppenderMemory
-> AppenderBuffer
lgr::Filterable$add_filter()
lgr::Filterable$filter()
lgr::Filterable$remove_filter()
lgr::Filterable$set_filters()
lgr::Appender$set_layout()
lgr::Appender$set_threshold()
lgr::AppenderMemory$append()
lgr::AppenderMemory$set_buffer_size()
lgr::AppenderMemory$set_flush_on_exit()
lgr::AppenderMemory$set_flush_on_rotate()
lgr::AppenderMemory$set_flush_threshold()
lgr::AppenderMemory$set_should_flush()
lgr::AppenderMemory$show()
new()
The Layout for this Appender is used only to format console output of
its $show()
method.
AppenderBuffer$new( threshold = NA_integer_, layout = LayoutFormat$new(fmt = "%L [%t] %m", timestamp_fmt = "%H:%M:%S", colors = getOption("lgr.colors")), appenders = NULL, buffer_size = 1000, flush_threshold = NULL, flush_on_exit = TRUE, flush_on_rotate = TRUE, should_flush = NULL, filters = NULL )
flush()
Sends the buffer's contents to all attached Appenders and then clears the Buffer
AppenderBuffer$flush()
clear()
Clears the buffer, discarding all buffered Events
AppenderBuffer$clear()
set_appenders()
Exactly like A Logger, an AppenderBuffer can have an arbitrary amount of Appenders attached. When the buffer is flushed, the buffered events are dispatched to these Appenders.
AppenderBuffer$set_appenders(x)
x
single Appender or a list
thereof. Appenders control the
output of a Logger. Be aware that a Logger also inherits the Appenders
of its ancestors (see vignette("lgr", package = "lgr")
for more info
about Logger inheritance).
add_appender()
Add an Appender to the AppenderBuffer
Add or remove an Appender. Supplying a name
is optional but
recommended. After adding an Appender with
appender$add_appender(AppenderConsole$new(), name = "console")
you can
refer to it via appender$appenders$console
. remove_appender()
can
remove an Appender by position or name.
AppenderBuffer$add_appender(appender, name = NULL)
appender
a single Appender
name
a character
scalar. Optional but recommended.
remove_appender()
remove an appender
AppenderBuffer$remove_appender(pos)
pos
integer
index or character
name of the Appender(s) to
remove
format()
AppenderBuffer$format(...)
Other Appenders:
Appender
,
AppenderConsole
,
AppenderFile
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
,
AppenderTable
An Appender that outputs to the R console. If you have the package crayon installed log levels will be coloured by default (but you can modify this behaviour by passing a custom Layout).
lgr::Filterable
-> lgr::Appender
-> AppenderConsole
new()
AppenderConsole$new( threshold = NA_integer_, layout = LayoutFormat$new(fmt = "%L [%t] %m %f", timestamp_fmt = "%H:%M:%OS3", colors = getOption("lgr.colors", list())), filters = NULL, connection = NULL )
append()
AppenderConsole$append(event)
set_connection()
AppenderConsole$set_connection(connection)
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderFile
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
,
AppenderTable
# create a new logger with propagate = FALSE to prevent routing to the root # logger. Please look at the section "Logger Hirarchies" in the package # vignette for more info. lg <- get_logger("test")$set_propagate(FALSE) lg$add_appender(AppenderConsole$new()) lg$add_appender(AppenderConsole$new( layout = LayoutFormat$new("[%t] %c(): [%n] %m", colors = getOption("lgr.colors")))) # Will output the message twice because we attached two console appenders lg$warn("A test message") lg$config(NULL) # reset config
# create a new logger with propagate = FALSE to prevent routing to the root # logger. Please look at the section "Logger Hirarchies" in the package # vignette for more info. lg <- get_logger("test")$set_propagate(FALSE) lg$add_appender(AppenderConsole$new()) lg$add_appender(AppenderConsole$new( layout = LayoutFormat$new("[%t] %c(): [%n] %m", colors = getOption("lgr.colors")))) # Will output the message twice because we attached two console appenders lg$warn("A test message") lg$config(NULL) # reset config
A simple Appender that outputs to a file in the file system. If you plan
to log to text files, consider logging to JSON files and take a look at
AppenderJson, which is a shortcut for AppenderFile
preconfigured with
LayoutJson
.
lgr::Filterable
-> lgr::Appender
-> AppenderFile
file
character
scalar. path to the log file
data
data.frame
. Contents of file
parsed to a
data.frame
if used with a Layout that supports parsing of log
file data (notably LayoutJson). Will throw an error if Layout
does
not support parsing.
data
character
scalar. Like $data
, but returns a data.table
instead (requires the data.table package).
new()
AppenderFile$new( file, threshold = NA_integer_, layout = LayoutFormat$new(), filters = NULL )
append()
AppenderFile$append(event)
set_file()
Set a log file
AppenderFile$set_file(file)
file
character
scalar. Path to the log file. If file
does not
exist it will be created.
show()
Display the contents of the log file.
AppenderFile$show(threshold = NA_integer_, n = 20L)
threshold
character
or integer
scalar. The minimum log level
that should be displayed.
n
integer
scalar. Show only the last n
log entries that match
threshold
.
lgr::Filterable
-> lgr::Appender
-> lgr::AppenderFile
-> AppenderJson
new()
AppenderJson$new( file, threshold = NA_integer_, layout = LayoutJson$new(), filters = NULL )
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
,
AppenderTable
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
,
AppenderTable
lg <- get_logger("test") default <- tempfile() fancy <- tempfile() json <- tempfile() lg$add_appender(AppenderFile$new(default), "default") lg$add_appender( AppenderFile$new(fancy, layout = LayoutFormat$new("[%t] %c(): %L %m")), "fancy" ) lg$add_appender( AppenderFile$new(json, layout = LayoutJson$new()), "json" ) lg$info("A test message") readLines(default) readLines(fancy) readLines(json) # cleanup lg$config(NULL) unlink(default) unlink(fancy) unlink(json) tf <- tempfile() lg <- get_logger("test")$ set_appenders(AppenderJson$new(tf))$ set_propagate(FALSE) lg$info("A test message") lg$info("A test message %s strings", "with format strings", and = "custom_fields") lg$appenders[[1]]$show() lg$appenders[[1]]$data # cleanup lg$config(NULL) unlink(tf)
lg <- get_logger("test") default <- tempfile() fancy <- tempfile() json <- tempfile() lg$add_appender(AppenderFile$new(default), "default") lg$add_appender( AppenderFile$new(fancy, layout = LayoutFormat$new("[%t] %c(): %L %m")), "fancy" ) lg$add_appender( AppenderFile$new(json, layout = LayoutJson$new()), "json" ) lg$info("A test message") readLines(default) readLines(fancy) readLines(json) # cleanup lg$config(NULL) unlink(default) unlink(fancy) unlink(json) tf <- tempfile() lg <- get_logger("test")$ set_appenders(AppenderJson$new(tf))$ set_propagate(FALSE) lg$info("A test message") lg$info("A test message %s strings", "with format strings", and = "custom_fields") lg$appenders[[1]]$show() lg$appenders[[1]]$data # cleanup lg$config(NULL) unlink(tf)
Log to a rotating file
Log to a rotating file
An extension of AppenderFile that rotates logfiles based on certain
conditions. Please refer to the documentation of rotor::rotate()
for
the meanings of the extra arguments
lgr::Filterable
-> lgr::Appender
-> lgr::AppenderFile
-> AppenderFileRotating
backups
A data.frame
containing information on path, file size,
etc... on the available backups of file
.
new()
AppenderFileRotating$new( file, threshold = NA_integer_, layout = LayoutFormat$new(), filters = NULL, size = Inf, max_backups = Inf, compression = FALSE, backup_dir = dirname(file), create_file = NULL )
size, max_backups, compression, backup_dir, fmt
see rotor::rotate()
for the meaning of these arguments. Note that
fmt
corresponds to format
and backup_dir
to dir
.
append()
AppenderFileRotating$append(event)
rotate()
AppenderFileRotating$rotate(force = FALSE)
prune()
AppenderFileRotating$prune(max_backups = self$max_backups)
set_file()
AppenderFileRotating$set_file(file)
set_size()
AppenderFileRotating$set_size(x)
set_max_backups()
AppenderFileRotating$set_max_backups(x)
set_compression()
AppenderFileRotating$set_compression(x)
set_create_file()
AppenderFileRotating$set_create_file(x)
set_backup_dir()
AppenderFileRotating$set_backup_dir(x)
format()
AppenderFileRotating$format(color = false, ...)
clone()
The objects of this class are cloneable with this method.
AppenderFileRotating$clone(deep = FALSE)
deep
Whether to make a deep clone.
AppenderFileRotatingDate, AppenderFileRotatingTime, rotor::rotate()
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFile
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
,
AppenderTable
Log to a date-stamped rotating file
Log to a date-stamped rotating file
This is a simpler version of AppenderFileRotatingTime when the timestamps do not need to include sub-day accuracy.
lgr::Filterable
-> lgr::Appender
-> lgr::AppenderFile
-> lgr::AppenderFileRotating
-> AppenderFileRotatingDate
lgr::Filterable$add_filter()
lgr::Filterable$filter()
lgr::Filterable$remove_filter()
lgr::Filterable$set_filters()
lgr::Appender$set_layout()
lgr::Appender$set_threshold()
lgr::AppenderFile$show()
lgr::AppenderFileRotating$append()
lgr::AppenderFileRotating$prune()
lgr::AppenderFileRotating$set_backup_dir()
lgr::AppenderFileRotating$set_compression()
lgr::AppenderFileRotating$set_create_file()
lgr::AppenderFileRotating$set_file()
lgr::AppenderFileRotating$set_max_backups()
lgr::AppenderFileRotating$set_size()
lgr::AppenderFileRotating$format()
lgr::AppenderFileRotating$rotate()
lgr::AppenderFileRotating$set_age()
lgr::AppenderFileRotating$set_cache_backups()
lgr::AppenderFileRotating$set_fmt()
lgr::AppenderFileRotating$set_overwrite()
new()
AppenderFileRotatingDate$new( file, threshold = NA_integer_, layout = LayoutFormat$new(), filters = NULL, age = Inf, size = -1, max_backups = Inf, compression = FALSE, backup_dir = dirname(file), fmt = "%Y-%m-%d", overwrite = FALSE, cache_backups = TRUE, create_file = NULL )
size, age, max_backups, compression, backup_dir, fmt, overwrite, cache_backups
see rotor::rotate_date()
for the meaning of these arguments. Note that
fmt
corresponds to format
(because $format
has a special meaning
for R6 classes).
clone()
The objects of this class are cloneable with this method.
AppenderFileRotatingDate$clone(deep = FALSE)
deep
Whether to make a deep clone.
AppenderFileRotatingTime, AppenderFileRotating, rotor::rotate()
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFile
,
AppenderFileRotating
,
AppenderFileRotatingTime
,
AppenderTable
Log to a time-stamped rotating file
Log to a time-stamped rotating file
lgr::Filterable
-> lgr::Appender
-> lgr::AppenderFile
-> lgr::AppenderFileRotating
-> AppenderFileRotating
cache_backups
TRUE
or FALSE
. If TRUE
(the default) the list of backups is cached,
if FALSE
it is read from disk every time this appender triggers.
Caching brings a significant speedup for checking whether to rotate or
not based on the age
of the last backup, but is only safe if
there are no other programs/functions (except this appender) interacting
with the backups.
lgr::Filterable$add_filter()
lgr::Filterable$filter()
lgr::Filterable$remove_filter()
lgr::Filterable$set_filters()
lgr::Appender$set_layout()
lgr::Appender$set_threshold()
lgr::AppenderFile$show()
lgr::AppenderFileRotating$append()
lgr::AppenderFileRotating$prune()
lgr::AppenderFileRotating$set_backup_dir()
lgr::AppenderFileRotating$set_compression()
lgr::AppenderFileRotating$set_create_file()
lgr::AppenderFileRotating$set_file()
lgr::AppenderFileRotating$set_max_backups()
lgr::AppenderFileRotating$set_size()
new()
AppenderFileRotatingTime$new( file, threshold = NA_integer_, layout = LayoutFormat$new(), filters = NULL, age = Inf, size = -1, max_backups = Inf, compression = FALSE, backup_dir = dirname(file), fmt = "%Y-%m-%d--%H-%M-%S", overwrite = FALSE, cache_backups = TRUE, create_file = NULL )
size, age, max_backups, compression, backup_dir, fmt, overwrite, cache_backups
see rotor::rotate_time()
for the meaning of these arguments. Note that
fmt
corresponds to format
and backup_dir
to dir
.
rotate()
AppenderFileRotatingTime$rotate(force = FALSE, now = Sys.time())
set_age()
AppenderFileRotatingTime$set_age(x)
set_fmt()
AppenderFileRotatingTime$set_fmt(x)
set_overwrite()
AppenderFileRotatingTime$set_overwrite(x)
set_cache_backups()
set the cache_backups
flag.
AppenderFileRotatingTime$set_cache_backups(x)
x
a logical
scalar
format()
AppenderFileRotatingTime$format(color = FALSE, ...)
clone()
The objects of this class are cloneable with this method.
AppenderFileRotatingTime$clone(deep = FALSE)
deep
Whether to make a deep clone.
AppenderFileRotatingDate, AppenderFileRotating, rotor::rotate()
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFile
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderTable
NOTE: This is an abstract class. Abstract classes cannot be instantiated directly, but are exported for package developers that want to extend lgr - for example by creating their own Appenders or Layouts. Please refer to the see also section for actual implementations of this class.
AppenderMemory is extended by Appenders that retain an in-memory event
buffer, such as AppenderBuffer and AppenderPushbullet
from the
lgrExtra package.
lgr::Filterable
-> lgr::Appender
-> AppenderMemory
flush_on_exit
A logical
scalar. Should the buffer be flushed if
the Appender is destroyed (e.g. because the R session is terminated)?
flush_on_rotate
A logical
scalar. Should the buffer be flushed when it is
rotated because $buffer_size
is exceeded?
should_flush
A function
with exactly one arguments: event
.
$append()
calls this function internally on the current LogEvent
and flushes the buffer if it evaluates to TRUE
.
buffer_size
integer
scalar >= 0
. Maximum number of LogEvents
to buffer.
flush_threshold
A numeric
or character
threshold. LogEvents
with a log_level equal to or lower than this threshold trigger
flushing the buffer.
buffer_events
A list
of LogEvents. Contents of the buffer.
buffer_events
A data.frame
. Contents of the buffer converted
to a data.frame
.
buffer_events
A data.frame
. Contents of the buffer converted
to a data.table
.
new()
AppenderMemory$new(...)
append()
AppenderMemory$append(event)
flush()
Sends the buffer's contents to all attached Appenders and then clears the Buffer
AppenderMemory$flush()
clear()
Clears the buffer, discarding all buffered Events
AppenderMemory$clear()
set_buffer_size()
Set the maximum size of the buffer
AppenderMemory$set_buffer_size(x)
x
an integer
scalar >= 0
. Number of LogEvents to buffer.
set_should_flush()
Set function that can trigger flushing the buffer
AppenderMemory$set_should_flush(x)
x
A function
with the single argument event
. Setting x
to
NULL
is a shortcut for function(event) FALSE
. See active bindings.
set_flush_on_exit()
Should the buffer be flushed when the Appender is destroyed?
AppenderMemory$set_flush_on_exit(x)
x
A logical
scalar. See active bindings.
set_flush_on_rotate()
Should the buffer be flushed if buffer_size
is exceeded?
AppenderMemory$set_flush_on_rotate(x)
x
A logical
scalar. See active bindings.
set_flush_threshold()
Set threshold that triggers flushing
AppenderMemory$set_flush_threshold(level)
level
A numeric
or character
threshold. See
active bindings.
show()
Display the contents of the log table. Relies on the
$format_event
method of the Layout attached to this Appender.
AppenderMemory$show(threshold = NA_integer_, n = 20L)
threshold
character
or integer
scalar. The minimum log level
that should be displayed.
n
integer
scalar. Show only the last n
log entries that match
threshold
.
format()
AppenderMemory$format(color = FALSE, ...)
Other abstract classes:
Appender
,
AppenderTable
,
Filterable
NOTE: This is an abstract class. Abstract classes cannot be instantiated directly, but are exported for package developers that want to extend lgr - for example by creating their own Appenders or Layouts. Please refer to the see also section for actual implementations of this class.
AppenderTable is extended by Appenders that write to a data
source that can be interpreted as tables, (usually a data.frame
). Examples
are AppenderDbi
, AppenderRjdbc
and AppenderDt
from the
lgrExtra package.
lgr::Filterable
-> lgr::Appender
-> AppenderTable
data
character
scalar. Contents of the table, parsed to a
data.frame
.
data
character
scalar. Like $data
, but returns a data.table
instead (requires the data.table package).
new()
AppenderTable$new(...)
show()
Show recent log entries
AppenderTable$show(threshold = NA_integer_, n = 20L)
threshold
an integer
or character
threshold.
Only show events with a log level at or below this threshold.
n
a positive integer
scalar. Show at most that many entries
format()
AppenderTable$format(color = FALSE, ...)
Other abstract classes:
Appender
,
AppenderMemory
,
Filterable
Other Appenders:
Appender
,
AppenderBuffer
,
AppenderConsole
,
AppenderFile
,
AppenderFileRotating
,
AppenderFileRotatingDate
,
AppenderFileRotatingTime
Smartly coerce R objects that look like LogEvents to LogEvents. Mainly useful for developing Appenders.
as_LogEvent(x, ...) ## S3 method for class 'list' as_LogEvent(x, ...) ## S3 method for class 'data.frame' as_LogEvent(x, ...)
as_LogEvent(x, ...) ## S3 method for class 'list' as_LogEvent(x, ...) ## S3 method for class 'data.frame' as_LogEvent(x, ...)
x |
any supported R object |
... |
currently ignored |
Note: as_LogEvent.data.frame()
only supports single-row data.frames
a LogEvent
Other docs relevant for extending lgr:
LogEvent
,
event_list()
,
standardize_threshold()
Coerce LogEvents to data.frames
, data.tables
,
or tibbles
.
## S3 method for class 'LogEvent' as.data.frame( x, row.names = NULL, optional = FALSE, stringsAsFactors = FALSE, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = NULL ) as.data.table.LogEvent( x, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = "msg" ) as_tibble.LogEvent( x, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = "msg" )
## S3 method for class 'LogEvent' as.data.frame( x, row.names = NULL, optional = FALSE, stringsAsFactors = FALSE, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = NULL ) as.data.table.LogEvent( x, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = "msg" ) as_tibble.LogEvent( x, ..., box_if = function(.) !(is.atomic(.) && identical(length(.), 1L)), cols_expand = "msg" )
x |
any R object. |
row.names |
|
optional |
currently ignored and only included for compatibility. |
stringsAsFactors |
|
... |
passed on to |
box_if |
a |
cols_expand |
|
data.table::data.table, tibble::tibble
lg <- get_logger("test") lg$info("lorem ipsum") as.data.frame(lg$last_event) lg$info("LogEvents can store any custom log values", df = iris) as.data.frame(lg$last_event) head(as.data.frame(lg$last_event)$df[[1]]) # how boxing works # by default non-scalars are boxed lg$info("letters", letters = letters) as.data.frame(lg$last_event) # this behaviour can be modified by supplying a custom boxing function as.data.frame(lg$last_event, box_if = function(.) FALSE) as.data.frame(lg$last_event, cols_expand = "letters") # The `msg` argument of a log event is always vectorized lg$info(c("a vectorized", "log message")) as.data.frame(lg$last_event) lg$config(NULL)
lg <- get_logger("test") lg$info("lorem ipsum") as.data.frame(lg$last_event) lg$info("LogEvents can store any custom log values", df = iris) as.data.frame(lg$last_event) head(as.data.frame(lg$last_event)$df[[1]]) # how boxing works # by default non-scalars are boxed lg$info("letters", letters = letters) as.data.frame(lg$last_event) # this behaviour can be modified by supplying a custom boxing function as.data.frame(lg$last_event, box_if = function(.) FALSE) as.data.frame(lg$last_event, cols_expand = "letters") # The `msg` argument of a log event is always vectorized lg$info(c("a vectorized", "log message")) as.data.frame(lg$last_event) lg$config(NULL)
A quick and easy way to configure the root logger. This is less powerful
then using lgr$config()
or lgr$set_*()
(see Logger), but reduces the
most common configurations to a single line of code.
basic_config( file = NULL, fmt = "%L [%t] %m", timestamp_fmt = "%Y-%m-%d %H:%M:%OS3", threshold = "info", appenders = NULL, console = if (is.null(appenders)) "all" else FALSE, console_fmt = "%L [%t] %m %f", console_timestamp_fmt = "%H:%M:%OS3", console_connection = NULL, memory = FALSE )
basic_config( file = NULL, fmt = "%L [%t] %m", timestamp_fmt = "%Y-%m-%d %H:%M:%OS3", threshold = "info", appenders = NULL, console = if (is.null(appenders)) "all" else FALSE, console_fmt = "%L [%t] %m %f", console_timestamp_fmt = "%H:%M:%OS3", console_connection = NULL, memory = FALSE )
file |
|
fmt |
|
timestamp_fmt |
see |
threshold |
|
appenders |
a single Appender or a list thereof. |
console |
|
console_fmt |
|
console_timestamp_fmt |
|
console_connection |
see |
memory |
|
the root
Logger (lgr)
# log to a file basic_config(file = tempfile()) unlink(lgr$appenders$file$file) # cleanup basic_config(file = tempfile(fileext = "jsonl")) unlink(lgr$appenders$file$file) # cleanup # log debug messages to a memory buffer basic_config(threshold = "all", memory = "all", console = "info") lgr$info("an info message") lgr$debug("a hidden message") show_log() # reset to default config basic_config()
# log to a file basic_config(file = tempfile()) unlink(lgr$appenders$file$file) # cleanup basic_config(file = tempfile(fileext = "jsonl")) unlink(lgr$appenders$file$file) # cleanup # log debug messages to a memory buffer basic_config(threshold = "all", memory = "all", console = "info") lgr$info("an info message") lgr$debug("a hidden message") show_log() # reset to default config basic_config()
Logger Error Conditions
CannotInitializeAbstractClassError(class = parent.frame(2)[["classes"]])
CannotInitializeAbstractClassError(class = parent.frame(2)[["classes"]])
class |
|
a condition object
Colorize Levels
colorize_levels( x, colors = getOption("lgr.colors", NULL), transform = identity )
colorize_levels( x, colors = getOption("lgr.colors", NULL), transform = identity )
x |
|
colors |
A |
transform |
a |
a character
vector wit color ANSI codes
Other formatting utils:
label_levels()
cat(colorize_levels(c(100, 200))) cat(colorize_levels(c("trace", "warn ", "DEBUG"))) cat(colorize_levels(c("trace", "warn ", "DEBUG"), transform = function(x) strtrim(x, 1) ))
cat(colorize_levels(c(100, 200))) cat(colorize_levels(c("trace", "warn ", "DEBUG"))) cat(colorize_levels(c("trace", "warn ", "DEBUG"), transform = function(x) strtrim(x, 1) ))
Throws a timestamped warning instead of stopping the program. This is the default exception handler used by Loggers.
default_exception_handler(e)
default_exception_handler(e)
e |
an |
The warning as character
vector
tryCatch(stop("an error has occurred"), error = default_exception_handler)
tryCatch(stop("an error has occurred"), error = default_exception_handler)
An event_list is a class for list()
s whose only elements are LogEvents.
This structure is occasionally used internally in lgr (for example by
AppenderBuffer) and can be useful for developers that want to write
their own Appenders.
event_list(...) as_event_list(x, ...) ## S3 method for class 'list' as_event_list(x, ..., scalarize = FALSE) ## S3 method for class 'LogEvent' as_event_list(x, ..., scalarize = FALSE) ## S3 method for class 'data.frame' as_event_list(x, na.rm = TRUE, ...) as.data.table.event_list(x, na.rm = TRUE) ## S3 method for class 'event_list' as.data.frame( x, row.names = NULL, optional = FALSE, stringsAsFactors = FALSE, na.rm = TRUE, ... )
event_list(...) as_event_list(x, ...) ## S3 method for class 'list' as_event_list(x, ..., scalarize = FALSE) ## S3 method for class 'LogEvent' as_event_list(x, ..., scalarize = FALSE) ## S3 method for class 'data.frame' as_event_list(x, na.rm = TRUE, ...) as.data.table.event_list(x, na.rm = TRUE) ## S3 method for class 'event_list' as.data.frame( x, row.names = NULL, optional = FALSE, stringsAsFactors = FALSE, na.rm = TRUE, ... )
... |
for |
x |
any |
scalarize |
|
na.rm |
remove |
row.names |
|
optional |
currently ignored and only included for compatibility. |
stringsAsFactors |
|
For convenience, as.data.frame()
and as.data.table()
methods
exist for event lists.
an event_list()
and as_event_list()
return a flat list
of LogEvents. Nested lists get automatically flattened.
as.data.frame
and as.data.table
return a data.frame
or data.table
respectively
Other docs relevant for extending lgr:
LogEvent
,
as_LogEvent()
,
standardize_threshold()
e <- LogEvent$new(level = 300, msg = "a", logger = lgr) as_event_list(e) as_event_list(c(e, e)) # nested lists get automatically unnested as_event_list(c(e, list(nested_event = e))) # scalarize = TRUE "unpacks" events with vector log messages e <- LogEvent$new(level = 300, msg = c("A", "B"), logger = lgr) as_event_list(e, scalarize = FALSE) as_event_list(e, scalarize = TRUE)
e <- LogEvent$new(level = 300, msg = "a", logger = lgr) as_event_list(e) as_event_list(c(e, e)) # nested lists get automatically unnested as_event_list(c(e, list(nested_event = e))) # scalarize = TRUE "unpacks" events with vector log messages e <- LogEvent$new(level = 300, msg = c("A", "B"), logger = lgr) as_event_list(e, scalarize = FALSE) as_event_list(e, scalarize = TRUE)
EventFilters specify arbitrarily complex logic for whether or
not a LogEvent should be processed by a Logger or Appender. They are
attached to Loggers/Appenders via their $set_filter()
or $add_filter()
methods. If any EventFilter evaluates to FALSE
for a given event, that
event is ignored - similarly to when it does not pass the objects'
threshold.
Usually you do not need to instantiate a formal EventFilter
object as you
can just use any function
that has the single argument event
instead.
If you need to implement more complex filter logic - for example a filter
that is dependent on a dataset - it might be desirable to subclass
EventFilter, as R6::R6 objects can store data and functions together.
.obj()
is a special function that can only be used within the
$filter()
methods of EventFilters. It returns the Logger
or Appender that the EventFilter is attached to.
.obj()
.obj()
Since LogEvents are R6 objects with reference semantics, EventFilters can be
abused to modify events before passing them on. lgr comes with a few
preset filters that use this property: FilterInject (similar to
with_log_level()
) and FilterForceLevel (similar to with_log_value()
).
NOTE: The base class for Filters is called EventFilter
so that it
doesn't conflict with base::Filter()
. The recommended convention for
Filter subclasses is to call them FilterSomething
and leave out the
Event
prefix.
new()
Initialize a new EventFilter
EventFilter$new(fun = function(event) TRUE)
fun
a function
with a single argument event
that must return
either TRUE
or FALSE
. Any non-FALSE
will be interpreted as
TRUE
(= no filtering takes place) and a warning will be thrown.
clone()
The objects of this class are cloneable with this method.
EventFilter$clone(deep = FALSE)
deep
Whether to make a deep clone.
lg <- get_logger("test") f <- function(event) { cat("via event$.logger:", event$.logger$threshold, "\n") # works for loggers only cat("via .obj(): ",.obj()$threshold, "\n") # works for loggers and appenders TRUE } lg$add_filter(f) lg$fatal("test") lg$config(NULL)
lg <- get_logger("test") f <- function(event) { cat("via event$.logger:", event$.logger$threshold, "\n") # works for loggers only cat("via .obj(): ",.obj()$threshold, "\n") # works for loggers and appenders TRUE } lg$add_filter(f) lg$fatal("test") lg$config(NULL)
Superclass for classes that have a $filter()
method such as
Appenders and Loggers. See EventFilter for details.
NOTE: This is an abstract class. Abstract classes cannot be instantiated directly, but are exported for package developers that want to extend lgr - for example by creating their own Appenders or Layouts. Please refer to the see also section for actual implementations of this class.
filters
a list
of all attached Filters.
filter()
Determine whether the LogEvent x
should be passed on to
Appenders (TRUE
) or not (FALSE
). See also the active binding
filters
.
Filterable$filter(event)
event
a LogEvent
add_filter()
Attach a filter
Filterable$add_filter(filter, name = NULL)
filter
a function with the single argument event
that returns TRUE
or FALSE
;
an EventFilter R6::R6 object; or
any R object with a $filter()
method.
If a Filter returns a non-FALSE
value, will be interpreted as TRUE
(= no filtering takes place) and a warning will be thrown.
name
character
scalar or NULL
. An optional
name which makes it easier to access (or remove) the filter
remove_filter()
Remove a filter
Filterable$remove_filter(pos)
pos
character
or integer
scalar. The name or index of the
Filter to be removed.
set_filters()
Set or replace (all) Filters of parent object. See EventFilter for how Filters work.
Filterable$set_filters(filters)
filters
a list
(named or unnamed) of EventFilters
or predicate functions. See is_filter()
.
Other abstract classes:
Appender
,
AppenderMemory
,
AppenderTable
Overrides the log level of the Appender/Logger that this filter
is attached to to with level
. See also with_log_level()
. It is
recommended to use filters that modify LogEvents only with Loggers, but
they will also work with Appenders.
lgr::EventFilter
-> FilterForceLevel
new()
Initialize a new FilterForceLevel
FilterForceLevel$new(level)
level
an integer
or character
log level
clone()
The objects of this class are cloneable with this method.
FilterForceLevel$clone(deep = FALSE)
deep
Whether to make a deep clone.
lg <- get_logger("test") analyse <- function(){ lg$add_filter(FilterForceLevel$new("info"), "force") on.exit(lg$remove_filter("force")) lg$error("an error with forced log level INFO") } analyse() lg$error("an normal error") lg$config(NULL) # reset config
lg <- get_logger("test") analyse <- function(){ lg$add_filter(FilterForceLevel$new("info"), "force") on.exit(lg$remove_filter("force")) lg$error("an error with forced log level INFO") } analyse() lg$error("an normal error") lg$config(NULL) # reset config
Inject arbitrary values into all LogEvents processed by a Logger/Appender. It is recommended to use filters that modify LogEvents only with Loggers, but they will also work with Appenders.
lgr::EventFilter
-> FilterInject
values
a named list
of values to be injected into each
LogEvent processed by this filter
new()
Initialize a new FilterInject
FilterInject$new(..., .list = list())
..., .list
any number of named R objects that will be injected as
custom fields into all LogEvents processed by the
Appender/Logger that this filter is attached to. See also
with_log_value()
.
clone()
The objects of this class are cloneable with this method.
FilterInject$clone(deep = FALSE)
deep
Whether to make a deep clone.
lg <- get_logger("test") analyse <- function(){ lg$add_filter(FilterInject$new(type = "analysis"), "inject") on.exit(lg$remove_filter("inject")) lg$error("an error with forced custom 'type'-field") } analyse() lg$error("an normal error") lg$config(NULL) # reset config
lg <- get_logger("test") analyse <- function(){ lg$add_filter(FilterInject$new(type = "analysis"), "inject") on.exit(lg$remove_filter("inject")) lg$error("an error with forced custom 'type'-field") } analyse() lg$error("an normal error") lg$config(NULL) # reset config
get_caller()
Tries to determine the calling functions based on where
.
get_caller(where = -1L) get_user(fallback = "unknown user")
get_caller(where = -1L) get_user(fallback = "unknown user")
where |
|
fallback |
A fallback in case the user name could not be determined |
a character
scalar.
foo <- function() get_caller(-1L) foo() get_user()
foo <- function() get_caller(-1L) foo() get_user()
Display, add and remove character labels for log levels.
get_log_levels() add_log_levels(levels) remove_log_levels(level_names)
get_log_levels() add_log_levels(levels) remove_log_levels(level_names)
levels |
a named |
level_names |
a |
a named character
vector of the globally available log levels
(add_log_levels()
and remove_log_levels()
return invisibly).
lgr comes with the following predefined log levels that are identical to the log levels of log4j.
Level | Name | Description |
0 |
off | A log level of 0/off tells a Logger or Appender to suspend all logging |
100 |
fatal | Critical error that leads to program abort. Should always indicate a stop() or similar |
200 |
error | A severe error that does not trigger program abort |
300 |
warn | A potentially harmful situation, like warning()
|
400 |
info | An informational message on the progress of the application |
500 |
debug | Finer grained informational messages that are mostly useful for debugging |
600 |
trace | An even finer grained message than debug |
NA |
all | A log level of NA/all tells a Logger or Appender to process all log events |
get_log_levels() add_log_levels(c(errorish = 250)) get_log_levels() remove_log_levels("errorish") get_log_levels()
get_log_levels() add_log_levels(c(errorish = 250)) get_log_levels() remove_log_levels("errorish") get_log_levels()
Get/Create a Logger
get_logger(name, class = Logger, reset = FALSE) get_logger_glue(name)
get_logger(name, class = Logger, reset = FALSE) get_logger_glue(name)
name |
a |
class |
An R6ClassGenerator object. Usually |
reset |
a |
a Logger
lg <- get_logger("log/ger/test") # equivalent to lg <- get_logger(c("log", "ger", "test")) lg$warn("a %s message", "warning") lg lg$parent if (requireNamespace('glue')){ lg <- get_logger_glue("log/ger") } lg$warn("a {.text} message", .text = "warning") # completely reset 'glue' to an unconfigured vanilla Logger get_logger("log/ger", reset = TRUE) # WARNING: this invalidates existing references to the Logger try(lg$info("lg has been invalidated an no longer works")) lg <- get_logger("log/ger") lg$info("now all is well again")
lg <- get_logger("log/ger/test") # equivalent to lg <- get_logger(c("log", "ger", "test")) lg$warn("a %s message", "warning") lg lg$parent if (requireNamespace('glue')){ lg <- get_logger_glue("log/ger") } lg$warn("a {.text} message", .text = "warning") # completely reset 'glue' to an unconfigured vanilla Logger get_logger("log/ger", reset = TRUE) # WARNING: this invalidates existing references to the Logger try(lg$info("lg has been invalidated an no longer works")) lg <- get_logger("log/ger") lg$info("now all is well again")
Returns TRUE
for any R object that can be used as a Filter
for Loggers or, Appenders:
a function
with the single argument event
;
an EventFilter R6::R6 object; or
any object with a $filter(event)
method.
Note: A Filter must return a scalar TRUE
or FALSE
, but this
property cannot be checked by is_filter()
.
is_filter(x)
is_filter(x)
x |
any R Object |
TRUE
or FALSE
Label/Unlabel Log Levels
label_levels(levels, log_levels = getOption("lgr.log_levels")) unlabel_levels(labels, log_levels = getOption("lgr.log_levels"))
label_levels(levels, log_levels = getOption("lgr.log_levels")) unlabel_levels(labels, log_levels = getOption("lgr.log_levels"))
levels |
an |
log_levels |
named |
labels |
a |
a character
vector for label_levels()
and an integer vector for
unlabel_levels
Other formatting utils:
colorize_levels()
x <- label_levels(c(seq(0, 600, by = 100), NA)) print(x) unlabel_levels(x)
x <- label_levels(c(seq(0, 600, by = 100), NA)) print(x) unlabel_levels(x)
Abstract Class for Layouts
Abstract Class for Layouts
Appenders pass LogEvents to a Layout which formats it for
output. For the Layouts included in lgr that means turning the LogEvent
into a character
string.
For each Appender exist one more more possible Layouts, but not every Layout
will work with every Appender. See the package lgrExtra for examples
for Layouts that return different data types (such as data.frames
) and
Appenders that can handle them.
Layouts may have an additional $read(file, threshold, n)
method that returns
a character
vector, and/or an $parse(file)
method that
returns a data.frame
. These can be used by Appenders to $show()
methods
and $data
active bindings respectively (see source code of AppenderFile).
format_event()
Format a log event
Function that the Layout uses to transform a LogEvent into something that an Appender can write to an output destination.
Layout$format_event(event)
event
a LogEvent
toString()
Layout$toString()
clone()
The objects of this class are cloneable with this method.
Layout$clone(deep = FALSE)
deep
Whether to make a deep clone.
Other Layouts:
LayoutFormat
,
LayoutGlue
,
LayoutJson
Format Log Events as Text
Format Log Events as Text
Format a LogEvent as human readable text using format.LogEvent()
, which
provides a quick and easy way to customize log messages. If you need
more control and flexibility, consider using LayoutGlue instead.
see Fields
see Fields
see Fields
see Fields
Convert Layout to a character
string
Read a log file written using LayoutFormat
This is the same list of format tokens as for format.LogEvent()
%t
The timestamp of the message, formatted according to
timestamp_fmt
)
%l
the log level, lowercase character
representation
%L
the log level, uppercase character
representation
%k
the log level, first letter of lowercase character
representation
%K
the log level, first letter of uppercase character
representation
%n
the log level, integer
representation
%g
the name of the logger
%p
the PID (process ID). Useful when logging code that uses multiple threads.
%c
the calling function
%m
the log message
%f
all custom fields of x
in a pseudo-JSON like format that is
optimized for human readability and console output
%j
all custom fields of x
in proper JSON. This requires that you
have jsonlite installed and does not support colors as opposed to
%f
lgr::Layout
-> LayoutFormat
fmt
a character
scalar containing format tokens. See format.LogEvent()
.
timestamp_fmt
a character
scalar. See base::format.POSIXct()
.
colors
a named list
of functions (like the ones provided by
the package crayon) passed on on format.LogEvent()
.
pad_levels
"right"
, "left"
or NULL
. See format.LogEvent()
.
new()
LayoutFormat$new( fmt = "%L [%t] %m %j", timestamp_fmt = "%Y-%m-%d %H:%M:%OS3", colors = NULL, pad_levels = "right" )
format_event()
Format a LogEvent
LayoutFormat$format_event(event)
event
a LogEvent
set_fmt()
LayoutFormat$set_fmt(x)
set_timestamp_fmt()
LayoutFormat$set_timestamp_fmt(x)
set_colors()
LayoutFormat$set_colors(x)
set_pad_levels()
LayoutFormat$set_pad_levels(x)
toString()
LayoutFormat$toString()
read()
LayoutFormat$read(file, threshold = NA_integer_, n = 20L)
threshold
a character
or integer
threshold
n
number of log entries to display
clone()
The objects of this class are cloneable with this method.
LayoutFormat$clone(deep = FALSE)
deep
Whether to make a deep clone.
Other Layouts:
Layout
,
LayoutGlue
,
LayoutJson
# setup a dummy LogEvent event <- LogEvent$new( logger = Logger$new("dummy logger"), level = 200, timestamp = Sys.time(), caller = NA_character_, msg = "a test message" ) lo <- LayoutFormat$new() lo$format_event(event)
# setup a dummy LogEvent event <- LogEvent$new( logger = Logger$new("dummy logger"), level = 200, timestamp = Sys.time(), caller = NA_character_, msg = "a test message" ) lo <- LayoutFormat$new() lo$format_event(event)
Format a LogEvent as human readable text using glue::glue. The function is evaluated in an environment in which it has access to all elements of the LogEvent (see examples). This is more flexible than LayoutFormat, but also more complex and slightly less performant.
lgr::Layout
-> LayoutGlue
fmt
A string that will be interpreted by glue::glue()
new()
LayoutGlue$new( fmt = "{pad_right(colorize_levels(toupper(level_name)), 5)} [{timestamp}] {msg}" )
format_event()
LayoutGlue$format_event(event)
set_fmt()
LayoutGlue$set_fmt(x)
set_colors()
LayoutGlue$set_colors(x)
toString()
LayoutGlue$toString()
clone()
The objects of this class are cloneable with this method.
LayoutGlue$clone(deep = FALSE)
deep
Whether to make a deep clone.
lgr exports a number of formatting utility functions that are
useful for layout glue: colorize_levels()
, pad_left()
, pad_right()
.
Other Layouts:
Layout
,
LayoutFormat
,
LayoutJson
lg <- get_logger("test")$ set_appenders(AppenderConsole$new())$ set_propagate(FALSE) lg$appenders[[1]]$set_layout(LayoutGlue$new()) lg$fatal("test") # All fields of the LogEvent are available, even custom ones lg$appenders[[1]]$layout$set_fmt( "{logger} {level_name}({level}) {caller}: {toupper(msg)} {{custom: {custom}}}" ) lg$fatal("test", custom = "foobar") lg$config(NULL) # reset logger config
lg <- get_logger("test")$ set_appenders(AppenderConsole$new())$ set_propagate(FALSE) lg$appenders[[1]]$set_layout(LayoutGlue$new()) lg$fatal("test") # All fields of the LogEvent are available, even custom ones lg$appenders[[1]]$layout$set_fmt( "{logger} {level_name}({level}) {caller}: {toupper(msg)} {{custom: {custom}}}" ) lg$fatal("test", custom = "foobar") lg$config(NULL) # reset logger config
A format for formatting LogEvents as jsonlines log files. This provides a nice balance between human- an machine-readability.
lgr::Layout
-> LayoutJson
toJSON_args
a list of values passed on to jsonlite::toJSON()
timestamp_fmt
Used by $format_event()
to format timestamps.
new()
LayoutJson$new(toJSON_args = list(auto_unbox = TRUE), timestamp_fmt = NULL)
format_event()
LayoutJson$format_event(event)
set_toJSON_args()
Set arguments to pass on to jsonlite::toJSON()
LayoutJson$set_toJSON_args(x)
x
a named list
set_timestamp_fmt()
Set a format that this Layout will apply to timestamps.
LayoutJson$set_timestamp_fmt(x)
x
NULL
(the default): formatting of the timestamp is left to
jsonlite::toJSON()
,
a character
scalar as for format.POSIXct()
, or
a function
that returns a vector of the same length as its
(POSIXct) input. The returned vector can be of any type
supported by jsonlite::toJSON()
, but should usually be character
.
toString()
LayoutJson$toString()
parse()
LayoutJson$parse(file)
read()
LayoutJson$read(file, threshold = NA_integer_, n = 20L)
clone()
The objects of this class are cloneable with this method.
LayoutJson$clone(deep = FALSE)
deep
Whether to make a deep clone.
read_json_lines()
, https://jsonlines.org/
Other Layouts:
Layout
,
LayoutFormat
,
LayoutGlue
# setup a dummy LogEvent event <- LogEvent$new( logger = Logger$new("dummy logger"), level = 200, timestamp = Sys.time(), caller = NA_character_, msg = "a test message", custom_field = "LayoutJson can handle arbitrary fields" ) # Default settings show all event fals lo <- LayoutJson$new() lo$format_event(event)
# setup a dummy LogEvent event <- LogEvent$new( logger = Logger$new("dummy logger"), level = 200, timestamp = Sys.time(), caller = NA_character_, msg = "a test message", custom_field = "LayoutJson can handle arbitrary fields" ) # Default settings show all event fals lo <- LayoutJson$new() lo$format_event(event)
A LogEvent
is a single unit of data that should be logged. LogEvents
are
usually created by a Logger, and then processed by one more Appenders.
They do not need to be instantiated manually except for testing and
experimentation; however, if you plan on writing your own Appenders or
Layouts you need to understand LogEvents.
level
integer
. The log_level / priority of the LogEvent. Use the
active binding level_name
to get the character
representation
instead.
timestamp
POSIXct
. The time when then the
LogEvent was created.
caller
character
. The name of the calling function.
msg
character
. The log message.
.logger
Logger. A reference to the Logger that created the
event (equivalent to get_logger(event$logger)
).
values
list
. All values stored in the LogEvent
, including
all custom fields, but not including event$.logger
.
level_name
character
. The log_level / priority of the LogEvent labelled
according to getOption("lgr.log_levels")
logger
character
scalar. The name of the Logger that
created this event, equivalent to event$.logger$name
)
new()
The arguments to LogEvent$new()
directly translate to the fields stored
in the LogEvent
. Usually these values will be scalars, but (except for
"logger"
) they can also be vectors if they are all of the same length (or
scalars that will be recycled). In this case the event will be treated by
the Appenders and Layouts as if several separate events.
LogEvent$new( logger, level = 400, timestamp = Sys.time(), caller = NA, msg = NA, ... )
logger, level, timestamp, caller, msg
see Public fields.
...
All named arguments in ...
will be added to the LogEvent
as custom fields. You can store arbitrary R objects in LogEvents
this way, but not all Appenders will support them. See AppenderJson for
clone()
The objects of this class are cloneable with this method.
LogEvent$clone(deep = FALSE)
deep
Whether to make a deep clone.
Other docs relevant for extending lgr:
as_LogEvent()
,
event_list()
,
standardize_threshold()
lg <- get_logger("test") lg$error("foo bar") # The last LogEvent produced by a Logger is stored in its `last_event` field lg$last_event # formatted console output lg$last_event$values # values stored in the event # Also contains the Logger that created it as .logger lg$last_event$logger # equivalent to lg$last_event$.logger$name # This is really a reference to the complete Logger, so the following is # possible (though nonsensical) lg$last_event$.logger$last_event$msg identical(lg, lg$last_event$.logger) lg$config(NULL) # reset logger config
lg <- get_logger("test") lg$error("foo bar") # The last LogEvent produced by a Logger is stored in its `last_event` field lg$last_event # formatted console output lg$last_event$values # values stored in the event # Also contains the Logger that created it as .logger lg$last_event$logger # equivalent to lg$last_event$.logger$name # This is really a reference to the complete Logger, so the following is # possible (though nonsensical) lg$last_event$.logger$last_event$msg identical(lg, lg$last_event$.logger) lg$config(NULL) # reset logger config
A Logger produces a LogEvent that contains a log message along with
metadata (timestamp, calling function, ...) and dispatches it to one or
more Appenders which are responsible for the output (console, file, ...)
of the event. lgr comes with a single pre-configured Logger called the
root Logger
that can be accessed via lgr$<...>
. Instantiation of new
Loggers is done with get_logger()
. It is advisable to instantiate a
separate Logger with a descriptive name for each package/script in which
you use lgr.
lgr::Filterable
-> Logger
name
A character
scalar. The unique name of each logger,
which also includes the names of its ancestors (separated by /
).
threshold
integer
scalar. The threshold of the Logger
, or if it
NULL
the threshold it inherits from its closest ancestor with a
non-NULL
threshold
propagate
A TRUE
or FALSE
. Should a Logger propagate events
to the Appenders of its ancestors?
ancestry
A named logical
vector of containing the propagate value
of each Logger upper the inheritance tree. The names are the names of
the appenders. ancestry
is an S3 class with a custom
format()
/print()
method, so if you want to use the plain logical
vector use unclass(lg$ancestry)
parent
a Logger
. The direct ancestor of the Logger
.
last_event
The last LogEvent produced by the current Logger
appenders
a list
of all Appenders of the Logger
inherited_appenders
A list
of all appenders that the Logger
inherits from its ancestors
exception_handler
a function
. See $set_exception_handler
and
$handle_exception
new()
Loggers should never be instantiated directly with Logger$new()
but
rather via get_logger("name")
. This way new Loggers are
registered in a global namespace which ensures uniqueness and
facilitates inheritance between Loggers. If "name"
does not exist, a
new Logger with that name will be created, otherwise the function returns
a Reference to the existing Logger.
name
is potentially a "/"
separated hierarchical value like
foo/bar/baz
. Loggers further down the hierarchy are descendants of the
loggers above and (by default) inherit threshold
and Appenders
from
their ancestors.
Logger$new( name = "(unnamed logger)", appenders = list(), threshold = NULL, filters = list(), exception_handler = default_exception_handler, propagate = TRUE )
name, appenders, threshold, filters, exception_handler, propagate
See section Active bindings.
log()
Log an event.
If level
passes the Logger's threshold
a new LogEvent with level
,
msg
, timestamp
and caller
is created. If the new LogEvent also
passes the Loggers Filters, it is be dispatched to the
relevant Appenders.
Logger$log(level, msg, ..., timestamp = Sys.time(), caller = get_caller(-7))
level
a character
or integer
scalar. See log_levels.
msg
character
. A log message. If unnamed arguments are supplied
in ...
, msg
is passed on to base::sprintf()
(which means "%"
have
to be escaped), otherwise msg
is left as-is.
...
unnamed arguments in ...
must be character
scalars and
are passed to base::sprintf()
. Named arguments must have unique names
but can be arbitrary R objects that are passed to LogEvent$new()
and
will be turned into custom fields.
timestamp
POSIXct. Timestamp of the event.
caller
a character
scalar. The name of the calling function.
fatal()
Log an Event fatal priority
Logger$fatal(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
error()
Log an Event error priority
Logger$error(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
warn()
Log an Event warn priority
Logger$warn(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
info()
Log an Event info priority
Logger$info(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
debug()
Log an Event debug priority
Logger$debug(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
trace()
Log an Event trace priority
Logger$trace(msg, ..., caller = get_caller(-8L))
msg, ..., caller
see $log()
list_log()
list_log()
is a shortcut for do.call(Logger$log, x)
.
See https://github.com/s-fleck/joblog for an R package that
leverages this feature to create custom log event types for tracking
the status of cron jobs.
Logger$list_log(x)
x
a named list
that must at least contain the named elements
level
and timestamp
lg <- get_logger("test") lg$list_log(list(level = 400, msg = "example"))
config()
Load a Logger configuration.
Logger$config(cfg, file, text, list)
cfg
a special list
object with any or all of the the following elements:
appenders
, threshold
, filters
, propagate
, exception_handler
,
the path to a YAML
/JSON
config file,
a character
scalar containing YAML/JSON
,
NULL
(to reset the logger config to the default/unconfigured state)
file, text, list
can be used as an alternative to
cfg
that enforces that the supplied argument is of the specified
type. See logger_config for details.
add_appender()
Add an Appender to the Logger
Logger$add_appender(appender, name = NULL)
appender
a single Appender
name
a character
scalar. Optional but recommended.
lg <- get_logger("test") lg$add_appender(AppenderConsole$new(), name = "myconsole") lg$appenders[[1]] lg$appenders$myconsole lg$remove_appender("myconsole") lg$config(NULL) # reset config
remove_appender()
remove an appender
Logger$remove_appender(pos)
pos
integer
index or character
name of the Appender(s) to
remove
handle_exception()
To prevent errors in the logging logic from crashing the whole script,
Loggers pass errors they encounter to an exception handler. The default
behaviour is to demote errors to warnings. See also
set_exception_handler()
.
Logger$handle_exception(expr)
expr
expression to be evaluated.
set_exception_handler()
Set the exception handler of a logger
Logger$set_exception_handler(fun)
fun
a function
with the single argument e
(an error condition)
lgr$info(stop("this produces a warning instead of an error"))
set_propagate()
Should a Logger propagate events to the Appenders of its ancestors?
Logger$set_propagate(x)
x
TRUE
or FALSE
. Should LogEvents be passed on to the appenders
of the ancestral Loggers?
set_threshold()
Set the minimum log level of events that a Logger should process
Logger$set_threshold(level)
level
character
or integer
scalar. The minimum
log level that triggers this Logger
set_appenders()
Set the Logger's Appenders
Logger$set_appenders(x)
x
single Appender or a list
thereof. Appenders control the
output of a Logger. Be aware that a Logger also inherits the Appenders
of its ancestors (see vignette("lgr", package = "lgr")
for more info
about Logger inheritance).
spawn()
Spawn a child Logger.
This is very similar to using get_logger()
, but
can be useful in some cases where Loggers are created programmatically
Logger$spawn(name)
name
character
vector. Name of the child logger
get_logger("foo/bar")$spawn("baz")
is equivalent
to get_logger("foo/bar/baz")
If you are a package developer you should define a new Logger for each package, but you do not need to configure it. The user of the package should decide how and where to output logging, usually by configuring the root Logger (new Appenders added/removed, Layouts modified, etc...).
# lgr::lgr is the root logger that is always available lgr$info("Today is a good day") lgr$fatal("This is a serious error") # Loggers use sprintf() for string formatting by default lgr$info("Today is %s", Sys.Date() ) # If no unnamed `...` are present, msg is not passed through sprintf() lgr$fatal("100% bad") # so this works lgr$fatal("%s%% bad", 100) # if you use unnamed arguments, you must escape % # You can create new loggers with get_logger() tf <- tempfile() lg <- get_logger("mylogger")$set_appenders(AppenderFile$new(tf)) # The new logger passes the log message on to the appenders of its parent # logger, which is by default the root logger. This is why the following # writes not only the file 'tf', but also to the console. lg$fatal("blubb") readLines(tf) # This logger's print() method depicts this relationship. child <- get_logger("lg/child") print(child) print(child$name) # use formatting strings and custom fields tf2 <- tempfile() lg$add_appender(AppenderFile$new(tf2, layout = LayoutJson$new())) lg$info("Not all %s support custom fields", "appenders", type = "test") cat(readLines(tf), sep = "\n") cat(readLines(tf2), sep = "\n") # cleanup unlink(c(tf, tf2)) lg$config(NULL) # reset logger config # LoggerGlue # You can also create a new logger that uses the awesome glue library for # string formatting instead of sprintf if (requireNamespace("glue")){ lg <- get_logger_glue("glue") lg$fatal("blah ", "fizz is set to: {fizz}", foo = "bar", fizz = "buzz") # prevent creation of custom fields with prefixing a dot lg$fatal("blah ", "fizz is set to: {.fizz}", foo = "bar", .fizz = "buzz") #' # completely reset 'glue' to an unconfigured vanilla Logger get_logger("glue", reset = TRUE) } # Configuring a Logger lg <- get_logger("test") lg$config(NULL) # resets logger to unconfigured state # With setters lg$ set_threshold("error")$ set_propagate(FALSE)$ set_appenders(AppenderConsole$new(threshold = "info")) lg$config(NULL) # With a list lg$config(list( threshold = "error", propagate = FALSE, appenders = list(AppenderConsole$new(threshold = "info")) )) lg$config(NULL) # resets logger to unconfigured state # Via YAML cfg <- " Logger: threshold: error propagate: false appenders: AppenderConsole: threshold: info " lg$config(cfg) lg$config(NULL) ## ------------------------------------------------ ## Method `Logger$list_log` ## ------------------------------------------------ lg <- get_logger("test") lg$list_log(list(level = 400, msg = "example")) ## ------------------------------------------------ ## Method `Logger$add_appender` ## ------------------------------------------------ lg <- get_logger("test") lg$add_appender(AppenderConsole$new(), name = "myconsole") lg$appenders[[1]] lg$appenders$myconsole lg$remove_appender("myconsole") lg$config(NULL) # reset config ## ------------------------------------------------ ## Method `Logger$set_exception_handler` ## ------------------------------------------------ lgr$info(stop("this produces a warning instead of an error"))
# lgr::lgr is the root logger that is always available lgr$info("Today is a good day") lgr$fatal("This is a serious error") # Loggers use sprintf() for string formatting by default lgr$info("Today is %s", Sys.Date() ) # If no unnamed `...` are present, msg is not passed through sprintf() lgr$fatal("100% bad") # so this works lgr$fatal("%s%% bad", 100) # if you use unnamed arguments, you must escape % # You can create new loggers with get_logger() tf <- tempfile() lg <- get_logger("mylogger")$set_appenders(AppenderFile$new(tf)) # The new logger passes the log message on to the appenders of its parent # logger, which is by default the root logger. This is why the following # writes not only the file 'tf', but also to the console. lg$fatal("blubb") readLines(tf) # This logger's print() method depicts this relationship. child <- get_logger("lg/child") print(child) print(child$name) # use formatting strings and custom fields tf2 <- tempfile() lg$add_appender(AppenderFile$new(tf2, layout = LayoutJson$new())) lg$info("Not all %s support custom fields", "appenders", type = "test") cat(readLines(tf), sep = "\n") cat(readLines(tf2), sep = "\n") # cleanup unlink(c(tf, tf2)) lg$config(NULL) # reset logger config # LoggerGlue # You can also create a new logger that uses the awesome glue library for # string formatting instead of sprintf if (requireNamespace("glue")){ lg <- get_logger_glue("glue") lg$fatal("blah ", "fizz is set to: {fizz}", foo = "bar", fizz = "buzz") # prevent creation of custom fields with prefixing a dot lg$fatal("blah ", "fizz is set to: {.fizz}", foo = "bar", .fizz = "buzz") #' # completely reset 'glue' to an unconfigured vanilla Logger get_logger("glue", reset = TRUE) } # Configuring a Logger lg <- get_logger("test") lg$config(NULL) # resets logger to unconfigured state # With setters lg$ set_threshold("error")$ set_propagate(FALSE)$ set_appenders(AppenderConsole$new(threshold = "info")) lg$config(NULL) # With a list lg$config(list( threshold = "error", propagate = FALSE, appenders = list(AppenderConsole$new(threshold = "info")) )) lg$config(NULL) # resets logger to unconfigured state # Via YAML cfg <- " Logger: threshold: error propagate: false appenders: AppenderConsole: threshold: info " lg$config(cfg) lg$config(NULL) ## ------------------------------------------------ ## Method `Logger$list_log` ## ------------------------------------------------ lg <- get_logger("test") lg$list_log(list(level = 400, msg = "example")) ## ------------------------------------------------ ## Method `Logger$add_appender` ## ------------------------------------------------ lg <- get_logger("test") lg$add_appender(AppenderConsole$new(), name = "myconsole") lg$appenders[[1]] lg$appenders$myconsole lg$remove_appender("myconsole") lg$config(NULL) # reset config ## ------------------------------------------------ ## Method `Logger$set_exception_handler` ## ------------------------------------------------ lgr$info(stop("this produces a warning instead of an error"))
logger_config()
is an S3 constructor for logger_config
objects
that can be passed to the $config
method of a Logger. You
can just pass a normal list
instead, but using this constructor is
a more formal way that includes additional argument checking.
logger_config( appenders = NULL, threshold = NULL, filters = NULL, exception_handler = NULL, propagate = TRUE ) as_logger_config(x) ## S3 method for class 'list' as_logger_config(x) ## S3 method for class 'character' as_logger_config(x)
logger_config( appenders = NULL, threshold = NULL, filters = NULL, exception_handler = NULL, propagate = TRUE ) as_logger_config(x) ## S3 method for class 'list' as_logger_config(x) ## S3 method for class 'character' as_logger_config(x)
appenders |
see Logger |
threshold |
see Logger |
filters |
see Logger |
exception_handler |
see Logger |
propagate |
see Logger |
x |
any R object. Especially:
|
a list
with the subclass "logger_config"
a logger_config object
Return a data.frame of all registered loggers
logger_index()
logger_index()
a logger_index
data.frame
logger_tree()
for a more visual representation of registered
loggers
get_logger("tree/leaf") get_logger("shrub/leaf") get_logger("plant/shrub/leaf") logger_index()
get_logger("tree/leaf") get_logger("shrub/leaf") get_logger("plant/shrub/leaf") logger_index()
Displays a tree structure of all registered Loggers.
logger_tree()
logger_tree()
data.frame
with subclass "logger_tree"
unconfigured Loggers are displayed in gray (if your terminal supports colors and you have the package crayon installed).
If a logger's threshold
is set, it is displayed in square brackets next
to its name (reminder: if the threshold is not set, it is inherited from
next logger up the logger tree).
If a logger's propagate
field is set to FALSE
an red hash (#
) sign
is displayed in front of the logger name, to imply that it does not pass
LogEvents up the tree.
logger_index()
for a tidy data.frame
representation of
all registered loggers
get_logger("fancymodel") get_logger("fancymodel/shiny")$ set_propagate(FALSE) get_logger("fancymodel/shiny/ui")$ set_appenders(AppenderConsole$new()) get_logger("fancymodel/shiny/server")$ set_appenders(list(AppenderConsole$new(), AppenderConsole$new()))$ set_threshold("trace") get_logger("fancymodel/plumber") if (requireNamespace("cli")){ print(logger_tree()) }
get_logger("fancymodel") get_logger("fancymodel/shiny")$ set_propagate(FALSE) get_logger("fancymodel/shiny/ui")$ set_appenders(AppenderConsole$new()) get_logger("fancymodel/shiny/server")$ set_appenders(list(AppenderConsole$new(), AppenderConsole$new()))$ set_threshold("trace") get_logger("fancymodel/plumber") if (requireNamespace("cli")){ print(logger_tree()) }
LoggerGlue
uses glue::glue()
instead of base::sprintf()
to construct
log messages. glue is a very well designed package for
string interpolation. It makes composing log messages
more flexible and comfortable at the price of an additional dependency and
slightly less performance than sprintf()
.
glue()
lets you define temporary named variables inside the call.
As with the normal Logger, these named arguments get turned into custom
fields; however, you can suppress this behaviour by making named argument
start with a "."
. Please refer to vignette("lgr", package = "lgr")
for
examples.
lgr::Filterable
-> lgr::Logger
-> LoggerGlue
lgr::Filterable$add_filter()
lgr::Filterable$filter()
lgr::Filterable$remove_filter()
lgr::Filterable$set_filters()
lgr::Logger$add_appender()
lgr::Logger$config()
lgr::Logger$handle_exception()
lgr::Logger$initialize()
lgr::Logger$remove_appender()
lgr::Logger$set_appenders()
lgr::Logger$set_exception_handler()
lgr::Logger$set_propagate()
lgr::Logger$set_threshold()
fatal()
LoggerGlue$fatal(..., caller = get_caller(-8L), .envir = parent.frame())
error()
LoggerGlue$error(..., caller = get_caller(-8L), .envir = parent.frame())
warn()
LoggerGlue$warn(..., caller = get_caller(-8L), .envir = parent.frame())
info()
LoggerGlue$info(..., caller = get_caller(-8L), .envir = parent.frame())
debug()
LoggerGlue$debug(..., caller = get_caller(-8L), .envir = parent.frame())
trace()
LoggerGlue$trace(..., caller = get_caller(-8L), .envir = parent.frame())
log()
LoggerGlue$log( level, ..., timestamp = Sys.time(), caller = get_caller(-7), .envir = parent.frame() )
list_log()
LoggerGlue$list_log(x)
spawn()
LoggerGlue$spawn(name)
Pad Character Vectors
x |
a |
width |
|
pad |
|
pad_left("foo", 5) pad_right("foo", 5, ".") pad_left(c("foo", "foooooo"), pad = ".")
pad_left("foo", 5) pad_right("foo", 5, ".") pad_left(c("foo", "foooooo"), pad = ".")
The print()
method for Loggers displays the most important aspects of
the Appender.
## S3 method for class 'Appender' print(x, color = requireNamespace("crayon", quietly = TRUE), ...)
## S3 method for class 'Appender' print(x, color = requireNamespace("crayon", quietly = TRUE), ...)
x |
any R Object |
color |
|
... |
ignored |
print()
returns x
(invisibly), format()
returns a character
vector.
# print most important details of logger print(lgr$console)
# print most important details of logger print(lgr$console)
Print or Format Logging Data
## S3 method for class 'LogEvent' print( x, fmt = "%L [%t] %m %f", timestamp_fmt = "%Y-%m-%d %H:%M:%S", colors = getOption("lgr.colors"), log_levels = getOption("lgr.log_levels"), pad_levels = "right", ... ) ## S3 method for class 'LogEvent' format( x, fmt = "%L [%t] %m %f", timestamp_fmt = "%Y-%m-%d %H:%M:%S", colors = NULL, log_levels = getOption("lgr.log_levels"), pad_levels = "right", ... )
## S3 method for class 'LogEvent' print( x, fmt = "%L [%t] %m %f", timestamp_fmt = "%Y-%m-%d %H:%M:%S", colors = getOption("lgr.colors"), log_levels = getOption("lgr.log_levels"), pad_levels = "right", ... ) ## S3 method for class 'LogEvent' format( x, fmt = "%L [%t] %m %f", timestamp_fmt = "%Y-%m-%d %H:%M:%S", colors = NULL, log_levels = getOption("lgr.log_levels"), pad_levels = "right", ... )
x |
a LogEvent |
fmt |
A |
timestamp_fmt |
see |
colors |
A |
log_levels |
named |
pad_levels |
|
... |
ignored |
x
for print()
and a character
scalar for format()
%t
The timestamp of the message, formatted according to
timestamp_fmt
)
%l
the log level, lowercase character
representation
%L
the log level, uppercase character
representation
%k
the log level, first letter of lowercase character
representation
%K
the log level, first letter of uppercase character
representation
%n
the log level, integer
representation
%g
the name of the logger
%p
the PID (process ID). Useful when logging code that uses multiple threads.
%c
the calling function
%m
the log message
%f
all custom fields of x
in a pseudo-JSON like format that is
optimized for human readability and console output
%j
all custom fields of x
in proper JSON. This requires that you
have jsonlite installed and does not support colors as opposed to
%f
# standard fields can be printed using special tokens x <- LogEvent$new( level = 300, msg = "a test event", caller = "testfun()", logger = lgr ) print(x) print(x, fmt = c("%t (%p) %c: %n - %m")) print(x, colors = NULL) # custom values y <- LogEvent$new( level = 300, msg = "a gps track", logger = lgr, waypoints = 10, location = "Austria" ) # default output with %f print(y) # proper JSON output with %j if (requireNamespace("jsonlite")){ print(y, fmt = "%L [%t] %m %j") }
# standard fields can be printed using special tokens x <- LogEvent$new( level = 300, msg = "a test event", caller = "testfun()", logger = lgr ) print(x) print(x, fmt = c("%t (%p) %c: %n - %m")) print(x, colors = NULL) # custom values y <- LogEvent$new( level = 300, msg = "a gps track", logger = lgr, waypoints = 10, location = "Austria" ) # default output with %f print(y) # proper JSON output with %j if (requireNamespace("jsonlite")){ print(y, fmt = "%L [%t] %m %j") }
The print()
method for Loggers displays the most important aspects of
the Logger.
You can also print just the ancestry
of a Logger which can be accessed with
with logger$ancestry()
. This returns a named character
vector whose
names correspond to the names of the Loggers logger
inherits from. The
TRUE
/FALSE
status of its elements correspond to the propagate
values of
these Loggers.
## S3 method for class 'Logger' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'Logger' format(x, color = FALSE, ...) ## S3 method for class 'ancestry' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'ancestry' format(x, color = FALSE, ...)
## S3 method for class 'Logger' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'Logger' format(x, color = FALSE, ...) ## S3 method for class 'ancestry' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'ancestry' format(x, color = FALSE, ...)
x |
any R Object |
color |
|
... |
ignored |
print()
returns x
(invisibly), format()
returns a character
vector.
# print most important details of logger print(lgr) # print only the ancestry of a logger lg <- get_logger("AegonV/Aerys/Rheagar/Aegon") get_logger("AegonV/Aerys/Rheagar")$set_propagate(FALSE) print(lg$ancestry) unclass(lg$ancestry)
# print most important details of logger print(lgr) # print only the ancestry of a logger lg <- get_logger("AegonV/Aerys/Rheagar/Aegon") get_logger("AegonV/Aerys/Rheagar")$set_propagate(FALSE) print(lg$ancestry) unclass(lg$ancestry)
Print Logger Trees
## S3 method for class 'logger_tree' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'logger_tree' format(x, color = FALSE, ...)
## S3 method for class 'logger_tree' print(x, color = requireNamespace("crayon", quietly = TRUE), ...) ## S3 method for class 'logger_tree' format(x, color = FALSE, ...)
x |
|
color |
|
... |
passed on to |
x
(invisibly)
Read a JSON logfile
read_json_lines(file, ...)
read_json_lines(file, ...)
file |
|
... |
passed on to |
a data.frame
lgr provides convenience functions managing the root Logger. These are designed chiefly for interactive use and are less verbose than their R6 method counterparts.
threshold()
sets or retrieves the threshold for an Appender or Logger
(the minimum level of log messages it processes). It's target
defaults to
the root logger. (equivalent to lgr::lgr$threshold
and
lgr::lgr$set_threshold
)
console_threshold()
is a shortcut to set the threshold of the root
loggers AppenderConsole, which is usually the only Appender that manages
console output for a given R session. (equivalent to
lgr::lgr$appenders$console$threshold
and
lgr::lgr$appenders$console$set_threshold
)
add_appender()
and remove_appender()
add Appenders to Loggers and other
Appenders. (equivalent to lgr::lgr$add_appender
and
lgr::lgr$remove_appender
)
show_log()
displays the last n
log entries of an Appender (or a Logger
with such an Appender attached) with a $show()
method. Most, but not all
Appenders support this function (try AppenderFile or AppenderBuffer).
show_data()
and show_dt()
work similar to show_log()
, except that
they return the log as data.frame
or data.table
respectively. Only
Appenders that log to formats that can easily be converted to data.frames
are supported (try AppenderJson or AppenderBuffer).
The easiest way to try out this features is by adding an AppenderBuffer
to the root logger with basic_config(memory = TRUE)
.
log_exception(code, logfun = lgr$fatal, caller = get_caller(-3)) threshold(level, target = lgr::lgr) console_threshold(level, target = lgr::lgr$appenders$console) add_appender(appender, name = NULL, target = lgr::lgr) remove_appender(pos, target = lgr::lgr) show_log(threshold = NA_integer_, n = 20L, target = lgr::lgr) show_dt(target = lgr::lgr) show_data(target = lgr::lgr)
log_exception(code, logfun = lgr$fatal, caller = get_caller(-3)) threshold(level, target = lgr::lgr) console_threshold(level, target = lgr::lgr$appenders$console) add_appender(appender, name = NULL, target = lgr::lgr) remove_appender(pos, target = lgr::lgr) show_log(threshold = NA_integer_, n = 20L, target = lgr::lgr) show_dt(target = lgr::lgr) show_data(target = lgr::lgr)
code |
Any R code |
logfun |
a |
caller |
a |
level |
|
target |
a Logger or Appender or the name of a Logger as |
appender |
an |
name |
|
pos |
|
threshold |
|
n |
|
threshold()
and console_threshold()
return the log_level of target
as integer
(invisibly)
add_appender()
and remove_appender()
return target
.
show_log()
prints to the console and returns whatever the target
Appender's $show()
method returns, usually a character
vector,
data.frame
or data.table
(invisibly).
show_data()
always returns a data.frame
and show_dt()
always returns
a data.table
.
# Get and set the threshold of the root logger threshold("error") threshold() lgr$info("this will be supressed") lgr$error("an important error message") # you can also specify a target to modify other loggers lg <- get_logger("test") threshold("fatal", target = lg) threshold(target = lg) # If a Logger's threshold is not set, the threshold is inherited from # its parent, in this case the root logger (that we set to error/200 before) threshold(NULL, target = lg) threshold(target = lg) # Alternative R6 API for getting/setting thresholds lg$set_threshold("info") lg$threshold lg$set_threshold(300) lg$threshold lg$set_threshold(NULL) lg$threshold # cleanup lgr$config(NULL) lg$config(NULL) # add Appenders to a Logger add_appender(AppenderConsole$new(), "second_console_appender") lgr$fatal("Multiple console appenders are a bad idea") remove_appender("second_console_appender") lgr$info("Good that we defined an appender name, so it's easy to remove") # Reconfigure the root logger basic_config(memory = TRUE) # log some messages lgr$info("a log message") lgr$info("another message with data", data = 1:3) show_log() show_data() # cleanup lgr$config(NULL)
# Get and set the threshold of the root logger threshold("error") threshold() lgr$info("this will be supressed") lgr$error("an important error message") # you can also specify a target to modify other loggers lg <- get_logger("test") threshold("fatal", target = lg) threshold(target = lg) # If a Logger's threshold is not set, the threshold is inherited from # its parent, in this case the root logger (that we set to error/200 before) threshold(NULL, target = lg) threshold(target = lg) # Alternative R6 API for getting/setting thresholds lg$set_threshold("info") lg$threshold lg$set_threshold(300) lg$threshold lg$set_threshold(NULL) lg$threshold # cleanup lgr$config(NULL) lg$config(NULL) # add Appenders to a Logger add_appender(AppenderConsole$new(), "second_console_appender") lgr$fatal("Multiple console appenders are a bad idea") remove_appender("second_console_appender") lgr$info("Good that we defined an appender name, so it's easy to remove") # Reconfigure the root logger basic_config(memory = TRUE) # log some messages lgr$info("a log message") lgr$info("another message with data", data = 1:3) show_log() show_data() # cleanup lgr$config(NULL)
These are helper functions for verifying log levels and converting them from their character to their integer representations. This is primarily useful if you want to build your own Loggers, Appenders or Layouts and need to handle log levels in a way that is consistent with lgr .
standardize_threshold( x, log_levels = c(getOption("lgr.log_levels"), c(all = NA_integer_, off = 0L)) ) is_threshold(x) standardize_log_level(x, log_levels = getOption("lgr.log_levels")) is_log_level(x) standardize_log_levels(x, log_levels = getOption("lgr.log_levels")) is_log_levels(x)
standardize_threshold( x, log_levels = c(getOption("lgr.log_levels"), c(all = NA_integer_, off = 0L)) ) is_threshold(x) standardize_log_level(x, log_levels = getOption("lgr.log_levels")) is_log_level(x) standardize_log_levels(x, log_levels = getOption("lgr.log_levels")) is_log_levels(x)
x |
a |
log_levels |
named |
An unnamed integer
vector
Other docs relevant for extending lgr:
LogEvent
,
as_LogEvent()
,
event_list()
standardize_threshold("info") standardize_threshold("all") is_threshold("all") is_threshold("foobar") standardize_log_level("info") # all is a valid threshold, but not a valid log level try(is.na(standardize_log_level("all"))) is_log_level("all") # standardized_log_level intentionally only works with scalars, because many # functions require scalar log level inputs try(standardize_log_level(c("info", "fatal"))) # You can still use standardize_log_levels() (plural) to work with vectors standardize_log_levels(c("info", "fatal"))
standardize_threshold("info") standardize_threshold("all") is_threshold("all") is_threshold("foobar") standardize_log_level("info") # all is a valid threshold, but not a valid log level try(is.na(standardize_log_level("all"))) is_log_level("all") # standardized_log_level intentionally only works with scalars, because many # functions require scalar log level inputs try(standardize_log_level(c("info", "fatal"))) # You can still use standardize_log_levels() (plural) to work with vectors standardize_log_levels(c("info", "fatal"))
This is inspired by the python function repr
and produces a short
string representation of any R object that is suitable for logging and error
messages. It is a generic so you can implement methods for custom S3 objects.
string_repr(x, width = 32, ...) ## S3 method for class ''function'' string_repr(x, width = 32L, ...) ## S3 method for class 'data.frame' string_repr(x, width = 32L, ...) ## S3 method for class 'matrix' string_repr(x, width = 32L, ...) ## Default S3 method: string_repr(x, width = 32L, ...)
string_repr(x, width = 32, ...) ## S3 method for class ''function'' string_repr(x, width = 32L, ...) ## S3 method for class 'data.frame' string_repr(x, width = 32L, ...) ## S3 method for class 'matrix' string_repr(x, width = 32L, ...) ## Default S3 method: string_repr(x, width = 32L, ...)
x |
Any R object. |
width |
a scalar integer |
... |
passed on to methods |
a scalar
character
string_repr(iris) string_repr(LETTERS) string_repr(LETTERS, 10)
string_repr(iris) string_repr(LETTERS) string_repr(LETTERS, 10)
Completely disable logging for all loggers. This is for example useful for
automated test code. suspend_logging()
globally disables all logging with
lgr until unsuspend_logging()
is invoked, while without_logging()
and
with_logging()
temporarily disable/enable logging.
suspend_logging() unsuspend_logging() without_logging(code) with_logging(code)
suspend_logging() unsuspend_logging() without_logging(code) with_logging(code)
code |
Any R code |
suspend_logging()
and unsuspend_logging()
return NULL
(invisibly),
without_logging()
and with_logging()
returns whatever code
returns.
lg <- get_logger("test") # temporarily disable logging lg$fatal("foo") without_logging({ lg$info("everything in this codeblock will be suppressed") lg$fatal("bar") }) # globally disable logging suspend_logging() lg$fatal("bar") with_logging(lg$fatal("foo")) # log anyways # globally enable logging again unsuspend_logging() lg$fatal("foo")
lg <- get_logger("test") # temporarily disable logging lg$fatal("foo") without_logging({ lg$info("everything in this codeblock will be suppressed") lg$fatal("bar") }) # globally disable logging suspend_logging() lg$fatal("bar") with_logging(lg$fatal("foo")) # log anyways # globally enable logging again unsuspend_logging() lg$fatal("foo")
Convert a LogEvent to a character string
## S3 method for class 'LogEvent' toString(x, ...)
## S3 method for class 'LogEvent' toString(x, ...)
x |
a LogEvent |
... |
ignored |
a character
scalar
toString(LogEvent$new(logger = lgr::lgr))
toString(LogEvent$new(logger = lgr::lgr))
This gives you a minimal logger with no appenders that you can use inside
your package under the name lg
(e.g. lg$fatal("test")). use_logger()
does not modify any files but only prints code for you to copy and paste.
use_logger( pkg = desc::desc_get("Package", rprojroot::find_package_root_file("DESCRIPTION"))[[1]] )
use_logger( pkg = desc::desc_get("Package", rprojroot::find_package_root_file("DESCRIPTION"))[[1]] )
pkg |
|
a character
scalar containing R code.
use_logger("testpkg")
use_logger("testpkg")
with_log_level
temporarily overrides the log level of all LogEvents
created by target Logger.
with_log_level(level, code, logger = lgr::lgr) with_log_value(values, code, logger = lgr::lgr)
with_log_level(level, code, logger = lgr::lgr) with_log_value(values, code, logger = lgr::lgr)
level |
|
code |
Any R code |
logger |
a Logger or the name of one (see |
values |
a named |
These functions abuses lgr's filter mechanic to modify LogEvents in-place before they passed on the Appenders. Use with care as they can produce hard to reason about code.
whatever code
would return
with_log_level("warn", { lgr$info("More important than it seems") lgr$fatal("Really not so bad") }) with_log_value( list(msg = "overriden msg"), { lgr$info("bar") lgr$fatal("FOO") })
with_log_level("warn", { lgr$info("More important than it seems") lgr$fatal("Really not so bad") }) with_log_value( list(msg = "overriden msg"), { lgr$info("bar") lgr$fatal("FOO") })