如何正确登录Sanctuary / Fluture?
How to log properly in 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
。
这太可怕了。
我不希望我的日志比现在更具侵入性,而且我绝对不想用 try/catch
s.
风格的 Promise 乱丢我的代码。
不幸的是,这是我唯一能想到的……我认为最好的选择是备份记录器,例如console.error
在 myLogF
失败时使用,但理想情况下我希望它不可见。
应用程序根本不知道它正在被记录!
问题
因此,鉴于此片段,我有以下问题:
- 如果日志发生故障,您将如何保持链条运行?
- 如何使应用程序看不到日志故障和恢复(而不用等同于 (
try/catch
的东西乱扔垃圾)?
- 最常用的日志模式是什么?
我会专门为 Futures 创建一个 tap
函数,例如:
const always = x => y => x
const tapF = f => x => f(x).fold(always(x), always(x))
这个 tapF
的实现期望 f
到 return 一个未来,它会强制它用原始输入值解析。
然后可以用于日志记录,例如:
request.get("http://mywebsite.com")
.chain( tapF(res => myLogF(`res is: ${res}`)) )
.chain( saveDB )
.chain( tapF(() => myLogF("Saved!")) )
现在这个表达式的结果完全独立于 tapF
函数内部发生的事情。
我相信这应该可以回答您的前两个问题。最后; "What is the most commonly used pattern for logs?",我不确定。那里有一些模式,我能想到两个:
- 在表示副作用的 Monad 中记录为副作用。这就是我们对
tapF
. 所做的
- 使用Writer Monad收集内存中的日志,并在程序边缘写入。我对这种方法没有经验。
背景
我有一个函数,叫做 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
。
这太可怕了。
我不希望我的日志比现在更具侵入性,而且我绝对不想用 try/catch
s.
不幸的是,这是我唯一能想到的……我认为最好的选择是备份记录器,例如console.error
在 myLogF
失败时使用,但理想情况下我希望它不可见。
应用程序根本不知道它正在被记录!
问题
因此,鉴于此片段,我有以下问题:
- 如果日志发生故障,您将如何保持链条运行?
- 如何使应用程序看不到日志故障和恢复(而不用等同于 (
try/catch
的东西乱扔垃圾)? - 最常用的日志模式是什么?
我会专门为 Futures 创建一个 tap
函数,例如:
const always = x => y => x
const tapF = f => x => f(x).fold(always(x), always(x))
这个 tapF
的实现期望 f
到 return 一个未来,它会强制它用原始输入值解析。
然后可以用于日志记录,例如:
request.get("http://mywebsite.com")
.chain( tapF(res => myLogF(`res is: ${res}`)) )
.chain( saveDB )
.chain( tapF(() => myLogF("Saved!")) )
现在这个表达式的结果完全独立于 tapF
函数内部发生的事情。
我相信这应该可以回答您的前两个问题。最后; "What is the most commonly used pattern for logs?",我不确定。那里有一些模式,我能想到两个:
- 在表示副作用的 Monad 中记录为副作用。这就是我们对
tapF
. 所做的
- 使用Writer Monad收集内存中的日志,并在程序边缘写入。我对这种方法没有经验。