Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to redirect informal console messages to a file #401

Merged
merged 6 commits into from
May 31, 2018
Merged

Conversation

wlandau
Copy link
Member

@wlandau wlandau commented May 31, 2018

Summary

If verbose is > 0, make() outputs progress message()s to the console.

make(my_plan)
#> target large
#> target small
#> ...

In this PR, make(console = "log.txt") appends these messages to the file "log.txt". That way, users can just inspect a log file instead of polling progress(), and we avoid the issues described in futureverse/future#171 (comment).

Note: if you want to suppress color coding characters, you will need to call options(crayon.enabled = FALSE) in your session and possibly make(prework = "options(crayon.enabled = FALSE)").

cc @lorenzwalthert

Related GitHub issues

Checklist

  • I have read drake's code of conduct, and I agree to follow its rules.
  • I have read the guidelines for contributing.
  • I have listed any substantial changes in the development news.
  • I have added testthat unit tests to tests/testthat to confirm that any new features or functionality work correctly.
  • I have tested this pull request locally with devtools::check()
  • This pull request is ready for review.
  • I think this pull request is ready to merge.

@lorenzwalthert
Copy link
Contributor

lorenzwalthert commented May 31, 2018

I like your paste @wlandau 👍 😊. So is that approach catching communication issued via message() only or also other output such as output issued with cat()?

@codecov-io
Copy link

codecov-io commented May 31, 2018

Codecov Report

Merging #401 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #401   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          65     65           
  Lines        5170   5191   +21     
=====================================
+ Hits         5170   5191   +21
Impacted Files Coverage Δ
R/graph.R 100% <100%> (ø) ⬆️
R/cache.R 100% <100%> (ø) ⬆️
R/console.R 100% <100%> (ø) ⬆️
R/handlers.R 100% <100%> (ø) ⬆️
R/config.R 100% <100%> (ø) ⬆️
R/make.R 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ecbaa87...01709e4. Read the comment docs.

@wlandau wlandau merged commit e6f3788 into master May 31, 2018
@wlandau wlandau deleted the i400 branch May 31, 2018 15:32
@wlandau
Copy link
Member Author

wlandau commented May 31, 2018

@lorenzwalthert, I am not sure I know what you mean. In make(console = NULL) (default), drake uses message(msg) to tell the user about the targets, imports, and checks it goes through (depending on the verbose argument). In make(console = "log.txt"), drake calls write(msg, "log.txt") instead. (See write_to_console().) Overall, drake restricts itself to message(), warning() and stop() to print things. It previously used cat(), but I switched all those calls to message() in late 2017.

@wlandau
Copy link
Member Author

wlandau commented May 31, 2018

drake also captures messages, warnings, and errors generated by individual targets (see run_command()). These side effects are stored with the rest of the metadata, and you can retrieve them later with diagnose(). drake does not currently capture regular stdout() outputs from print(), cat(), etc.

@lorenzwalthert
Copy link
Contributor

Thanks. Maybe I was not specific enough, so here's the reprex:

library(drake)
futile.logger::flog.appender(futile.logger::appender.file("futile-logger"), 
  name = "default")
#> NULL
options(crayon.enabled = FALSE)
just_some_random_communication <- function(a) {
  cat("cat")
  print("print")
  warning("warning")
  message("message")
  as.integer("L")
  futile.logger::flog.error("This is an error", name = "default")
}

plan <- drake_plan(random = just_some_random_communication(4))
clean()
unlink(c("drake-logger", "futile-logger"))
make(plan, seed = 200, console = "drake-logger")
#> cat[1] "print"
#> Warning in just_some_random_communication(4): warning
#> message
#> Warning in just_some_random_communication(4): NAs introduced by coercion
#> Warning: target random warnings:
#>   warning
#>   NAs introduced by coercion
#> Target random messages:
#>   message
readLines("drake-logger")
#> [1] "target random"
readLines("futile-logger")
#> [1] "ERROR [2018-05-31 23:26:27] This is an error"

I think in principle it would be nice to have the warnings and messages created inside the functions inside the drake plan sent to the logging file too instead of the console. But as I said, it does not seem to be a super pressing issue.

I tried to play around a bit with sink() but I could not figure it out. And capture.output() seems too radical.

@wlandau
Copy link
Member Author

wlandau commented Jun 1, 2018

I suppose we could write other messages to the log too, plus warnings and errors. For what it's worth, the log does tell you if a target failed.

@wlandau
Copy link
Member Author

wlandau commented Jun 1, 2018

Update: from 2b0fff2, the log file should now catch errors, warnings, and messages from running the user-supplied commands to build targets. Regular output from cat() is not yet captured. Also, non-target warnings and errors from drake itself are not captured in the log file.

Also, if you specify a file with make(console = "log.txt"), crayon characters are suppressed.

@wlandau
Copy link
Member Author

wlandau commented Jun 1, 2018

And from 7f603e7, stdout output from cat() etc. is captured too.

library(drake)
futile.logger::flog.appender(futile.logger::appender.file("futile-logger"), 
  name = "default")
#> NULL
options(crayon.enabled = FALSE)
just_some_random_communication <- function(a) {
  cat("cat")
  print("print")
  warning("warning")
  message("message")
  as.integer("L")
  futile.logger::flog.error("This is an error", name = "default")
}
plan <- drake_plan(random = just_some_random_communication(4))
clean()
unlink(c("drake-logger", "futile-logger"))
make(plan, seed = 200, console = "drake-logger")
#> Warning in just_some_random_communication(4): warning
#> message
#> Warning in just_some_random_communication(4): NAs introduced by coercion
#> Warning: target random warnings:
#>   warning
#>   NAs introduced by coercion
cat(readLines("drake-logger"), sep = "\n")
#> target random
#> Warning: target random warnings:
#>   warning
#>   NAs introduced by coercion
#> Target random messages:
#>   message
#> Target random console output:
#>   cat[1] "print"
cat(readLines("futile-logger"), sep = "\n")
#> ERROR [2018-06-01 12:49:27] This is an error

@wlandau
Copy link
Member Author

wlandau commented Jun 1, 2018

On second thought, I do not think it is a good idea to capture stdout from the user's calls to print() or cat(). People like to print progress and informally time things with print() statements, and I do not think drake should interfere with this. Reverted in 8817464.

@lorenzwalthert
Copy link
Contributor

Thanks so much @wlandau 😊. I just tried quickly and it works as expected. I can even use the same log file for futile.logger and the terminal output. This is exactly what I wanted. 👍 .

Obviously I can't foresee all use-cases, but it seems to make sense to reserve print() and cat() to be always sent to the console, e.g. for debugging. One could write a wrapper with capture.output() or similar around functions that use cat() and print() in an unexpected manner to keep a clean console.

@wlandau
Copy link
Member Author

wlandau commented Jun 11, 2018

Update: in 1a77aae, I changed the console argument to console_log_file. Much clearer this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants