如何正确登录Sanctuary / Fluture?

时间:2018-07-26 08:37:25

标签: logging functional-programming sanctuary fluture

背景

我有一个名为logInfoAsync的函数。让我们考虑一下该函数通过网络将一些信息发送到日志服务器。出于这个问题的目的,我们假设该函数的实现如下:

const logInfoAsync = logger => message =>
    new Promise( ( resolve, reject ) => {
        setTimeout( () => {
            //random fail reason.
            if( message.length > 10 ){ 
                reject( "We have angered the Gods. Message is too big!" );
                return;
            }
            logger(message);
            resolve();
        }, 2000 );
    })

用法:

const myLog= logInfoAsync( console.log );
myLog("Hello world!") // Rejected: "We have angered the Gods. Message is too big!"
myLog("Hello") // Resolved: "Hello"

问题

到目前为止,一切都很好。我们有一个标准的记录器,有时会起作用,有时会激怒众神。

现在,让我们假设我们有一系列连续的async计算:

const { Future } = require("Fluture");

const myLogF= Future.encaseP( logInfoAsync( console.log ) );

//request.get returns a Future and so does saveDB
request.get("http://mywebsite.com")
    .chain( response => myLogF(`res is: ${res}`) )
    .chain( saveDB )
    .chain( ( ) => myLogF("Saved!") )
    .fork(
        err => console.log(`Something failed badly!: ${err}`),
        ( ) => console.log("Data saved to Olympus with great success!")
    );

在此示例中,如果记录器激怒众神会发生什么? 好吧,我们无法保存数据!也许请求很好,也许数据有效,但是由于记录器失败,我们搞砸了!

研究

现在,可能的解决方案是在每个日志之后使用Fluture.bimap这太可怕了

我不希望自己的日志更具侵入性,而且我绝对不希望使用Promise样式的try/catch乱扔我的代码。

不幸的是,这是我唯一可以考虑的事情...我认为最好的选择是备份记录器,例如,console.error应该使用myLogF失败了,但理想情况下,我希望它不可见。

应用程序根本不应该知道它正在被记录!

问题

因此,鉴于此摘要,我有以下问题:

  1. 如果日志失败,您将如何保持链条运行?
  2. 如何使日志失败和恢复对应用程序不可见(而不用(try/catch来代替它)?
  3. 最常用的日志模式是什么?

1 个答案:

答案 0 :(得分:2)

我将专门为期货创建一个tap函数,例如:

const always = x => y => x
const tapF = f => x => f(x).fold(always(x), always(x))

tapF的实现期望f返回Future,并将强制其使用原始输入值进行解析。

然后可以将其用于记录,例如:

request.get("http://mywebsite.com")
.chain( tapF(res => myLogF(`res is: ${res}`)) )
.chain( saveDB )
.chain( tapF(() => myLogF("Saved!")) )

现在,此表达式的结果完全独立于tapF函数内部的情况。

我认为应该回答您的前两个问题。最后; “最常用的日志模式是什么?”,我不确定。有几种模式,我可以想到两种:

  • 在Monad内部记录为副作用的代表副作用。这就是我们对tapF所做的事情。
  • 使用Writer Monad收集内存中的日志,并将其写入程序的边缘。我没有这种方法的经验。