## ----setup, include=FALSE-----------------------------------------------------
# knitr::opts_chunk$set(echo = TRUE, error = TRUE)  # render R errors as output instead of stopping to knit

## ----error = TRUE-------------------------------------------------------------
try({
log("text")   # calculating the logarithm of a string throws an error
})

## ----results='hold'-----------------------------------------------------------
log(-1)                # logarithm of a negative number throws a warning

## ----error = TRUE-------------------------------------------------------------
try({
if (1 != 2)
  stop("something is wrong")
})

## ----error = TRUE-------------------------------------------------------------
try({
stopifnot(1 == 2)
})

## -----------------------------------------------------------------------------
warning("bad weather today, don't forget your umbrella")

## -----------------------------------------------------------------------------
message("good morning")

## ----error = TRUE, eval = TRUE------------------------------------------------
try({
options(error = NULL)  # switch to default behaviour of pure R

test <- function() {
  log("not a number")
  print("R does stop due to an error and never executes this line")
}

test()     # throws an error
})

## ----error = TRUE, collapse = FALSE, eval = TRUE------------------------------
try({
try(log("not a number"), silent = TRUE)
print("errors can't stop me")
})

## -----------------------------------------------------------------------------
an.error.occured <- FALSE
tryCatch( { result <- log("not a number"); print(res) }
          , error = function(e) {an.error.occured <<- TRUE})
print(an.error.occured)

## -----------------------------------------------------------------------------
tryCatch( { result <- log(-1); print(result) }
          , warning = function(w) { print("Hey, a warning") })

## -----------------------------------------------------------------------------
last.message <- NULL
tryCatch( { message("please handle me"); print("Done") }
          , message = function(m) { last.message <<- m })
print(last.message$message)

## -----------------------------------------------------------------------------
condition <- function(subclass, message, call = sys.call(-1), ...) {
  structure( class = c(subclass, "condition"),
             list(message = message, call = call, ...))
}

tryCatch( { work <- condition("my.work.condition", "after work party")
            signalCondition(work); print("Done") }
          , my.work.condition = function(c) { print(c$message) })

## -----------------------------------------------------------------------------
{ # required to execute the code as one block to summarize the output in this Rmd
  f <- function() {
    warning("deprecated function called")
    print("Hello world")
  }
  f()
  print("Done")
}

## ----echo=FALSE---------------------------------------------------------------
# dummy code to avoid a "missing function" error in the next code junk
write.to.log <- function(msg) { invisible() }

## -----------------------------------------------------------------------------
f <- function() {
  warning("deprecated function called")
  print("Hello world")
}
tryCatch(f(), warning = function(w) { write.to.log(w) })
print("Done")

## ----error = TRUE, eval = FALSE-----------------------------------------------
try({
# options(error=function() traceback(2)) # http://stackoverflow.com/a/13119318/4468078
# f <- function() {
#   log("not a number")
#   print("Hello world")
# }
# f()
})

## ----eval = FALSE-------------------------------------------------------------
# Error in log("not a number") :
#   non-numeric argument to mathematical function
# 6: (function ()
#    traceback(2))() at f.R#3
# 5: f() at f.R#6
# ...
# 1: source("f.R")

## ----error = TRUE, eval = FALSE-----------------------------------------------
try({
# f <- function() {
#   log("not a number")
#   print("Hello world")
# }
# tryCatch(f(), error = function(e) { traceback() })
})

## ----eval = FALSE-------------------------------------------------------------
# 8: value[[3L]](cond)
# 7: tryCatchOne(expr, names, parentenv, handlers[[1L]])
# 6: tryCatchList(expr, classes, parentenv, handlers)
# 5: tryCatch(f(), error = function(e) {
#        traceback(2)
#    }) at f.R#5
# ...
# 1: source("f.R")

## -----------------------------------------------------------------------------
f <- function() {
  warning("deprecated function called")
  print("Hello world")
}
withCallingHandlers(f(), warning = function(w) { write.to.log(sys.calls()) })

## ----results = 'hold'---------------------------------------------------------
f <- function() {
  warning("deprecated function called")
  print("Hello old world")
}
withCallingHandlers(f(), warning = function(w) { write.to.log(sys.calls())
                                                 invokeRestart("muffleWarning")})
print("Done")

## ----results='hold'-----------------------------------------------------------
f <- function() {
  warning("deprecated function called")
  print("A warning cannot stop me")
  log("not a number")
  print("Hello old world")
}

tryCatch(withCallingHandlers(f(), error=function(e) {write.to.log(sys.calls())}
                                , warning=function(w) {write.to.log(sys.calls())
                                                invokeRestart("muffleWarning")})
         , error = function(e) { print("recovered from error") })
print("Done")

## ----eval = FALSE-------------------------------------------------------------
# # install.packages("devtools")
# library(devtools)
# install_github("aryoda/tryCatchLog")

## ----results = 'hide', message = FALSE, echo = FALSE--------------------------
library(tryCatchLog)   # load the package to avoid startup messages in the results later

## ----eval = FALSE, warning=F--------------------------------------------------
# library(tryCatchLog)
# f <- function(value) {
#   print("begin")
#   log(value)            # negative number -> warning; string -> error
#   print("end")
# }
# tryLog(f("not a number"))
# print("Errors don't stop me!")

## ----eval = FALSE-------------------------------------------------------------
# ## [1] "begin"
# ## ERROR [2016-12-06 21:44:21] non-numeric argument to mathematical function
# ## Compact call stack:
# ##   1 test.R#7: tryLog(f("not a number"))
# ##   2 tryCatchLog.R#345: tryCatchLog(expr = expr, write.error.dump.file = write.error.dump.file, error = function(e) {
# ##   3 tryCatchLog.R#259: tryCatch(withCallingHandlers(expr, error = function(e) {
# ##   4 test.R#4: .handleSimpleError(function (e)
# ## ...
# ## [1] "Errors don't stop me!"

## ----eval = FALSE, warning=F--------------------------------------------------
# library(tryCatchLog)
# f <- function(value) {
#   print("begin")
#   log(value)            # negative number -> warning; string -> error
#   print("end")
# }
# tryLog(f(-1))

## ----eval = FALSE-------------------------------------------------------------
# ## [1] "begin"
# ## WARN [2016-12-06 21:33:41] NaNs produced
# ## Compact call stack:
# ##   1 test.R#7: tryLog(f(-1))
# ##   2 tryCatchLog.R#345: tryCatchLog(expr = expr, write.error.dump.file = write.error.dump.file, error = function(e) {
# ##   3 tryCatchLog.R#259: tryCatch(withCallingHandlers(expr, error = function(e) {
# ##   4 test.R#4: .signalSimpleWarning("NaNs produced", quote(log(value)))
# ...
# ## [1] "end"

## ----eval = FALSE-------------------------------------------------------------
# library(tryCatchLog)
# 
# send.email <- function(receiver, body) { }  # dummy function (does nothing)
# 
# tryCatchLog(log("not a number"),
#             error = function(e) { send.email("admin@home", e)
#             })

## ----eval = FALSE-------------------------------------------------------------
# ERROR [2017-01-22 22:04:56] non-numeric argument to mathematical function
# Compact call stack:
#   1 tryCatchLog_error_example.R#5: tryCatchLog(log("not a number"), error = function(e) {
#   2 tryCatchLog.R#273: tryCatch(withCallingHandlers(expr, error = function(e) {
# ...

## ----eval = FALSE-------------------------------------------------------------
#   library(futile.logger)
# 
#   flog.appender(appender.file("app.log"))
# 
#   flog.threshold(ERROR)    # TRACE, DEBUG, INFO, WARN, ERROR, FATAL
# 
#   try(log(-1))             # the warning will not be logged!

## ----eval = FALSE-------------------------------------------------------------
# library(tryCatchLog)
# f <- function(value) {
#   log(value)
# }
# a <- "100"
# tryLog(f(a), write.error.dump.file = TRUE)

## ----eval = FALSE-------------------------------------------------------------
# ERROR [2016-12-12 22:29:52] non-numeric argument to mathematical function
# Call stack environments dumped into file: dump_20161212_222952.rda
# Compact call stack:
#   1 source("~/R_trainings/tryCatchLog/src/test.R")
#   2 test.R#6: tryLog(f(a), write.error.dump.file = TRUE)
#   3 tryCatchLog.R#348: tryCatchLog(expr = expr, write.error.dump.file = write.error.dump.file, error = function(e) {
#   4 tryCatchLog.R#262: tryCatch(withCallingHandlers(expr, error = function(e) {
#   5 test.R#3: .handleSimpleError(function (e)
#   ...

## ----eval = FALSE-------------------------------------------------------------
# load("dump_20161212_222952.rda")    # load the dump into the global environment
# debugger(last.dump)                 # start the post-mortem analysis

## ----eval = FALSE-------------------------------------------------------------
# Message:  non-numeric argument to mathematical functionAvailable environments had calls:
# 1: source("test.R")
# ...
# 5: test.R#6: tryLog(f(a), write.error.dump.file = TRUE)
# 6: tryCatchLog.R#348: tryCatchLog(expr = expr, write.error.dump.file = dump.erro
# 7: tryCatchLog.R#262: tryCatch(withCallingHandlers(expr, error = function(e) {
# ...
# 12: f(a)
# 13: test.R#3: .handleSimpleError(function (e)
# 14: h(simpleError(msg, call))
# 
# Enter an environment number, or 0 to exit
# Selection: <Cursor is waiting for your input here>

## ----eval = FALSE-------------------------------------------------------------
# Enter an environment number, or 0 to exit
# Selection: 12
# Browsing in the environment with call:
#    f(a)
# Called from: debugger.look(ind)
# Browse[1]> ls()
# [1] "value"
# Browse[1]> value
# [1] "100"
# Browse[1]> typeof(value)
# [1] "character"
# Browse[1]>

## ----eval = FALSE-------------------------------------------------------------
# tryCatchLog(expr, ..., finally = NULL,
#   write.error.dump.file = getOption("tryCatchLog.write.error.dump.file", FALSE),
#   silent.warnings       = getOption("tryCatchLog.silent.warnings", FALSE),
#   silent.messages       = getOption("tryCatchLog.silent.messages", FALSE))

## ----eval = FALSE-------------------------------------------------------------
# tryLog(expr,
#   write.error.dump.file = getOption("tryCatchLog.write.error.dump.file", FALSE),
#   silent.warnings       = getOption("tryCatchLog.silent.warnings", FALSE),
#   silent.messages       = getOption("tryCatchLog.silent.messages", FALSE))

## ----results = "hide"---------------------------------------------------------
# Initialize your own default values globally for tryLog and tryCatchLog
options(tryCatchLog.write.error.dump.file = FALSE)
options(tryCatchLog.silent.messages       = TRUE)
options(tryCatchLog.silent.warnings       = TRUE)

test <- function() {
  message("hello")
  warning("a warning")
}

# Use your own default values by ommiting those parameters...
tryLog(f())

# .. instead of the longer version which passes each parameter again and again
tryLog(f(), silent.warnings=TRUE, silent.messages=TRUE, write.error.dump.file=FALSE)

## ----eval = FALSE-------------------------------------------------------------
# library(futile.logger)
# library(tryCatchLog)
# 
# options(keep.source = TRUE)        # source code file name and line number tracking
# options("tryCatchLog.write.error.dump.file" = TRUE) # dump for post-mortem analysis
# 
# flog.appender(appender.file("my_app.log"))  # to log into a file instead of console
# flog.threshold(INFO)    # TRACE, DEBUG, INFO, WARN, ERROR, FATAL
# 
# tryCatchLog(source("your_main_script.R"))

