简体   繁体   English

wai-logger FileLogSpec 作为 Scotty 中间件报告 openFile:资源繁忙(文件已锁定)

[英]wai-logger FileLogSpec as Scotty Middleware reporting openFile: resource busy (file is locked)

I am using Scotty for a backend application in Haskell and I am interested in logging all requests to a file.我正在将 Scotty 用于 Haskell 中的后端应用程序,并且我有兴趣将所有请求记录到文件中。 The existing wai-middleware requestlogger is not enough as I would like the properties of FileLogSpec , since I like have multiple but short logfiles, which FileLogSpec permits.现有的 wai-middleware requestlogger是不够的,因为我想要FileLogSpec的属性,因为我喜欢 FileLogSpec 允许的多个但很短的日志文件。

I am also open to alternative solutions on the logging issue, but I am not interested in switching from Scotty.我也对日志记录问题的替代解决方案持开放态度,但我对从 Scotty 切换不感兴趣。

My problem is, that after the first request I get this error:我的问题是,在第一次请求后我收到此错误:

openFile: resource busy (file is locked)
openFile: resource busy (file is locked)

and the application stops logging entirely.并且应用程序完全停止记录。

My current implementation making wai-logger into a middleware is:我目前将 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")

I have tried using bracket to clean up the logger as follows:我尝试使用括号来清理记录器,如下所示:

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

And here is how I use it:这是我使用它的方式:

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" ...

Unfortunately, this led to the same result.不幸的是,这导致了同样的结果。

I have created an issue on wai logger as well: https://github.com/kazu-yamamoto/logger/issues/183我也在 wai 记录器上创建了一个问题: https://github.com/kazu-yamamoto/logger/issues/183

The full source is available here: https://github.com/into-cps-association/utilities_backend完整的源代码在这里: https://github.com/into-cps-association/utilities_backend

sicklorkin from irc freenode #haskell responded with the rather obvious solution -来自 irc freenode #haskell 的icklorkin 给出了一个相当明显的解决方案——

Make sure you havn't accidentally opened the logger twice确保您没有意外打开记录器两次

and asked me to try passing in the logger.并让我尝试传入记录器。

So the new and working solution is:因此,新的有效解决方案是:

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)

And further down the mw has been split from createLogger:再往下,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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM