Giter Club home page Giter Club logo

futile.logger's People

Contributors

aryoda avatar asieira avatar atheriel avatar averissimo avatar btupper avatar cashpath-bot avatar daroczig avatar fnoorian avatar harlanh avatar hervecommeignes avatar iwccsbfb avatar joehickson avatar kota7 avatar muxspace avatar mvanwyk avatar stanislawraczynski avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

futile.logger's Issues

percentage sign in message

I was logging some messages including a percentage sign, which was working fine until the most recent (1.4) release. E.g. demo with futile.logger_1.3.7:

> flog.debug('%m')
DEBUG [2015-04-15 20:49:02] %m

But now with futile.logger_1.4:

> flog.debug('%m')
Error in (function (fmt, ...)  : unrecognised format specification '%m'
> flog.debug("%a")
Error in (function (fmt, ...)  : too few arguments

Use futile.logger in package

This is not really an issue, rather than question how to apply futile.logger as R package author:

I am looking for some references teaching me how to embed futile.logger functionality into an R package.

Use case:
The R package will provide funtions to the user.
The user of the package shall be able to define the file location and threshold of logging.

Thx for some helpful pointers.

First unnamed argument to flog.info,etc passed as argument 'id'

For a custom json layout based on the package json.layout and layout.format functions, the first unnamed argument is passed as id.

custom.json <- function(level, msg, id='', ...) {

  if (!is.null(substitute(...))) msg <- sprintf(msg, ...)
  output_list <- list(
    level = jsonlite::unbox(names(level)),
    timestamp = jsonlite::unbox(format(Sys.time(), "%Y-%m-%d %H:%M:%S %z")),
    message = jsonlite::unbox(msg),
    func = jsonlite::unbox('unavailable') # haven't worked this out
)
return(sprintf("%s\n", jsonlite::toJSON(output_list, simplifyVector=TRUE)))

}

flog.layout(custom.json)
flog.info('%s ', 'test')
{"level":"INFO","timestamp":"2018-09-11 17:20:50 -0400", "message":"%s ","func":"unavailable"}
flog.info('%s ', 'test', 'test2')
{"level":"INFO","timestamp":"2018-09-11 17:20:56 -0400", "message":"test2 ", "func":"unavailable"}

Removing the id argument from the custom.json function resolves this issue, but I'm not sure why it works since the layout.format seems to be called without any issues using the same signature.

Incorrect namespace determination

I have some code in a package I'm writing (called "WindOps"), and I added some calls to flog.info() in a few functions. In my unit tests, I wanted to turn off the logging, so I put a call to flog.threshold(ERROR, "WindOps") in the tests. However, this didn't shut off the logging.

I discovered that the logger thinks it's in the devtools namespace by adding this code to a logger in a package function:

flog.info("Logging from %s", flog.namespace())

That emits:

INFO [2016-09-07 21:58:49] Logging from devtools

So it seems like flog.namespace() can be fooled somehow?

futile.logger and futures

I use futile.logger a lot in my parallel scripts, all of which use package future to handle multiprocessing.
flog.* of course works well in this case when logging to a file, but does not for logging to the terminal: all messages are relayed at the end of the future.

Is there any way this could be accomplished?

Error 'Could not find function "appender.file2"' with CRAN version

If I use the current CRAN-version it appears that the appender.file2-function is missing.

When I use the current GitHub-version (using devtools::intstall_github("zatonovo/futile.logger")) everything works as expected.

Unfortunately, I am relying on a CRAN-installation, any way around this error?

The error should be reproduced by:

# install.packages("futile.logger")
library(futile.logger)
packageVersion("futile.logger")
#> [1] '1.4.3'

flog.appender(appender.file2("mylog.log", console=TRUE), name='mylogger')
#> Error in appender.file2("mylog.log", console = TRUE): could not find function "appender.file2"

Support file logging rollover

Hi, Thanks for this great add-on.

Is it possible to support daily/periodically file logging rollover like other language logging framework (for example log4j)

Thanks

Concurrent output to console and file

Hi Brian,

Would it be possible to have an easily accessible feature, such as a switch that can be toggled, to make futile.logger send the output to console concurrently with a file.

This feature can come in handy in cases when R crashes and you are unable to copy the log from screen.

Cheers!

Feature: printing of current function call

Hi,

I often find myself writing code to catch the name of the executing function, e.g.:

flog.debug('made it past input checks in %s', as.character(match.call()[[1]]));

Would it be possible to have a shortcut to this, so perhaps something like:

flog.debug('Value of x in %f is %s', x)

Specify log level as a parameter

First of all, thank you very much for this extremely useful package!

I am using it in several packages to auto-generate logs on what data transformations were done at my projects. Things are getting complicated as the number of functions grew, and it turned out that it might not be the best idea to flog.info the number of rows fetched from a database when such query occurs a dozen times in another function, where I'd like to focus on some other items to be logged as INFO, and keep the previous INFO messages as rather DEBUG. This is a simple example, but this can get complicated, believe me :)

In short, I'd like to check if I'm logging in nested or top-level function, and return messages of nested functions with a lower priority. Unfortunately it's not (easily) possible via the flog.info, flog.debug etc. functions -- can we have a flog function that takes the logs with the level specified as an argument?

Suggested optimisation of flog.namespace()

I noticed that most of the time in flog.trace() etal is spent in flog.namespace(). For instance:

Testing the logger functions directly:

flog.threshold(INFO)

Default:

Rprof(line.profiling = TRUE)
for (i in 1:20000) { flog.trace("A message") }
Rprof(NULL)
summaryRprof(lines = "both") # 28.58 seconds

Avoiding flog.namespace():

Rprof(line.profiling = TRUE)
for (i in 1:20000) { flog.trace("A message", name = 'ROOT') }
Rprof(NULL)
summaryRprof(lines = "both") # 3.98 seconds

So 80-90 % of the time is spent in getting the name of the name space. Profiling flog.namespace() directly, indicated that it is in capture.output() and/or str() the time is spent. Looking into the code of str(), I saw that for environments, it basically does format(), so I tested with an alternative way of getting the string representation of the environment, i.e. instead of

s <- capture.output(str(topenv(environment(sys.function(where))), give.attr=FALSE))

I tried

s <- format(topenv(environment(sys.function(where))))

Profiling showed that the alternative implementation of flog.namespace() is much faster:

Testing flog.namespace() directly:

Rprof(line.profiling = TRUE)
for (i in 1:20000) { tmp <- flog.namespace() }
Rprof(NULL)
summaryRprof(lines = "both") # 14.82 seconds

Alternative flog.namespace() directly:

Rprof(line.profiling = TRUE)
for (i in 1:20000) { tmp <- flog.namespace2() }
Rprof(NULL)
summaryRprof(lines = "both") # 3.32 seconds

And when using the alternative flog.namespace() in flog.trace(), it ran about twice as fast as before:

With alternative flog.namespace():

Rprof(line.profiling = TRUE)
for (i in 1:20000) { flog.trace2("A message") }
Rprof(NULL)
summaryRprof(lines = "both") # 17.14 seconds.

My understanding of environments etc is not perfect, so I cannot guarantee that the alternative will work in all cases, but at least it seems to work for the cases I've tested.

The reason for suggesting the optimisation is that I tend to put a lot of trace messages in my code while developing it, and then increase the log level when actually using the code. Therefore I don't want too much overhead of logging calls, at least not when they don't print anything. (I had a case where 97 % of the time was spent inside flog.trace() when the threshold was INFO.)

Write to Multiple Logs

I have a need to write to multiple log files which correspond to different threshold levels. We have log files that get progressively more detailed. So we have a log file for TRACE and higher, a log file for INFO and higher, and a log file for ERROR and higher.

I could build loggers for each of these like:

flog.logger(name='trace',threshold=TRACE, appender=appender.file('trace.txt'))
flog.logger(name='info',threshold=INFO, appender=appender.file('info.txt'))
flog.logger(name='error',threshold=ERROR, appender=appender.file('error.txt'))

but then I have to litter my code with a bunch of statements like:

flog.info('test', name = 'trace')
flog.info('test', name = 'info')
flog.info('test', name = 'error')

Ideally, I'd write one flog.info method and it logs to all of my appenders.

Maybe I'm doing it wrong. Can multiple appenders by added to a log based on thresholds? It looks like log4j supports that functionality but I cant figure it out with this package. Or is there another approach to take? Any help would be great.

flog.logger not found from lambda.r 1.2.x

Hi,

I'm using Futile Logger with the root logger, but with a tee.appender to both console and to a log file.

I've set R options so that console errors also get written to the log via:
options(error = function() { flog.error(geterrmessage()) ; traceback() ; stop() })

On a fresh install of my software an R system error would also generate a package error flog.logger not found

After some investigation is seems that using lambda.r_1.1.9 does not generate this error, but 1.2.x does.

I'm guessing it's some sort of namespace error?

Best
Alan

PS - thanks for the great package!

Log data frame to file and console

What's the best way to log a dataframe to a file? I found this question in SO and tried doing something like

    flog.logger(name = "logger", threshold = DEBUG,
                        appender = appender.tee(file.path(LOG_DIR, "transform.log")))
    flog.info(write.table(df, sep="\t"), name = "logger")

However I doesn't seem to do the trick. Thanks in advance

How to use futile.logger to override the default warnings

I can override the default R error handling for a non-interactive program by doing options(error = function() { flog.error(geterrmessage()) ; quit(runLast=FALSE)})

However I did not find how to do the same for warnings. Is this possible?

This stack overflow question basically poses the same question, but the accepted answer does not seem to work for me.

Writing errors to log with ftry

Hi,

Awesome tool.

I am trying to log errors from within a function in a sourced script.

ftry(myfunction,error = 
       function(e) {
          call.stack <- sys.calls()   
          log.message <- e$message
          flog.error(log.message)
                         })

But in spite of errors, nothing is written to the log. Can you advise me on how to use FTRY in this context?

Thanks again for an awesome tool!

Cannot build package

The DESCRIPTION file is a template as of revision 770683a. This is unfortunate, as this makes installation from GitHub using devtools's install_github() function impossible. I'm sure there is some magic that replaces the {date} and {version} placeholders with their values, but where?

Perhaps this could be replaced by an "update" magic: Always store the current value in the code, and provide a script that sets date and version to new values?

Configure the logging level based on a string

I want to configure the logging level based on strings, e.g. "WARN", but flog.threshold(..) only accepts the numbers that are accessible via the global constants such as futile.logger::TRACE. I wrote the following small helper function, but I'm sure you could also easily change flog.threshold to accept string values in the same way.

getLoglevelForName <- function(x) {
    name <- tolower(x)

    level <- switch(x, "trace" = futile.logger::TRACE,
                    "debug" = futile.logger::DEBUG,
                    "warn" = futile.logger::WARN,
                    "info" = futile.logger::INFO,
                    "error" = futile.logger::ERROR,
                    "fatal" = futile.logger::FATAL)
    if(is.null(level))
        return(futile.logger::INFO)
    return(level)
}

Am I missing a way that this is aready possible?

Would you accept a pull request adding this feature to flog.threshold?

different thresholds for different appenders

This may not be so much a feature request as a question:

Is it possible to append to both file and console but to choose different thresholds for each? I.e. can I log errors to console but info to file?

Request - function for logging & stopping

We often find ourselves doing this:

msg <- "Something happened"
flog.error(msg)
stop(msg)

It would be great if this had some syntactic sugar in futile.logger, so we could just do this:

flog.throw("Something happened")

An additional enhancement could be to take a class argument indicating the type of error stop should create. Not sure how that should work, though.

flog.debug, flog.threshold(DEBUG) - aren't working

I spent a few hours trying to figure out why my debug statements weren't being output after I set my logging threshold to DEBUG, as shown below:

flog.threshold(DEBUG);
flog.debug("this is my message"); # doesn't show up

After reviewing the source in logger.R, I can see the flog.debug statement appears to depend on the TRACE level, rather than a DEBUG level?

flog.debug <- function(msg, ..., name=get_namespace()) {
  .log_level(msg, ..., level=TRACE,name=name)
}

I think this is a bug, but noticed throughout the documentation that only trace, info, warn and error log levels are referred to, so I'm not sure. A debug level makes sense....

Matt.

flog.appender error with lambda.r 1.1.3

> library(futile.logger)
Loading required package: lambda.r
Loading required package: futile.options
> flog.appender(appender.file("test.log"), name="test.out")
Error in as.character(function (line)  :
  cannot coerce type 'closure' to vector of type 'character'
> traceback()
5: sprintf("'%s(%s)'", fn.name, args)
4: use_error(.ERR_NO_MATCH, fn.name, raw.args)
3: stop(use_error(.ERR_NO_MATCH, fn.name, raw.args))
2: UseFunction("flog.appender", ...) at <text>#1
1: flog.appender(appender.file("test.log"), name = "test.out")
> sessionInfo()
R version 3.0.1 (2013-05-16)
Platform: x86_64-apple-darwin10.8.0 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

other attached packages:
[1] futile.logger_1.3.3  futile.options_1.0.0 lambda.r_1.1.3
>

Brian said to reinstall futile.logger to fix the problem. Reinstalling the binary did not fix the problem, but reinstalling with type="source" did fix it. This makes me wonder whether a version bump would cause CRAN to produce binaries that would not have this problem. I don't know if it would but it's worth trying, probably.

Line number

Hi, is it possible to print in the log also the line number?

Thanks
Diego

layout.json not interpolating message string

The layout.json function is putting string interpolation arguments on the output as json fields instead of interpolating the message template.

library(futile.logger)
flog.info('test %s', 'interp')
INFO [2018-09-11 15:44:46] test interp

but after changing the layout:

flog.layout(layout.json)
flog.info('test %s', 'interp')
{"level":"INFO","timestamp":"2018-09-11 15:45:15 -0400","message":"test %s","func":"(shell)","5":["interp"]}

The interp argument shows up as field "5" on the output and the message template is unchanged.

I'm running futile.logger 1.4.3 on R 3.4.3.

Logger name in the message

I think it would be great if the message includes the logger name, like

> library(futile.logger)
> flog.info("foo", name="mylogger")
INFO | mylogger | 2018-01-11 17:41:13 : foo

At the beginning, I thought custom layout with "~n" (namespace) and "~f" (function) provides good information about where the logs come from, but when functions are nested, mere function names are not very helpful.

If this is already supported, please kindly let me know.

Error setting layout with lambda.r 1.1.3

I am currently using futile.logger 1.3.3 and just upgraded lambda.r to 1.1.3 on a Mac OS X with R 3.0.1. This used to work perfectly but is now giving me an error message:

flog.layout(
  function(level, msg, ...) {
    the.time <- format(Sys.time(), "%Y-%m-%d %H:%M:%S %Z")
    if (!is.null(substitute(...)))  msg <- sprintf(msg, ...)
    sprintf("%s [%s] pid=%i %s\n", names(level), the.time, Sys.getpid(), msg)
  }
)

This is the error message:

Error in as.character(function (level, msg, ...)  (from <text>#1) : 
  cannot coerce type 'closure' to vector of type 'character'

Enter a frame number, or 0 to exit   

1: flog.layout(function(level, msg, ...) {
    the.time <- format(Sys.time(), "%Y-%m-%d %H:%M:%S
2: <text>#1: UseFunction("flog.layout", ...)
3: stop(use_error(.ERR_NO_MATCH, fn.name, raw.args))
4: use_error(.ERR_NO_MATCH, fn.name, raw.args)
5: sprintf("'%s(%s)'", fn.name, args)

Any ideas what might be going on?

Capture warning(), etc.

There is one feature I'd really like to see in futile.logger, and that is the ability to capture the messages from message(), warning() and stop(). That would be a killer feature, IMO. It would make it very easy to add systematic logging to old code.

Is this something you could consider implementing in futile.logger?

I'm aware of one package that supports this (https://github.com/smbache/loggr).

Dates don't print correctly

I'm pretty sure the use of c(msg, parsed) here strings the arguments of their classes so for instance dates are printed as their integer value.

msg <- do.call(sprintf, c(msg, parsed))

I'm not an R expert but maybe this could be resolved by using c(list(msg), parsed)

increment version number?

Might I suggest that you increment the version in DESCRIPTION?

 Package: futile.logger
 Type: Package
 Title: A Logging Utility for R
-Version: 1.4.3
+Version: 1.4.3.9000
 Date: 2016-07-10
 Author: Brian Lee Yung Rowe
 Maintainer: Brian Lee Yung Rowe <[email protected]>

I recently looked in your code and found functionality I was hoping to find (a PR you merged into layout.json). When I noticed that this version and the one on CRAN were the same, I installed from CRAN ... but lo-and-behold, it wasn't there.

My use of .9000 is a convention I've seen that indicates a development version, saving 1.4.4 for the next release to CRAN. Something that distinguishes it from the CRAN version is the important part.

Thank you!

futile.logger & concurrent shiny sessions

We are using futile.logger in an R shiny application.
The logger writes user error messages from the application to a log file in the root directory of the application on our R server (linux).
As Shiny allows for multiple sessions to run concurrently we have a concern: if two application sessions would be writing to the same log file at the same time, would futile.logger handle this correctly? Or would the second session, that finds an open log file while trying to write, generate an error message?

We use the function flog.info to write to the log file.

Thanks.

Semantics of ftry and try are different (warnings should not stop further evaluation of the expression param)

If a warning occurs in ftry the evaluation of the expression is stopped due to establishing a warning handler in tryCatch (handled conditions in tryCatch do always stop the further evaluation).

try of base R behaves differently.

Proposal: Fix or document different semantics...

Example:

library(futile.logger)
sessionInfo()  # futile.logger_1.4.3

ftry({
       log(-1)   # throws a warning ("NaNs produced")
       print("warnings should not stop evaluation of this expression")
})
# WARN [2017-12-26 10:01:09] NaNs produced



# Compare:
try({
  log(-1)   # throws a warning ("NaNs produced")
  print("warnings should not stop evaluation of this expression")
})
# [1] "warnings should not stop evaluation of this expression"
# Warning message:
# In log(-1) : NaNs produced

The solution would establish a warning handler using withCallingHandlers within tryCatch...

[base.source] as namespace.function information from layout when running a script

It is related with the issue #21, and it works for me under RTMVS (R-Tools for Microsoft Visual Studio) when a select part of the script and execute it:

[INFO] [2017-02-14 17:58:01] [ROOT.(shell)] Begin
[INFO] [2017-02-14 17:58:01] [ROOT.f] Test
[INFO] [2017-02-14 17:58:01] [ROOT.(shell)] End

but, when I source the entire script: source("~/R-workspace/projects/RoR/RoR/sampleScript.R", encoding = "Windows-1252")

I get the following output:

[INFO] [2017-02-14 17:58:41] [base.source] Begin
[INFO] [2017-02-14 17:58:41] [base.source] Test
[INFO] [2017-02-14 17:58:41] [base.source] End

This is my sample script:

library(futile.logger) # The logger used
layout <- layout.format('[~l] [~t] [~n.~f] ~m')
flog.layout(layout)
flog.info("Begin")
f <- function() futile.logger::flog.info("Test")
f()
flog.info("End")

UPDATE
I also tested it under RStudio:

Using Run button for selected part of the source code:

> flog.info("Begin")
[INFO] [2017-03-03 09:18:14] [ROOT.(shell)] Begin
> f <- function() futile.logger::flog.info("Test")
> f()
[INFO] [2017-03-03 09:18:14] [ROOT.f] Test
> flog.info("End")
[INFO] [2017-03-03 09:18:14] [ROOT.(shell)] End
> 

but when using Source button:

> source('~/.active-rstudio-document')
[INFO] [2017-03-03 09:19:59] [base.source] Begin
[INFO] [2017-03-03 09:19:59] [base.source] Test
[INFO] [2017-03-03 09:19:59] [base.source] End
> 

I alo get the same result under R standard console (for windows).

What I am doing wrong here? is it a bug? Did not find any information in the documentation about how to use flog with the function source. Thanks.

Note: I have seen that for the majority of the bugs at least you provide some comment but not for this one, please can you provide some feedback. Thanks.

Print variables along with their name

I often find myself to write

flog.trace("x: %s", x)

What do you think about supporting

flog.trace(x)

as a shortcut? This should be accompanied by a parameter to explicitly turn on or off this behavior:

flog.trace(msg, ..., name=get_namespace(), capture=FALSE, print.name=!is.character(msg))

The same holds for all other debug levels, of course.

NULL list items don't behave properly

Using 1.3.7:

flog.info('Here is a null object: %s', NULL)

>INFO [2014-05-07 17:03:09] Here is a null object: %s

opt <- list()
opt$foo
>NULL

flog.info('Here is a null object: %s', opt$foo)
(no output)

identical(opt$foo, NULL)

[1] TRUE

Log layout bug when calling function explicitly

When I configure the log layout [~l] [~t] [~n.~f] ~m and then call the function explicitly as in

library("futile.logger")
futile.logger::flog.layout(layout.format("[~l] [~t] [~n.~f] ~m"))
futile.logger::flog.info("Test...")

I get the following warning:

[INFO] [2014-10-09 14:50:40] [futile.logger.::] Test...
Warning message:
In gsub("~f", the.function, message, fixed = TRUE) :
  argument 'replacement' has length > 1 and only the first element will be used

Probably an issue parsing the :: ?

Testing with `testthat::expect_warning`

I have a function that calls flog.warn under certain conditions, and I want to test those conditions. However, it looks like the warning doesn't go through the channels that testthat::expect_warning expects it to:

> expect_warning(
+     solution <- do.call(my.function, args),
+     regexp = 'Missing regime types .* offpeak'
+   )
WARN [2018-07-03 17:52:42] Missing regime types in 'last.period.peaks': offpeak; filling with zeroes
Error: `solution <- do.call(my.function, args)` did not produce any warnings.

So the warning makes it to STDOUT or STDERR, and doesn't get captured by expect_warning, so the test fails.

Is there some other way to accomplish this easily?

Getting the threshold of a custom logger

Is it true that flog.threshold(name='myLogger') is supposed to return the name of the custom logger? If so it does not seem to work. Using a cloned repository I tried the following additional tests:

 flog.threshold(ERROR)
 expect_that(flog.threshold() == "ERROR", is_true())  ### WORKS
 flog.threshold(DEBUG, name='my.package')
 expect_that(flog.threshold(name='my.package') == DEBUG, is_true())  ### FAILS

If this is not how this is supposed to work, is there some other way get this information?

Feature: Intercept warning() function ( with flog.warn() )

Firstly, thanks for this great package- I'm a big user, it has met a real need for me!

I was wondering if you'd consider intercepting warning() statements with futile.logger? From email you suggested it would be hard as warning is low-level, but would be a great addition.

Show thread number in messages

Use case:

When using foreach with parallel library (%dopar%) it would be nice to have the thread number ou process where it is executing.

Appender that writes to syslog

It would be really useful if the package provided a default appender that submits logs to the local syslog process (if it exists) in a Mac OS X or *nix machine. :)

FATAL log entry and stop()

First of all, thanks for the great module. Simple, elegant and powerful.

I have a suggestion. I find that it is probably expected that logging a FATAL log entry will soon be followed by a call to stop with the exact same string. A sample code I've written:

if (condition) {
   message = sprintf("myFunc: invalid whatever %s", var)
   flog.fatal(message)
   stop(message)
}

I was hoping you could change the flog.fatal, flog.trace, etc functions to return the string value of the final message generated by the layout function. This way, the above code could be rewritten in a smaller and more readable form:

if (condition) stop(flog.fatal("myFunc: invalid whatever %s", var))

1.3.3 change in capture handling? No new line

Hi,

1.3.3 seems to have changed the way captures are printed, for example in an interactive session:

1.3.3:

> flog.info('Alphabet', capture=TRUE, letters)
INFO [2013-07-30 17:19:40] Alphabet
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"> 

vs
1.3.1

> flog.info('Alphabet', capture=TRUE, letters)
INFO [2013-07-30 17:19:28] Alphabet

 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
> 

There is a new line missing before the capture (no problem), but the lack of a new line afterwards means my logs are much harder to read than before.

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.