我一定不知道如何正确使用hslogger。我收到此错误消息:
hsloggerTest1: test.log: hPutStr: illegal operation (handle is closed)
当我在hsloggerTest1.hs
中运行此代码时-- hslogger
import System.Log.Logger ( Priority(ERROR), addHandler
, errorM, updateGlobalLogger
)
import System.Log.Handler (close)
import System.Log.Handler.Simple (fileHandler)
main :: IO ()
main = do
let logger = "main"
fileName = "test.log"
h1 <- fileHandler fileName ERROR
putStrLn "opened file1"
updateGlobalLogger logger $ addHandler h1
putStrLn "will write1"
errorM logger "writing 1"
putStrLn "did write1"
close h1
putStrLn "closed file1"
h2 <- fileHandler fileName ERROR
putStrLn "opened file2"
updateGlobalLogger logger $ addHandler h2
putStrLn "will write2"
errorM logger "writing 2"
-- putStrLn "did write2"
-- close h2
-- putStrLn "closed file2"
test.log的内容是:
writing 1
writing 2
我做错了什么? (或者这是一个hslogger错误?)谢谢。
顺便说一句,我已经通过一些重组修复了我的实际代码中的问题。但是,我仍然很好奇为什么我上面做的是错误的。
答案 0 :(得分:1)
我没有看到删除处理程序的接口,因此为了使上面的代码工作,我使用了setHandlers并覆盖了之前的处理程序,如果这有助于你的用例。
import System.Log.Logger ( Priority(ERROR), addHandler, setHandlers
, errorM, updateGlobalLogger
)
import System.Log.Handler (close)
import System.Log.Handler.Simple (fileHandler)
import Data.Time.Clock
main :: IO ()
main = do
let logger = "main"
fileName = "test.log"
h1 <- fileHandler fileName ERROR
putStrLn "opened file1"
updateGlobalLogger logger $ setHandlers[h1]
putStrLn "will write1"
c1 <- getCurrentTime
errorM logger $ "writing 1 " ++ (show c1)
putStrLn "did write1"
close h1
putStrLn "closed file1"
h2 <- fileHandler fileName ERROR
putStrLn "opened file2"
updateGlobalLogger logger $ setHandlers[h2]
putStrLn "will write2"
c <- getCurrentTime
errorM logger ("writing 2 " ++ (show c))
putStrLn "did write2"
-- close h2
-- putStrLn "closed file2"
日志文件的内容:
writing 12014-02-27 23:03:35.0594493 UTC
writing 2 2014-02-27 23:03:35.0754502 UTC
更新: 这就是我解释http://hackage.haskell.org/package/hslogger-1.0.7/docs/System-Log-Logger.html doc的方法:如果根层次结构相同,则搜索相同的处理程序集。为了让我理解api,这是另一个版本:
-- hslogger
import System.Log.Logger ( Priority(ERROR), addHandler
, errorM, updateGlobalLogger
)
import System.Log.Handler (close)
import System.Log.Handler.Simple (fileHandler)
main :: IO ()
main =
do
putStrLn("This will work because the hierarchies are different")
mainWithLoggerPair ("main", "main2")
putStrLn("______________________________________________________")
putStrLn("This will fail because the root logger is returned from the tree map")
mainWithLoggerPair ("main", "main.sub")
mainWithLoggerPair (logger1, logger2) = do
let fileName = "test.log"
h1 <- fileHandler fileName ERROR
putStrLn "opened file1"
updateGlobalLogger logger1 $ addHandler h1
putStrLn "will write1"
errorM logger1 "writing 1"
putStrLn "did write1"
close h1
putStrLn "closed file1"
h2 <- fileHandler fileName ERROR
putStrLn "opened file2"
updateGlobalLogger logger2 $ addHandler h2
putStrLn "will write2"
errorM logger2 "writing 2"
putStrLn "did write2"
close h2
putStrLn "closed file2"
` 在上述情况下,当使用相同的记录器层次结构时,写入失败,因为我们仍然遇到在关闭基础文件句柄时未删除处理程序的问题。
我尝试浏览网站上的代码,以便更好地了解该库:
type LogTree = Map.Map String Logger
例如,该树基于记录器字符串进行维护 “a.b.c”属于“a”下的树,但记录器“l1”和“l2”是不同的记录器。我希望这有助于为api增加一些额外的亮点。 现在,让我们考虑当前的测试用例: 记录器的名称从未改变,这意味着映射将找到较早的记录器并返回现有的记录器实例(等效的haskell术语?),并在处理程序列表中引用已关闭的文件句柄。
提供一个removeHandler接口来处理上述测试用例是非常直观的。