【问题标题】:Printing Timestamps while Debugging in Haskell在 Haskell 中调试时打印时间戳
【发布时间】:2017-01-14 21:31:26
【问题描述】:

我还在学习 Haskell 和调试一些函数,并且通常有一个时间戳函数来了解某些操作何时开始和停止:

doSomeAction :: String -> IO ()
doSomeAction arg1 = do
  putStrLn =<< makeTime
  theThingthatTakesAwhile arg1
  putStrLn =<< makeTime
  where
    makeTime = (formatTime defaultTimeLocale "%Y%m%d%H%M%S") <$> getZonedTime

我的=&lt;&lt;where 子句包含&lt;$&gt; 是与getZonedTime 周围的IO 交互的合理方式吗?

λ> :t getZonedTime
getZonedTime :: IO ZonedTime

或者这是对我或读者的误导还是非惯用语?

输出是:

20170114152312
Doing some long function....
20170114152336

这正是我想看到的——它告诉我我需要什么。对putStrLn =&lt;&lt; something 来说,获得这种效果似乎很奇怪。

【问题讨论】:

    标签: haskell io bind


    【解决方案1】:

    您的代码非常好。任何精通 Haskell 的程序员都应该很快理解它。

    不过,在我自己的风格中,我倾向于在 do 块中更喜欢 let

    doSomeAction :: String -> IO ()
    doSomeAction arg1 = do
      let makeTime = formatTime defaultTimeLocale "%Y%m%d%H%M%S" <$> getZonedTime
      putStrLn =<< makeTime
      theThingthatTakesAwhile arg1
      putStrLn =<< makeTime
    

    或者可能是一些变化

    doSomeAction :: String -> IO ()
    doSomeAction arg1 = do
      let printTime = putStrLn . formatTime defaultTimeLocale "%Y%m%d%H%M%S" =<< getZonedTime
      printTime
      theThingthatTakesAwhile arg1
      printTime
    

    不过,这只是个人喜好问题。

    【讨论】:

      【解决方案2】:

      如果你使用一些日志库,你可以做得更好。例如hslogger。它可以打印带有时间戳的消息。您可以在此问题下查看用法示例:hslogger & Duplicate Log Lines

      UPD: 记录时间戳的示例

      这里是初始化日志的模块的完整示例:

      import           Control.Concurrent        (threadDelay)
      import           System.IO                 (stdout)
      import           System.Log.Formatter      (simpleLogFormatter)
      import           System.Log.Handler        (setFormatter)
      import           System.Log.Handler.Simple (streamHandler)
      import           System.Log.Logger         (Priority (DEBUG), debugM, rootLoggerName,
                                                  setHandlers, setLevel, updateGlobalLogger)
      
      initLogging :: IO ()
      initLogging = do
          stdOutHandler <- streamHandler stdout DEBUG >>= \lh -> return $
                  setFormatter lh (simpleLogFormatter "[$loggername:$time] $msg")
          updateGlobalLogger rootLoggerName (setLevel DEBUG . setHandlers [stdOutHandler])
      
      doSomeAction :: String -> IO ()
      doSomeAction arg1 = do
          debugM "someAction" "before long thing"
          theThingThatTakesAWhile arg1
          debugM "someAction" "after long thing"
      
      theThingThatTakesAWhile :: String -> IO ()
      theThingThatTakesAWhile arg = threadDelay (3 * 10^(6 :: Int)) >> putStrLn arg
      
      main :: IO ()
      main = do
          initLogging
          doSomeAction "some long action" 
      

      输出是:

      [someAction:2017-01-16 17:19:49 MSK] before long thing
      some long action
      [someAction:2017-01-16 17:19:52 MSK] after long thing
      

      如果您希望将时间打印为时间戳(仅秒),则可以使用 tfLogFormatter 函数指定消息的确切格式。

      【讨论】:

      • 你能提供一个例子来帮助我理解如何在我的函数之外声明初始化,以便我可以轻松地在里面调用updateGlobalLogger rootLoggerName吗?
      • @Mittenchops 我已经用日志初始化示例更新了答案。
      猜你喜欢
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 2017-10-28
      • 2014-10-19
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      相关资源
      最近更新 更多