Skip to contents

Importance of Logging

Logging in FIMS is important because it allows developers to understand what is happening within a model. It is especially useful when problems arise. The FIMS logging system has been designed to handle common issues, such as undefined modules, dimension issues, and software errors that may occur when a model is not properly defined. This logging system is accessible from both R and C++ and messages are provided using a JSON format.

How FIMS Logging works

At run time, FIMS records log entries in C++ and exposes them to R as JSON strings. From R, you can inspect all entries (get_log()), or only warnings and errors (get_log_warnings(), get_log_errors()).

For implementation details (log schema, severity macros, write-on-exit behavior, and signal handling), see the following resources:

The log is initiated when CreateTMBModel() is run, where the first entry is always the call to this function, e.g.,

empty_model <- CreateTMBModel()
log_string <- get_log()
log_data_frame <- jsonlite::fromJSON(log_string)
log_data_frame
##                  timestamp level
## 1 Mon Apr  6 07:46:36 2026  info
## 2 Mon Apr  6 07:46:36 2026  info
## 3 Mon Apr  6 07:46:36 2026  info
## 4 Mon Apr  6 07:46:36 2026  info
##                                                  message id   user
## 1 Creating model and checking for required components...  0 runner
## 2                            Model successfully created.  1 runner
## 3 Creating model and checking for required components...  2 runner
## 4                            Model successfully created.  3 runner
##                                      wd
## 1 /home/runner/work/FIMS/FIMS/vignettes
## 2 /home/runner/work/FIMS/FIMS/vignettes
## 3 /home/runner/work/FIMS/FIMS/vignettes
## 4 /home/runner/work/FIMS/FIMS/vignettes
##                                                              file
## 1 /home/runner/work/FIMS/FIMS/inst/include/common/information.hpp
## 2 /home/runner/work/FIMS/FIMS/inst/include/common/information.hpp
## 3 /home/runner/work/FIMS/FIMS/inst/include/common/information.hpp
## 4 /home/runner/work/FIMS/FIMS/inst/include/common/information.hpp
##                                                                                routine
## 1                bool fims_info::Information<Type>::CreateModel() [with Type = double]
## 2                bool fims_info::Information<Type>::CreateModel() [with Type = double]
## 3 bool fims_info::Information<Type>::CreateModel() [with Type = TMBad::global::ad_aug]
## 4 bool fims_info::Information<Type>::CreateModel() [with Type = TMBad::global::ad_aug]
##   line
## 1  826
## 2  843
## 3  826
## 4  843

This particular log entry originates from the use of FIMS_INFO_LOG() inside of CreateTMBModel(), see inst/include/interface/rcpp/rcpp_interface.hpp. In the example, the entry for the “level” column is "info" because FIMS_INFO_LOG() was called, whereas if FIMS_WARNING_LOG() was called instead, then the “level” entry would be "warning". The log entry also specifies the C++ file where the log entry originated from. Additionally, the “routine” and “line” columns specify the function and line, respectively, within the file that led to the creation of the log entry.

See the introduction to FIMS vignette for a log of a complete model run.

Using the Logging System in R

The FIMS Logging System is also available from R, with a caveat! Logging from R gives less information than logging from C++. When a log entry originates from R, file, routine, and line information are absent. Further implementations may rectify this issue. Below are examples of adding log entries from R.

log_info("info entry from R script")
log_warning("warning entry from R script")
jsonlite::fromJSON(get_log())
##                  timestamp   level                     message id   user
## 1 Mon Apr  6 07:46:36 2026    info    info entry from R script  0 runner
## 2 Mon Apr  6 07:46:36 2026 warning warning entry from R script  1 runner
##                                      wd
## 1 /home/runner/work/FIMS/FIMS/vignettes
## 2 /home/runner/work/FIMS/FIMS/vignettes
##                                          file        routine line
## 1 /home/runner/work/FIMS/FIMS/vignettes/R_env R_script_entry   -1
## 2 /home/runner/work/FIMS/FIMS/vignettes/R_env R_script_entry   -1

The example above just logs information and warnings but you can also log errors. Notice that the “routine” information in the error log is not super informative even though it is filled with a lot of information. The R stack trace in this column is to large to capture the root cause of the error. For that reason, it’s advised to make the error message as detailed as possible when calling log_error(x) from R. Note that the formatting is better when written to a file rather than printed to the screen so the following code chunk is not rendered here but you can on your own computer.

error <- log_error("error entry from R script")
jsonlite::fromJSON(get_log_errors())

There are several logging functions that are exported to R. Below is a list of all of the functions as well as an example of how you can find out more information about each of them. Note that because these are C++ functions that are exported to R, we have chosen to document them in the C++ code using doxygen and just provide links to that documentation when users call methods::show() on them.

ls("package:FIMS") |>
  grep(pattern = "_log|log_", value = TRUE) |>
  cli::cli_bullets()
## get_log
## get_log_errors
## get_log_warnings
## inv_logit
## log_error
## log_info
## log_warning
## set_log_throw_on_error
# Get documentation for log_error
methods::show(log_error)
## internal C++ function <0x563673781cb0>
##     docstring : See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html.
##     signature : void log_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)

Another useful option is set_throw_on_error(). If this option is set to TRUE, FIMS will abort immediately when an error occurs and if write_log(TRUE) was previously called, the log file will be written before FIMS terminates the session.

set_log_throw_on_error(TRUE)
log_error("throwing now!")