wai-logger FileLogSpec 作为 Scotty 中间件报告 openFile:资源繁忙(文件已锁定)
wai-logger FileLogSpec as Scotty Middleware reporting openFile: resource busy (file is locked)
我在 Haskell 中将 Scotty 用于后端应用程序,我有兴趣将所有请求记录到一个文件中。
现有的 wai 中间件 requestlogger is not enough as I would like the properties of FileLogSpec,因为我喜欢有多个但很短的日志文件,FileLogSpec 允许。
我也对日志记录问题的替代解决方案持开放态度,但我对从 Scotty 切换不感兴趣。
我的问题是,在第一个请求之后我得到这个错误:
openFile: resource busy (file is locked)
openFile: resource busy (file is locked)
并且应用程序完全停止记录。
我目前将 wai-logger 变成中间件的实现是:
-- type Middleware = Application -> Application
-- Type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
mw :: Wai.Middleware
mw (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
app req myResponseFunction
where
myResponseFunction :: Response -> IO ResponseReceived
myResponseFunction response = do
logger' <- logger
logger' req (Wai.responseStatus response) Nothing
fRes response
logger :: IO Logger.ApacheLogger
logger = createLoggerActions >>= return . Logger.apacheLogger
createLoggerActions :: IO Logger.ApacheLoggerActions
createLoggerActions = let
-- 5 MB in bytes = 5242880
mb5InBytes = 5242880
-- From fast-logger default
defaultBufSize = 4096 in
Logger.initLogger
Logger.FromFallback
(Logger.LogFile Logger.FileLogSpec {Logger.log_file = "reqLogger", Logger.log_file_size = mb5InBytes, Logger.log_backup_number = 5} defaultBufSize)
( return $ B.pack "%d/%b/%Y:%T %z")
我试过使用括号来清理记录器,如下所示:
mw :: Wai.Middleware
mw (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
let loggerActions = createLoggerActions in
bracket_ setup (teardown loggerActions) $
app req (myResponseFunction loggerActions)
where
myResponseFunction :: IO Logger.ApacheLoggerActions -> Response -> IO ResponseReceived
myResponseFunction loggerActions response = do
logger' <- logger loggerActions
logger' req (Wai.responseStatus response) Nothing
fRes response
logger :: IO Logger.ApacheLoggerActions -> IO Logger.ApacheLogger
logger loggerActions = loggerActions >>= return . Logger.apacheLogger
createLoggerActions :: IO Logger.ApacheLoggerActions
createLoggerActions = let
-- 5 MB in bytes = 5242880
mb5InBytes = 5242880
-- From fast-logger default
defaultBufSize = 4096 in
Logger.initLogger
Logger.FromFallback
(Logger.LogFile Logger.FileLogSpec {Logger.log_file = "reqLogger", Logger.log_file_size = mb5InBytes, Logger.log_backup_number = 5} defaultBufSize)
( return $ B.pack "%d/%b/%Y:%T %z")
setup :: IO ()
setup = return ()
teardown :: IO (Logger.ApacheLoggerActions) -> IO ()
teardown loggerActions = loggerActions >>= Logger.logRemover
下面是我的使用方法:
someFunc :: IO ()
someFunc = do
appConfig <- loadAppConfig
workingDir <- Dir.getCurrentDirectory
putStrLn $ "Working directory: " <> workingDir
case appConfig of
Nothing -> putStrLn "Failed to load appconfig.json"
Just appConfig' ->
let checkSizeRequirement' = checkSizeRequirement (sizeLimitGB appConfig') in
scotty 3000 $ do
--middleware logStdoutDev
middleware $ mw
middleware $ staticPolicy (addBase "./ElmFeFMI/")
post "/api/fmichecker" ...
不幸的是,这导致了同样的结果。
我也在 wai 记录器上创建了一个问题:https://github.com/kazu-yamamoto/logger/issues/183
完整的源代码可在此处获得:https://github.com/into-cps-association/utilities_backend
来自 irc freenode 的 sicklorkin #haskell 回应了相当明显的解决方案 -
Make sure you havn't accidentally opened the logger twice
并让我尝试传入记录器。
所以新的有效解决方案是:
someFunc :: IO ()
someFunc = do
appConfig <- loadAppConfig
workingDir <- Dir.getCurrentDirectory
putStrLn $ "Working directory: " <> workingDir
fileLogger <- createLogger
case appConfig of
Nothing -> putStrLn "Failed to load appconfig.json"
Just appConfig' ->
let checkSizeRequirement' = checkSizeRequirement (sizeLimitGB appConfig') in
scotty 3000 $ do
--middleware logStdoutDev
middleware $ (mw fileLogger)
再往下,mw 已从 createLogger 中分离出来:
mw :: Logger.ApacheLogger -> Wai.Middleware
mw logger (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
app req myResponseFunction
where
myResponseFunction :: Response -> IO ResponseReceived
myResponseFunction response = do
logger req (Wai.responseStatus response) Nothing
fRes response
createLogger :: IO Logger.ApacheLogger
createLogger = createLoggerActions >>= return . Logger.apacheLogger
我在 Haskell 中将 Scotty 用于后端应用程序,我有兴趣将所有请求记录到一个文件中。 现有的 wai 中间件 requestlogger is not enough as I would like the properties of FileLogSpec,因为我喜欢有多个但很短的日志文件,FileLogSpec 允许。
我也对日志记录问题的替代解决方案持开放态度,但我对从 Scotty 切换不感兴趣。
我的问题是,在第一个请求之后我得到这个错误:
openFile: resource busy (file is locked)
openFile: resource busy (file is locked)
并且应用程序完全停止记录。
我目前将 wai-logger 变成中间件的实现是:
-- type Middleware = Application -> Application
-- Type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
mw :: Wai.Middleware
mw (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
app req myResponseFunction
where
myResponseFunction :: Response -> IO ResponseReceived
myResponseFunction response = do
logger' <- logger
logger' req (Wai.responseStatus response) Nothing
fRes response
logger :: IO Logger.ApacheLogger
logger = createLoggerActions >>= return . Logger.apacheLogger
createLoggerActions :: IO Logger.ApacheLoggerActions
createLoggerActions = let
-- 5 MB in bytes = 5242880
mb5InBytes = 5242880
-- From fast-logger default
defaultBufSize = 4096 in
Logger.initLogger
Logger.FromFallback
(Logger.LogFile Logger.FileLogSpec {Logger.log_file = "reqLogger", Logger.log_file_size = mb5InBytes, Logger.log_backup_number = 5} defaultBufSize)
( return $ B.pack "%d/%b/%Y:%T %z")
我试过使用括号来清理记录器,如下所示:
mw :: Wai.Middleware
mw (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
let loggerActions = createLoggerActions in
bracket_ setup (teardown loggerActions) $
app req (myResponseFunction loggerActions)
where
myResponseFunction :: IO Logger.ApacheLoggerActions -> Response -> IO ResponseReceived
myResponseFunction loggerActions response = do
logger' <- logger loggerActions
logger' req (Wai.responseStatus response) Nothing
fRes response
logger :: IO Logger.ApacheLoggerActions -> IO Logger.ApacheLogger
logger loggerActions = loggerActions >>= return . Logger.apacheLogger
createLoggerActions :: IO Logger.ApacheLoggerActions
createLoggerActions = let
-- 5 MB in bytes = 5242880
mb5InBytes = 5242880
-- From fast-logger default
defaultBufSize = 4096 in
Logger.initLogger
Logger.FromFallback
(Logger.LogFile Logger.FileLogSpec {Logger.log_file = "reqLogger", Logger.log_file_size = mb5InBytes, Logger.log_backup_number = 5} defaultBufSize)
( return $ B.pack "%d/%b/%Y:%T %z")
setup :: IO ()
setup = return ()
teardown :: IO (Logger.ApacheLoggerActions) -> IO ()
teardown loggerActions = loggerActions >>= Logger.logRemover
下面是我的使用方法:
someFunc :: IO ()
someFunc = do
appConfig <- loadAppConfig
workingDir <- Dir.getCurrentDirectory
putStrLn $ "Working directory: " <> workingDir
case appConfig of
Nothing -> putStrLn "Failed to load appconfig.json"
Just appConfig' ->
let checkSizeRequirement' = checkSizeRequirement (sizeLimitGB appConfig') in
scotty 3000 $ do
--middleware logStdoutDev
middleware $ mw
middleware $ staticPolicy (addBase "./ElmFeFMI/")
post "/api/fmichecker" ...
不幸的是,这导致了同样的结果。
我也在 wai 记录器上创建了一个问题:https://github.com/kazu-yamamoto/logger/issues/183
完整的源代码可在此处获得:https://github.com/into-cps-association/utilities_backend
来自 irc freenode 的 sicklorkin #haskell 回应了相当明显的解决方案 -
Make sure you havn't accidentally opened the logger twice
并让我尝试传入记录器。
所以新的有效解决方案是:
someFunc :: IO ()
someFunc = do
appConfig <- loadAppConfig
workingDir <- Dir.getCurrentDirectory
putStrLn $ "Working directory: " <> workingDir
fileLogger <- createLogger
case appConfig of
Nothing -> putStrLn "Failed to load appconfig.json"
Just appConfig' ->
let checkSizeRequirement' = checkSizeRequirement (sizeLimitGB appConfig') in
scotty 3000 $ do
--middleware logStdoutDev
middleware $ (mw fileLogger)
再往下,mw 已从 createLogger 中分离出来:
mw :: Logger.ApacheLogger -> Wai.Middleware
mw logger (app::Wai.Application) (req::Request) (fRes::(Response -> IO ResponseReceived)) =
app req myResponseFunction
where
myResponseFunction :: Response -> IO ResponseReceived
myResponseFunction response = do
logger req (Wai.responseStatus response) Nothing
fRes response
createLogger :: IO Logger.ApacheLogger
createLogger = createLoggerActions >>= return . Logger.apacheLogger