Git Product home page Git Product logo

rcppspdlog's Introduction

RcppSpdlog: Bundling of spdlog for use from R and Rcpp

CI License CRAN r-universe Dependencies Downloads Last Commit Documentation

About

The spdlog library is a widely-used and very capable header-only C++ library for logging. This package includes its headers as an R package to permit other R packages to deploy it via a simple LinkingTo: RcppSpdlog as described in Section 1.1.3 of WRE. As of version 0.0.9, it also provides both simple R logging functions and compiled functions callable by other packages as described in Section 5.4.3 of WRE.

Example

A simple first example, following the upstream examples:

edd@rob:~$ Rscript -e 'Rcpp::sourceCpp("inst/examples/exampleOne.cpp")'

R> exampleOne()
[07:45:57.168673] [I] [thread 1500593] Welcome to spdlog!
[07:45:57.168704] [E] [thread 1500593] Some error message with arg: 1
[07:45:57.168707] [W] [thread 1500593] Easy padding in numbers like 00000012
[07:45:57.168710] [C] [thread 1500593] Support for int: 42;  hex: 2a;  oct: 52; bin: 101010
[07:45:57.168728] [I] [thread 1500593] Support for floats 1.23
[07:45:57.168731] [I] [thread 1500593] Positional args are supported too..
[07:45:57.168734] [I] [thread 1500593] left aligned
[07:45:57.168737] [D] [thread 1500593] This message should be displayed..
edd@rob:~$

This logs the hour, minute, second, microsecond followed by a one-char code for info, error, warning or critical followed by the thread id and the actual loggable message. The code, apart from the included headers and more, is simply

// [[Rcpp::export]]
void exampleOne() {

  // change log pattern (changed from [%H:%M:%S %z] [%n] [%^---%L---%$] )
  spdlog::set_pattern("[%H:%M:%S.%f] [%L] [thread %t] %v");

  spdlog::info("Welcome to spdlog!");
  spdlog::error("Some error message with arg: {}", 1);

  spdlog::warn("Easy padding in numbers like {:08d}", 12);
  spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
  spdlog::info("Support for floats {:03.2f}", 1.23456);
  spdlog::info("Positional args are {1} {0}..", "too", "supported");
  spdlog::info("{:<30}", "left aligned");

  spdlog::set_level(spdlog::level::debug); // Set global log level to debug
  spdlog::debug("This message should be displayed..");

  // Compile time log levels
  // define SPDLOG_ACTIVE_LEVEL to desired level
  SPDLOG_TRACE("Some trace message with param {}", {});
  SPDLOG_DEBUG("Some debug message");

}

Many other customizations are possible, see the spdlog wiki.

Note that using spdlog examples directly may well trigger warning from R during package checking as stdout and/or stderr may be used. See the included example function described in the next section which uses a derived class to pass logging output explicitly to the R input/output stream as per the R coding requirements, see Section 1.3.1 (and others) of WRE.

Use in R Packages and Warnings

As shipped, both spdlog and the embedded fmt use stdout and stderr in ways that may make it non-trivial to fully replace them with R input/output as required by Section 1.3.1 (and others) of WRE.

However, based on some initial trials and some excellent help from upstream we have defined a specific sink for R in the header rcpp_sink.h, corrected one stderr use and added one #define. That combination now passes as can be seen in checks of the package RcppSpdlog and the included function exampleRsink() whose complete source code is included here:

// this portmanteau include also defines the r_sink we use below, and which
// diverts all logging to R via the Rcpp::Rcout replacement for std::cout
#include <RcppSpdlog>

//' spdlog Example using a sink for R
//'
//' A simple example invoking a derived R/Rcpp logger. Also demonstrates the
//' stopwatch feature. For more features see the 'spdlog' documnetation.
//'
//' Note that this no longer triggers R warnings thanks to excellent help by
//' Gabi Melman.
//' @return None
//' @examples
//' exampleRsink()
// [[Rcpp::export]]
void exampleRsink() {

    std::string logname = "fromR";                          // fix a name for this logger
    auto sp = spdlog::get(logname);                         // retrieve existing one
    if (sp == nullptr) sp = spdlog::r_sink_mt(logname);     // or create new one if needed

    spdlog::stopwatch sw;                                   // instantiate a stop watch

    // change log pattern (changed from [%H:%M:%S %z] [%n] [%^---%L---%$] )
    spdlog::set_pattern("[%H:%M:%S.%f] [%n] [%^%L%$] [thread %t] %v");

    spdlog::info("Welcome to spdlog!");
    spdlog::error("Some error message with arg: {}", 1);
    spdlog::info("Elapsed time: {}", sw);

    spdlog::warn("Easy padding in numbers like {:08d}", 12);
    spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
    spdlog::info("Support for floats {:03.2f}", 1.23456);
    spdlog::info("Positional args are {1} {0}..", "too", "supported");
    spdlog::info("{:<30}", "left aligned");
    spdlog::info("Elapsed time: {}", sw);

}

Note that it is deliberately similar in use to the example above. A new instance of the logger is instantiated as a shared pointer sp to a spdlog object. Similarly, a stopwatch is instantiated used simply by referring to it.

We may make additional package features available in the future.

See Also

The spdl package, now also on CRAN, wraps around this package to provide a uniform and consistent logging interface from both R and C++. It defines a new C++ namespace spdl along with matching R functions.

Author

Gabi Melman is the main author of spdlog.

Victor Zverovich is the main author of the embedded fmt library.

Dirk Eddelbuettel is author of this package and the R integration.

License

spdlog and fmt are under the MIT license.

RcppSpdlog is released under the GNU GPL, version 2 or later, just like R and Rcpp.

rcppspdlog's People

Contributors

eddelbuettel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

barracuda156

rcppspdlog's Issues

Steps towards making this possibly CRAN compliant

Initial attempts at just substituting stdout and stderr with Rcpp::Rcout and Rcpp::Rcerr lead nowhere, which is why this languished unfinished for too long.

Currently, the main branch has no compiled code 😁 leading to no warnings. Very clever.

Branch feature/with_src has the simple exampleFour.cpp with its derived sink for Rcpp. It still gets

* checking compiled code ... NOTE
File ‘RcppSpdlog/libs/RcppSpdlog.so’:
  Found ‘stderr’, possibly from ‘stderr’ (C)
    Object: ‘exampleFour.o’
  Found ‘stdout’, possibly from ‘stdout’ (C)
    Object: ‘exampleFour.o’

Compiled code should not call entry points which might terminate R nor write to stdout/stderr instead 
of to the console, nor use Fortran I/O nor system RNGs.

See ‘Writing portable packages’ in the ‘Writing R Extensions’ manual.
* checking examples ... OK

@gabime was kind enough to lend an ear over email, maybe we will get somewhere by capturing logging in an osstream object and passing that to R. Sadly, there is also a little bit of stdout in the fmt library so not sure we will get there.

Help needed and welcome if someone wants to poke -- please get in touch.

ctz, ctzll undefined on linux with mkl

Dear All,

This appears to be related to but separate from fmtlib/fmt#2176.

Granted our campus cluster OS is downlevel and to be upgraded shortly.
Meanwhile, I can avoid the subject errors shown below by downloading RcppSpdlog_0.0.6.tar.gz, untarring, and installing from local source after replacing the files/contents of ...

RcppSpdlog/inst/include/spdlog/fmt/bundled

...with that of...

https://github.com/fmtlib/fmt/tree/master/include/fmt

Please let me know if I can provide any more info, thanks!

Best,
CB

$ uname -a
Linux <host>01-090 2.6.32-431.23.3.el6.x86_64 #1 SMP Thu Jul 31 17:20:51 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ icpc --version
icpc (ICC) 19.0.1.144 20181018
Copyright (C) 1985-2018 Intel Corporation.  All rights reserved.

$ Rscript -e 'R.version.string'
[1] "R version 4.1.1 (2021-08-10)"

$ Rscript -e "install.packages('RcppSpdlog', repos='http://cran.us.r-project.org', destdir=NULL)" 2>&1 | tee fail-log
Installing package into ‘/lustre/project/hpcstaff/<me>/R/Library’
(as ‘lib’ is unspecified)
trying URL 'http://cran.us.r-project.org/src/contrib/RcppSpdlog_0.0.6.tar.gz'
Content type 'application/x-gzip' length 227499 bytes (222 KB)
==================================================
downloaded 222 KB

* installing *source* package ‘RcppSpdlog’ ...
** package ‘RcppSpdlog’ successfully unpacked and MD5 sums checked
** using staged installation
** libs
icpc -std=c++11 -fPIC  -I"/share/apps/R/4.1.1-intel/lib64/R/include" -DNDEBUG -I../inst/include/ -I'/lustre/project/hpcstaff/<me>/R/Library/Rcpp/include' -I/usr/local/include     -flto -c RcppExports.cpp -o RcppExports.o
icpc -std=c++11 -fPIC  -I"/share/apps/R/4.1.1-intel/lib64/R/include" -DNDEBUG -I../inst/include/ -I'/lustre/project/hpcstaff/<me>/R/Library/Rcpp/include' -I/usr/local/include     -flto -c exampleRsink.cpp -o exampleRsink.o
In file included from ../inst/include/spdlog/fmt/bundled/format.h(2825),
                 from ../inst/include/spdlog/fmt/bundled/core.h(3000),
                 from ../inst/include/spdlog/fmt/fmt.h(22),
                 from ../inst/include/spdlog/common.h(36),
                 from ../inst/include/spdlog/spdlog.h(12),
                 from ../inst/include/RcppSpdlog(17),
                 from exampleRsink.cpp(4):
../inst/include/spdlog/fmt/bundled/format-inl.h(1923): error: identifier "ctz" is undefined
    int t = ctz(n);
            ^

In file included from ../inst/include/spdlog/fmt/bundled/format.h(2825),
                 from ../inst/include/spdlog/fmt/bundled/core.h(3000),
                 from ../inst/include/spdlog/fmt/fmt.h(22),
                 from ../inst/include/spdlog/common.h(36),
                 from ../inst/include/spdlog/spdlog.h(12),
                 from ../inst/include/RcppSpdlog(17),
                 from exampleRsink.cpp(4):
../inst/include/spdlog/fmt/bundled/format-inl.h(1951): error: identifier "ctzll" is undefined
    int t = ctzll(n);
            ^

compilation aborted for exampleRsink.cpp (code 2)
make: *** [exampleRsink.o] Error 2
ERROR: compilation failed for package ‘RcppSpdlog’
* removing ‘/lustre/project/hpcstaff/<me>/R/Library/RcppSpdlog’

The downloaded source packages are in
	‘/local/tmp/<me>.1709648/RtmpYMXJvm/downloaded_packages’
Warning message:
In install.packages("RcppSpdlog", repos = "http://cran.us.r-project.org",  :
  installation of package ‘RcppSpdlog’ had non-zero exit status

Interaction between RcppArmadillo and RcppSpdlog seen: `assert` and `stderr` messages from R CMD check

Error description

I implemented standard Github actions for checking my package on push.

I am running the devtools::check() on

  • Ubuntu-20.04
  • macOS-latest

In Ubuntu, no warnings are produced.

In macOS the check fails during test execution with this warning:

>❯ checking compiled code ... WARNING
  File ‘mvMAPIT/libs/mvMAPIT.so’:
    Found ‘___assert_rtn’, possibly from ‘assert’ (C)
      Object: ‘MAPIT.o’
    Found ‘___stderrp’, possibly from ‘stderr’ (C)
      Object: ‘MAPIT.o’
  
 > Compiled code should not call entry points which might terminate R nor
  write to stdout/stderr instead of to the console, nor use Fortran I/O
  nor system RNGs.
  
  > See ‘Writing portable packages’ in the ‘Writing R Extensions’ manual.

The error occurs during execution of tests where I just run the function below.

Code

I was trying to follow exactly the example for usage in a package from the blog entry: https://dirk.eddelbuettel.com/code/rcpp.spdlog.html. Here is what the logger part looks like:

DESCRIPTION:

LinkingTo: Rcpp, RcppArmadillo, testthat, RcppSpdlog

Code

#define SPDLOG_DISABLE_DEFAULT_LOGGER 1
#include <RcppSpdlog>
#include <spdlog/stopwatch.h>           // also support stopwatch feature

...

Rcpp::List MAPITCpp(arma::mat X,
               arma::mat Y,
               ...)
{

   std::string logname = "mvMAPIT";
  auto logger = spdlog::get(logname);                         // retrieve existing one
  if (logger == nullptr) logger = spdlog::r_sink_mt(logname);     // or create new one if needed
  spdlog::set_default_logger(logger);                         // and set as default

  spdlog::stopwatch sw;                                   // instantiate a stop watch

  int i;
  const int n = X.n_cols;
  const int p = X.n_rows;
  const int d = Y.n_rows;
  int q = 0;

  logger->info("Number of samples: {}", n);
  logger->info("Number of SNPs: {}", p);
  logger->info("Number of phenotypes: {}", d);
  logger->info("Test method: {}", testMethod);
  logger->info("Phenotype covariance model: {}", phenotypeCovariance);
  
 ...
 
 }

Github PR in my repository: https://github.com/lcrawlab/mvMAPIT/pull/10/files

Expected behaviour

I would like to be able to use logging both under Ubuntu and macOS without breaking the R CMD check.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.