【问题标题】:send R diagnostic messages to stdout instead stderr将 R 诊断消息发送到 stdout 而不是 stderr
【发布时间】:2020-10-20 19:20:55
【问题描述】:

寻找一个选项,让我将 R 诊断消息(由 message() 生成)重定向到 stdout,而不是默认情况下的 stderr

message 手动状态:

默认处理程序将消息发送到 stderr() 连接。

所以问题是如何更改此默认行为?仍然保持warning()stop() 的重定向不变。

已经尝试过 sink type='message',但它会重定向所有(消息、警告、错误)。

如果有人愿意测试,这是示例脚本exec_test.R

print("using print")
cat("using cat\n")
message("using message")
warning("using warning")
stop("using stop")
q("no")

然后将被执行:

Rscript exec_test.R 1>> exec_test.Rout 2>> exec_test_error.Rout

我不使用 2>&1,因为我的脚本会产生大量 messages,而且很少出现真正的错误,因此我需要将这些日志存储在单独的文件中。

【问题讨论】:

  • 为什么要这样做?当你运行它时,如果你在某处记录它,你不能只添加2>&1 吗?
  • @doctorlove 我已经更新了问题。
  • 我不敢相信人们看不到这样做的好处 - 将消息、警告和错误全部发送到 stderr 并在 R 控制台中以相同的颜色打印意味着您无法在潜在的众多诊断消息中发现实际问题?!
  • 我一直在寻找没有运气的答案。我也有同样的情况。我希望我的 stderr 日志在操作上有意义,而不是某些随机包作者决定的任何内容,但我不想只是将它们关闭。我希望他们在更详细的日志中报告,而不是标准错误。
  • @jamie.f.olson 您可能总是要求包维护人员将message 更改为cat + 提供指向此 SO 的链接。简单地说,message 如果发送到 stderr,则不能被视为 消息,因此不应将其用作 消息

标签: r stdout message stderr


【解决方案1】:

使用sink。这是您的代码的修改:

sink(stdout(), type = "message") # sink messages to stdout
print("using print")
cat("using cat\n")
message("using message")
warning("using warning")
sink(NULL, type="message") # close the sink
warning("after ending sink") # this will be the only thing in your err file
q("no")

【讨论】:

  • 脚本中的各个地方都可能出现错误,我怎么知道sink messages to stdout在哪里以及close the sink在哪里?
  • 我想您希望我的示例的第一行成为脚本的第一行。您可以随心所欲地关闭水槽;可能在脚本的最后。
  • 如果我在脚本结束时关闭接收器,它根本不会将真正的错误(从 stop())重定向到标准错误。
  • 但是任何messages 都不会去stdout,而是去stderr,我只想将错误和警告重定向到stderr,并将消息重定向到stdout
  • @MusX 如果不重新定义各种消息功能,我认为这是不可能的。
【解决方案2】:

OP 显示了通过 Rscript 命令和使用一些 I/O 重定向发生的执行。如果您想使用重定向来记录所有内容并且仅在错误时显示到控制台,我发现的最佳方法是使用|| 在打印到屏幕之前检查脚本是否具有非零退出状态:

Rscript myrscript.R > temp.log 2>&1 || cat temp.log

此方法严格依赖于打印的退出代码,它仅部分绕过 message() 进入 stderr,但我认为此示例有助于提及,因为消息不一定会触发非零退出状态,您可以继续用这个方法安静地登录。

如果您想更进一步并继续附加到单个日志文件,那么这将起作用:

Rscript myrscript.R > temp.log 2>&1 || cat temp.log && cat temp.log >> persistent.log && rm temp.log

这个命令的伪代码是:

  1. stderrstdout 重定向到 temp.log 中
  2. 如果命令具有非零退出状态,则写入屏幕
  3. 然后将 temp.log 的内容重定向到您的 persistent.log
  4. 然后删除 temp.log

【讨论】:

    【解决方案3】:

    虽然这很可能不是最佳做法,但您可以使用默认写入 stdout() 的版本覆盖 message,对吧?

    message <- function (..., domain = NULL, appendLF = TRUE) 
    {
        args <- list(...)
        cond <- if (length(args) == 1L && inherits(args[[1L]], "condition")) {
            if (nargs() > 1L) 
                warning("additional arguments ignored in message()")
            args[[1L]]
        }
        else {
            msg <- .makeMessage(..., domain = domain, appendLF = appendLF)
            call <- sys.call()
            simpleMessage(msg, call)
        }
        defaultHandler <- function(c) {
            cat(conditionMessage(c), file = stdout(), sep = "")
        }
        withRestarts({
            signalCondition(cond)
            defaultHandler(cond)
        }, muffleMessage = function() NULL)
        invisible()
    }
    

    【讨论】:

    • 感谢伟大的代码。它不会严格将message 重定向到stdout,但它会将message 转换为output,这在interactive 会话的情况下是不需要的行为。如果没有更好的解决方案我会使用这个,也许只是在开头插入if(interactive())
    • 那是因为在交互式会话中,发送到 stdout 的所有内容都是您的 output。 ;)
    • 这在交互式控制台中调用 message() 时有效,但在库调用 message() 时无效。有没有办法在全球范围内覆盖它?我尝试将@export 放在message 函数的上述定义上,但这没有效果。
    【解决方案4】:

    将@Thomas 和@branch14 的答案合二为一,这就是我想出的:

    .stderr_message <- message
    message <- function(...) {
        sink(stdout(), type = "message")
        .stderr_message(...)
        sink(NULL, type = "message")
    }
    

    我使用此代码在 shell 上验证了这一点

    .stderr_message <- message
    message <- function(...) {
        sink(stdout(), type = "message")
        .stderr_message(...)
        sink(NULL, type = "message")
    }
    
    print(1)
    message(1)
    

    没有我的message()

    > Rscript bug.R 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
    stdout: [1] 1
    stderr: 1
    
    > Rscript bug.R 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
    stdout: [1] 1
    stdout: 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 2015-07-04
      • 2019-03-29
      • 1970-01-01
      相关资源
      最近更新 更多