---
title: "Migration Guide"
vignette: >
  %\VignetteIndexEntry{Migration Guide}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{css, echo=FALSE}
div.comparison {
    width: 49%;
    display: inline-block;
    vertical-align: top;
}
div.comparison p package {
    font-family: monospace;
    color: brown;
}
div#tocnav ul.nav li ul {
    padding-left: 10px;
}
```

```{r pkgchecks, echo = FALSE}
## check if other logger packages are available and exit if not
for (pkg in c("futile.logger", "logging", "log4r")) {
  if (!requireNamespace(pkg, quietly = TRUE)) {
    warning(paste(pkg, "package not available, so cannot build this vignette"))
    knitr::knit_exit()
  }
}
```

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## load the main package first
library(logger)
log_appender(appender_stdout)
```

In this vignette I suppose that you are already familiar with at least one of the [similar logging R packages](https://daroczig.github.io/logger/index.html#why-another-logging-r-package) and you are looking for suggestions on how to switch to `logger`. Before moving forward, please make sure that you have read the [Introduction to logger](https://daroczig.github.io/logger/articles/Intro.html), [The Anatomy of a Log Request](https://daroczig.github.io/logger/articles/anatomy.html) and [Customizing the Format and the Destination of a Log Record](https://daroczig.github.io/logger/articles/customize_logger.html) vignettes for a decent background on `logger`, and use this vignette as a quick-reference sheet to help you migrate from another package.

## futile.logger

The `logger` package has been very heavily inspired by [`futile.logger`](https://cran.r-project.org/package=futile.logger) and have been using it for many years, also opened multiple pull requests to extend `futile.logger` before I decided to revamp my ideas into a new R package -- but there are still many common things between `futile.logger` and `logger`.

### Initialize

Both packages comes with a default log engine / config, so it's enough to load the packages and those are ready to be used right away:

<package>futile.logger</package>
```{r}
library(futile.logger)
```


<package>logger</package>
```{r}
library(logger)
```


### Logging functions

The most important change is that function names are by snake_case in `logger`, while `futile.logger` uses dot.separated expressions, and `futile.logger` prefixes function names by `flog` while `logger` uses `log` for that:

<package>futile.logger</package>
```{r}
flog.info("hi there")
flog.warn("watch out")
```


<package>logger</package>
```{r}
log_info("hi there")
log_warn("watch out")
```


As you can see above, the default layout of the messages is exactly the same.

### Log levels

Regarding log levels, `futile.logger` bundles the default `log4j` levels (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR` and `FATAL`) that is extended by `SUCCESS` in `logger` as sometimes it's worth logging with a higher than `INFO` level that something succeeded.

### Log record layout

Changing layouts is easy in both package, as you simply pass a layout function:

<package>futile.logger</package>
```{r}
flog.layout(layout.json)
flog.info("hi again")
```


<package>logger</package>
```{r}
log_layout(layout_json())

log_info("hi again")
```


As you can see, `logger` provided a bit more information about the log request compared to `futile.logger`, but it's easy to change the list of fields to be used in the JSON -- see `?get_logger_meta_variables` for a complete list of variable names to be passed to `?layout_json`. `logger` also ships a lot more layouts, eg `?layout_glue_colors` or roll out your own via the `?layout_glue_generator` factory function.

```{r echo=FALSE, results='hide'}
flog.layout(layout.simple)
log_layout(layout_simple)
```

### Log message formatting

By default, `futile.logger` uses an `sprintf` formatter, while `logger` passes the objects to be logged to `glue`:

<package>futile.logger</package>
```{r}
flog.info("hi")
flog.info("hi %s", 84 / 2)
flog.info(paste("hi", 84 / 2))
flog.info(glue::glue("hi {84/2}"))
```


<package>logger</package>
```{r}
log_info("hi")
log_info("hi {84/2}")
log_formatter(formatter_sprintf)
log_info("hi %s", 84 / 2)
log_formatter(formatter_paste)
log_info("hi", 84 / 2)
```


```{r echo=FALSE, results='hide'}
log_formatter(formatter_glue)
```

It's easy to change this default formatter in both packages: use `flog.layout` handles this as well in `futile.logger`, while the formatter is separated from the layout function in `logger`, so check `?log_formatter` instead. `logger` ships with a bit more formatter functions, eg the default `?formatter_glue` and `?formatter_glue_or_sprintf` that tries to combine the best from both words.

### Log record destination

Setting the destination of the log records works similarly in both packages, although he `logger` packages bundles a lot more options:

<package>logging</package>
```{r}
t <- tempfile()
flog.appender(appender.file(t))
flog.appender(appender.tee(t))
```


<package>logger</package>
```{r}
t <- tempfile()
log_appender(appender_file(t))
log_appender(appender_tee(t))
```


```{r echo=FALSE, results='hide'}
flog.appender(appender.console)
log_appender(appender_stdout)
```

### Hierarchical logging and performance

Both packages support using different logging namespaces and stacking loggers within the same namespace. Performance-wise, there's `logger` seems to be faster than `futile.logger`, but for more details, check the [Simple Benchmarks on Performance](https://daroczig.github.io/logger/articles/performance.html) vignette.

### Using `logger` as a drop-in-replacement of `futile.logger`

`logger` has no hard requirements, so it's a very lightweight alternative of `futile.logger`. Although the function names are a bit different, and the message formatter also differs, but with some simple tweaks, `logger` can become an almost perfect drop-in-replacement of `futile.logger`:

```{r}
library(logger)
log_formatter(formatter_sprintf)
flog.trace <- log_trace
flog.debug <- log_debug
flog.info <- log_info
flog.warn <- log_warn
flog.error <- log_error

flog.info("Hello from logger in a futile.logger theme ...")
flog.warn("... where the default log message formatter is %s", "sprintf")
```

## logging

The [`logging`](https://cran.r-project.org/package=logging) package behaves very similarly to the Python logging module and so thus being pretty Pythonic, while `logger` tries to accommodate native R users' expectations -- so there are some minor nuances between the usage of the two packages.

### Initialize

In `logging`, you have to initialize a logger first via `addHandler` or simply by calling `basicConfig`, which is not required in `logger` as it already comes with a default log config:

<package>logging</package>
```{r}
library(logging)
basicConfig()
```


<package>logger</package>
```{r}
library(logger)
```


### Logging functions

After initializing the logging engine, actual logging works similarly in the two packages -- with a bit different function names:

* although `logging` uses mostly camelCase function names (eg `basicConfig`), but the logging functions are all lowercase without any separator, such as `loginfo` or `logwarn`
* `logger` uses snake_case for the function names, such as `log_info` and `log_warn`

<package>logging</package>
```{r}
loginfo("hi there")
logwarn("watch out")
```


<package>logger</package>
```{r}
log_info("hi there")
log_warn("watch out")
```


As you can see above, the default layout of the log messages is somewhat different:

* `logging` starts with the timestamp that is followed by the log level, optional namespace and the message separated by colons
* `logger` starts with the log level, followed by the timestamp between brackets and then the message

### Log levels

For the available log levels in `logging`, check `?loglevels`, and `?log_levels` for the same in `logger`:

<package>logging</package>
```{r}
str(as.list(loglevels))
```


<package>logger</package>
```{r}
levels <- mget(rev(logger:::log_levels_supported), envir = asNamespace("logger"))
str(levels, give.attr = FALSE)
```


### Performance

Performance-wise, there's no big difference between the two packages, but for more details, check the [Simple Benchmarks on Performance](https://daroczig.github.io/logger/articles/performance.html) vignette.

### Log record layout

Getting and setting the layout of the log record should happen up-front in both packages:

<package>logging</package>
```{r}
getLogger()[["handlers"]]$basic.stdout$formatter
```


<package>logger</package>
```{r}
log_layout()
```


`logger` provides multiple configurable layouts to fit the user's need, eg easily show the calling function of the lof request, the `pid` of the R process, name of the machine etc. or colorized outputs. See [Customizing the Format and the Destination of a Log Record](https://daroczig.github.io/logger/articles/customize_logger.html) vignette for more details.

### Log message formatting

If you want to pass dynamic log messages to the log engines, you can do that via the hard-coded `sprintf` in the `logging` package, while you can set that on a namespaces basis in `logger`, which is by default using `glue`:

<package>logging</package>
```{r}
loginfo("hi")
loginfo("hi %s", 84 / 2)
loginfo(paste("hi", 84 / 2))
loginfo(glue::glue("hi {84/2}"))
```


<package>logger</package>
```{r}
log_info("hi")
log_info("hi {84/2}")
log_formatter(formatter_sprintf)
log_info("hi %s", 84 / 2)
log_formatter(formatter_paste)
log_info("hi", 84 / 2)
```


For even better compatibility, there's also `?formatter_logging` that not only relies on `sprintf` when the first argument is a string, but will log the call and the result as well when the log object is an R expression:

```{r}
log_formatter(formatter_logging)
log_info("42")
log_info(42)
log_info(4 + 2)
log_info("foo %s", "bar")
log_info(12, 1 + 1, 2 * 2)
```

```{r echo=FALSE, results='hide'}
log_formatter(formatter_glue)
```

### Log record destination

Setting the destination of the log records works similarly in both packages, although he `logger` packages bundles a lot more options:

<package>logging</package>
```r
?addHandler
?writeToConsole
?writeToFile
```


<package>logger</package>
```r
?log_appender
?appender_console
?appender_file
?appender_tee
?appender_slack
?appender_pushbullet
```


### Hierarchical logging

Both packages support using different logging namespaces and stacking loggers within the same namespace.

### Using `logger` as a drop-in-replacement of `logging`

`logger` has no hard requirements, so it's an adequate alternative of `logging`. Although the function names are a bit different, and the message formatter also differs, but with some simple tweaks, `logger` can become an almost perfect drop-in-replacement of `logging` -- although not all log levels (eg \code{FINE} and \code{CRITICAL}) are supported:

```{r}
library(logger)
log_formatter(formatter_logging)
log_layout(layout_logging)
logdebug <- log_debug
loginfo <- log_info
logwarn <- log_warn
logerror <- log_error

loginfo("Hello from logger in a logging theme ...")
logwarn("... where the default log message formatter is %s", "sprintf", namespace = "foobar")
```

## log4r

The [`log4r`](https://cran.r-project.org/package=log4r) package provides an object-oriented approach for logging in R, so the logger object is to be passed to the log calls -- unlike in the `logger` package.

### Initialize

So thus it's important to create a logging object in `log4r` before being able to log messages, while that's automatically done in `logger:

<package>log4r</package>
```{r}
library(log4r)
logger <- create.logger(logfile = stdout(), level = "INFO")
```


<package>logger</package>
```{r}
library(logger)
```


Please note that in the background, `logger` does have a concept of logger objects, but that's behind the scene and the user does not have to specify / reference it. On the other hand, if you wish, you can do that via the `namespace` concept of `logger` -- more on that later.

### Logging functions

While `logger` has a `log_` prefix for all logging functions, `log4r` has lowercase functions names referring to the log level, which takes a logging object and the log message:

<package>log4r</package>
```{r}
info(logger, "hi there")
warn(logger, "watch out")
```


<package>logger</package>
```{r}
log_info("hi there")
log_warn("watch out")
```


As you can see the default layout of the messages is a bit different in the two packages.

### Log levels

Both packages are based on `log4j`, and `log4r` provides `DEBUG`, `INFO`, `WARN`, `ERROR` and `FATAL`, while `logger` also adds `TRACE` and `SUCCESS` on the top of these.

To change the log level threshold, use the `level` function on the logging object in `log4r`, while it's `log_level` in `logger`.

### Log record layout and formatter functions

The `log4r` provides a `logformat` argument in `create.logger` that can be used to override the default formatting, while `logger` provides formatter and layout functions for a flexible log record design.

### Log record destination

By default, `log4r` logs to a file that can be set to `stoud` to write to the console, while `logger` writes to the console by default, but logging to files via the `appender_file` functions is also possible -- besides a number of other log record destinations as well.

### Hierarchical logging and performance

Creating objects is the `log4r` way of handling multiple log environments, while `logger` handles that via `namespace`s.

## loggit and loggr

Both [`loggit`](https://cran.r-project.org/package=loggit) and [`loggr`](https://github.com/smbache/loggr) provides an easy way of capturing `message`, `warning` and `stop` function messages. Similar functionality has been added to `logger` in the form of `log_message`, `log_warning` and `log_error` functions.

```{r cleanup, include = FALSE}
logger:::namespaces_reset()
detach("package:logger", unload = TRUE)
detach("package:futile.logger", unload = TRUE)
detach("package:logging", unload = TRUE)
```
