packages feed

wrecker 1.2.4.0 → 1.3.0.0

raw patch · 6 files changed

+149/−135 lines, 6 filesdep +fast-loggerdep −unagi-chandep ~tdigestPVP ok

version bump matches the API change (PVP)

Dependencies added: fast-logger

Dependencies removed: unagi-chan

Dependency ranges changed: tdigest

API changes (from Hackage documentation)

- Wrecker.Logger: [inChan] :: Logger -> InChan (Maybe String)
- Wrecker.Logger: [thread] :: Logger -> ThreadId
- Wrecker.Logger: [wait] :: Logger -> IO ()
- Wrecker.Logger: forceShutdownLogger :: Logger -> IO ()
- Wrecker.Logger: newLogger :: Handle -> Int -> LogLevel -> IO Logger
- Wrecker.Logger: readLoop :: Handle -> OutChan (Maybe String) -> MVar () -> IO ThreadId
+ Network.Wreq.Wrecker: data Logger
+ Network.Wreq.Wrecker: logDebug :: ToLogStr msg => Session -> msg -> IO ()
+ Network.Wreq.Wrecker: logError :: ToLogStr msg => Session -> msg -> IO ()
+ Network.Wreq.Wrecker: logInfo :: ToLogStr msg => Session -> msg -> IO ()
+ Network.Wreq.Wrecker: logWarn :: ToLogStr msg => Session -> msg -> IO ()
+ Wrecker: [logFmt] :: Options -> LogFormat
+ Wrecker: [logger] :: Environment -> Logger
+ Wrecker.Logger: Json :: LogFormat
+ Wrecker.Logger: PlainText :: LogFormat
+ Wrecker.Logger: [cleanup] :: Logger -> IO ()
+ Wrecker.Logger: [logFormat] :: Logger -> LogFormat
+ Wrecker.Logger: [logFunc] :: Logger -> FastLogger
+ Wrecker.Logger: [timeFormatter] :: Logger -> IO FormattedTime
+ Wrecker.Logger: data LogFormat
+ Wrecker.Logger: formatLevel :: LogLevel -> LogStr
+ Wrecker.Logger: formatMsg :: LogFormat -> LogLevel -> FormattedTime -> LogStr -> LogStr
+ Wrecker.Logger: instance GHC.Classes.Eq Wrecker.Logger.LogFormat
+ Wrecker.Logger: instance GHC.Read.Read Wrecker.Logger.LogFormat
+ Wrecker.Logger: instance GHC.Show.Show Wrecker.Logger.LogFormat
+ Wrecker.Logger: toLevelCode :: LogLevel -> Int
+ Wrecker.Options: [logFmt] :: Options -> LogFormat
+ Wrecker.Options: [mLogFmt] :: PartialOptions -> Maybe LogFormat
+ Wrecker.Runner: [logger] :: Environment -> Logger
- Network.Wreq.Wrecker: withWreqSettings :: Recorder -> Maybe CookieJar -> ManagerSettings -> (Session -> IO a) -> IO a
+ Network.Wreq.Wrecker: withWreqSettings :: Recorder -> Logger -> Maybe CookieJar -> ManagerSettings -> (Session -> IO a) -> IO a
- Wrecker: Environment :: Recorder -> ConnectionContext -> Environment
+ Wrecker: Environment :: Recorder -> ConnectionContext -> Logger -> Environment
- Wrecker: Options :: Int -> Int -> RunType -> Int -> DisplayMode -> LogLevel -> String -> Maybe Int -> Maybe FilePath -> Bool -> URLDisplay -> Bool -> Bool -> Options
+ Wrecker: Options :: Int -> Int -> RunType -> Int -> DisplayMode -> LogLevel -> LogFormat -> String -> Maybe Int -> Maybe FilePath -> Bool -> URLDisplay -> Bool -> Bool -> Options
- Wrecker.Logger: Logger :: ThreadId -> InChan (Maybe String) -> IO () -> LogLevel -> Logger
+ Wrecker.Logger: Logger :: LogLevel -> LogFormat -> FastLogger -> IO () -> IO FormattedTime -> Logger
- Wrecker.Logger: logDebug :: Logger -> String -> IO Bool
+ Wrecker.Logger: logDebug :: ToLogStr msg => Logger -> msg -> IO ()
- Wrecker.Logger: logError :: Logger -> String -> IO Bool
+ Wrecker.Logger: logError :: ToLogStr msg => Logger -> msg -> IO ()
- Wrecker.Logger: logInfo :: Logger -> String -> IO Bool
+ Wrecker.Logger: logInfo :: ToLogStr msg => Logger -> msg -> IO ()
- Wrecker.Logger: logWarn :: Logger -> String -> IO Bool
+ Wrecker.Logger: logWarn :: ToLogStr msg => Logger -> msg -> IO ()
- Wrecker.Logger: newStdErrLogger :: Int -> LogLevel -> IO Logger
+ Wrecker.Logger: newStdErrLogger :: LogLevel -> LogFormat -> IO Logger
- Wrecker.Logger: shutdownLogger :: Int -> Logger -> IO ()
+ Wrecker.Logger: shutdownLogger :: Logger -> IO ()
- Wrecker.Logger: writeLogger :: Logger -> LogLevel -> String -> IO Bool
+ Wrecker.Logger: writeLogger :: Logger -> LogLevel -> LogStr -> IO ()
- Wrecker.Options: Options :: Int -> Int -> RunType -> Int -> DisplayMode -> LogLevel -> String -> Maybe Int -> Maybe FilePath -> Bool -> URLDisplay -> Bool -> Bool -> Options
+ Wrecker.Options: Options :: Int -> Int -> RunType -> Int -> DisplayMode -> LogLevel -> LogFormat -> String -> Maybe Int -> Maybe FilePath -> Bool -> URLDisplay -> Bool -> Bool -> Options
- Wrecker.Options: PartialOptions :: Maybe Int -> Maybe Int -> Maybe RunType -> Maybe Int -> Maybe DisplayMode -> Maybe LogLevel -> Maybe String -> Maybe Int -> Maybe FilePath -> Maybe Bool -> Maybe URLDisplay -> Maybe Bool -> Maybe Bool -> PartialOptions
+ Wrecker.Options: PartialOptions :: Maybe Int -> Maybe Int -> Maybe RunType -> Maybe Int -> Maybe DisplayMode -> Maybe LogLevel -> Maybe LogFormat -> Maybe String -> Maybe Int -> Maybe FilePath -> Maybe Bool -> Maybe URLDisplay -> Maybe Bool -> Maybe Bool -> PartialOptions
- Wrecker.Runner: Environment :: Recorder -> ConnectionContext -> Environment
+ Wrecker.Runner: Environment :: Recorder -> ConnectionContext -> Logger -> Environment
- Wrecker.Runner: collectEvent :: Logger -> NextRef AllStats -> Recorder -> IO ()
+ Wrecker.Runner: collectEvent :: NextRef AllStats -> Recorder -> IO ()
- Wrecker.Runner: sinkRecorder :: Logger -> Recorder -> IO (NextRef AllStats, Thread)
+ Wrecker.Runner: sinkRecorder :: Recorder -> IO (NextRef AllStats, Thread)

Files

src/Network/Wreq/Wrecker.hs view
@@ -16,6 +16,12 @@     , withWreq     , withWreqNoCookies     , withWreqSettings+    -- * Logging functions+    , logDebug+    , logInfo+    , logWarn+    , logError+    , Logger.Logger     -- * HTTP Methods     , get     , post@@ -53,7 +59,9 @@ import qualified Network.Wreq as Wreq import qualified Network.Wreq.Session as Session import qualified Network.Wreq.Types as Wreq+import System.Log.FastLogger (ToLogStr) import Wrecker+import qualified Wrecker.Logger as Logger  {-| An opaque type created by 'withWreq', 'withWreqNoCookies',     or 'withWreqSettings'. All HTTP calls require a 'Session'.@@ -64,6 +72,8 @@     , sRecord :: forall a. Recorder -> String -> IO a -> IO a       -- ^ A custom function to record the time of of executing the IO action       --   By default, it will use 'Wrecker.Recorder.record'+    , sLogger :: Logger.Logger+      -- ^ A custom logger that can be used for logging messages from the test functions     }  {- | Create 'ManagerSettings' with no timeout using a shared TLS@@ -84,6 +94,7 @@ withWreq f env =     withWreqSettings         (recorder env)+        (logger env)         (Just (HTTP.createCookieJar []))         (defaultManagerSettings (context env))         f@@ -95,7 +106,7 @@ -- which typically do not use cookies. withWreqNoCookies :: (Session -> IO a) -> Environment -> IO a withWreqNoCookies f env =-    withWreqSettings (recorder env) Nothing (defaultManagerSettings (context env)) f+    withWreqSettings (recorder env) (logger env) Nothing (defaultManagerSettings (context env)) f  -- | Replaces the record function of the Session with the provided one. --@@ -107,15 +118,16 @@ -- | Create a session, using the given cookie jar and manager settings. withWreqSettings ::        Recorder+    -> Logger.Logger     -> Maybe HTTP.CookieJar                  -- ^ If 'Nothing' is specified, no cookie management                  -- will be performed.     -> HTTP.ManagerSettings     -> (Session -> IO a)     -> IO a-withWreqSettings recorder cookie settings f = do+withWreqSettings recorder logFunc cookie settings f = do     session <- Session.newSessionControl cookie settings-    f (Session session recorder record)+    f (Session session recorder record logFunc)  -- this records things. It's not ideal, but an more acurate -- implementation is harder. Pull requests welcome.@@ -216,6 +228,18 @@     -> IO (HTTP.Response b) putJSONWith opts =     withRecorder1 (\sess url body -> Session.putWith opts sess url body >>= fromJSON "PUT" url)++logDebug :: ToLogStr msg => Session -> msg -> IO ()+logDebug Session {..} = Logger.logDebug sLogger++logInfo :: ToLogStr msg => Session -> msg -> IO ()+logInfo Session {..} = Logger.logDebug sLogger++logWarn :: ToLogStr msg => Session -> msg -> IO ()+logWarn Session {..} = Logger.logDebug sLogger++logError :: ToLogStr msg => Session -> msg -> IO ()+logError Session {..} = Logger.logDebug sLogger  -- | 'Session'-specific version of 'Network.Wreq.deleteWith' that expects a JSON response. deleteJSONWith :: FromJSON a => Wreq.Options -> Session -> String -> IO (HTTP.Response a)
src/Wrecker/Logger.hs view
@@ -1,13 +1,13 @@ {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}  module Wrecker.Logger where -import Control.Concurrent-import qualified Control.Concurrent.Chan.Unagi.Bounded as U-import Data.Foldable (traverse_)-import Data.Function-import System.IO-import System.Timeout+import Control.Monad (when)+import Data.Aeson+import Data.Monoid ((<>))+import qualified Data.Text.Encoding as TE+import System.Log.FastLogger  data LogLevel     = LevelDebug@@ -16,74 +16,81 @@     | LevelError     deriving (Show, Eq, Ord, Read) +data LogFormat+    = PlainText+    | Json+    deriving (Eq, Show, Read)+ data Logger = Logger-    { thread :: ThreadId-    , inChan :: U.InChan (Maybe String)-    , wait :: IO ()-    , currentLevel :: LogLevel+    { currentLevel :: LogLevel+    , logFormat :: LogFormat+    , logFunc :: FastLogger+    , cleanup :: IO ()+    , timeFormatter :: IO FormattedTime     } -{- | Create a 'Logger' with the given 'Handle' and max buffer size.-     The logger will drop messages if it is unable to keep up and it's message buffer-     goes over the max size.--}-newLogger ::-       Handle -- ^ The 'Handle' to log to.-    -> Int -- ^ Max buffer size-    -> LogLevel -- ^ Minimum log level to log.-    -> IO Logger-newLogger handle maxSize currentLevel = do-    (inChan, outChan) <- U.newChan maxSize-    lock <- newEmptyMVar-    thread <- readLoop handle outChan lock-    let wait = takeMVar lock-    return Logger {..}- -- | Create a logger using stderr. This is the typical way a logger is created.-newStdErrLogger :: Int -> LogLevel -> IO Logger-newStdErrLogger = newLogger stderr--readLoop :: Handle -> U.OutChan (Maybe String) -> MVar () -> IO ThreadId-readLoop handle chan lock =-    forkIO $ do-        fix $ \next-    -- Block on the next elemen-    -- If it "Just" print it and loop-    -- Otherwise we are not with the loop-         -> do-            U.readChan chan >>=-                traverse_-                    (\msg -> do-                         hPutStrLn handle msg-                         next)-        putMVar lock ()+newStdErrLogger :: LogLevel -> LogFormat -> IO Logger+newStdErrLogger level format = do+    let timeFormat =+            if format == PlainText+                then "%FT%T"+                else "%s"+    timeCache <- newTimeCache timeFormat+    (logger, clean) <- newFastLogger (LogStderr defaultBufSize)+    return+        Logger+        { currentLevel = level+        , logFormat = format+        , logFunc = logger+        , cleanup = clean+        , timeFormatter = timeCache+        }  -- True if the write was successful or False otherwise-writeLogger :: Logger -> LogLevel -> String -> IO Bool+writeLogger :: Logger -> LogLevel -> LogStr -> IO () writeLogger Logger {..} messageLevel msg =-    if (currentLevel <= messageLevel)-        then U.tryWriteChan inChan $ Just msg-        else return False+    when (currentLevel <= messageLevel) $ do+        t <- timeFormatter+        logFunc (formatMsg logFormat messageLevel t msg) -shutdownLogger :: Int -> Logger -> IO ()-shutdownLogger waitTime logger@(Logger {..}) = do-    U.writeChan inChan Nothing-    mtimedOut <- timeout waitTime wait-    case mtimedOut of-        Nothing -> forceShutdownLogger logger-        Just () -> return ()+formatMsg :: LogFormat -> LogLevel -> FormattedTime -> LogStr -> LogStr+formatMsg PlainText level prettyTime msg =+    toLogStr ("[" <> prettyTime <> "] - ") <> formatLevel level <> msg <> "\n"+formatMsg Json level prettyTime msg = toLogStr (encode jsonMsg) <> "\n"+  where+    jsonMsg =+        object+            [ "level" .= toLevelCode level+            , "timestamp" .= TE.decodeUtf8 prettyTime+            , "full_message" .= TE.decodeUtf8 (fromLogStr msg)+            ] -forceShutdownLogger :: Logger -> IO ()-forceShutdownLogger Logger {..} = killThread thread+formatLevel :: LogLevel -> LogStr+formatLevel level = "[" <> lvl level <> "] - "+  where+    lvl LevelDebug = "DBUG"+    lvl LevelInfo = "INFO"+    lvl LevelWarn = "WARN"+    lvl LevelError = "ERRO" -logDebug :: Logger -> String -> IO Bool-logDebug logger = writeLogger logger LevelDebug+toLevelCode :: LogLevel -> Int+toLevelCode LevelDebug = 7+toLevelCode LevelInfo = 6+toLevelCode LevelWarn = 4+toLevelCode LevelError = 3 -logInfo :: Logger -> String -> IO Bool-logInfo logger = writeLogger logger LevelInfo+shutdownLogger :: Logger -> IO ()+shutdownLogger Logger {..} = cleanup -logWarn :: Logger -> String -> IO Bool-logWarn logger = writeLogger logger LevelWarn+logDebug :: ToLogStr msg => Logger -> msg -> IO ()+logDebug logger = writeLogger logger LevelDebug . toLogStr -logError :: Logger -> String -> IO Bool-logError logger = writeLogger logger LevelError+logInfo :: ToLogStr msg => Logger -> msg -> IO ()+logInfo logger = writeLogger logger LevelInfo . toLogStr++logWarn :: ToLogStr msg => Logger -> msg -> IO ()+logWarn logger = writeLogger logger LevelWarn . toLogStr++logError :: ToLogStr msg => Logger -> msg -> IO ()+logError logger = writeLogger logger LevelError . toLogStr
src/Wrecker/Main.hs view
@@ -4,8 +4,7 @@  import Control.Monad (void) import Wrecker.Options (runParser)-import Wrecker.Runner (run)-import Wrecker.Runner (Environment)+import Wrecker.Runner (Environment, run)  {- | 'defaultMain' is typically the main entry point for 'wrecker' benchmarks.      'defaultMain' will parse all command line arguments and then call 'run'@@ -26,27 +25,30 @@ > > wrecker - HTTP stress tester and benchmarker >-> Usage: example [--concurrency ARG] [--bin-count ARG] ([--run-count ARG] |->                [--run-timed ARG]) [--timeout-time ARG] [--display-mode ARG]->                [--log-level ARG] [--match ARG] [--request-name-size ARG]->                [--output-path ARG] [--silent] [--record-query]->  Welcome to wrecker+> Usage: wreck [--concurrency ARG] [--bin-count ARG] ([--run-count ARG] |+>              [--run-timed ARG]) [--timeout-time ARG] ([--non-interactive] |+>              [--interactive]) [--log-level ARG] [--log-format ARG] [--match ARG]+>              [--request-name-size ARG] [--output-path ARG] [--silent]+>              ([--relative-url-display] | [--absolute-url-display])+>              [--record-query] [--list-test-groups]+>   Welcome to wrecker > > Available options:->  -h,--help                Show this help text->  --concurrency ARG        Number of threads for concurrent requests->  --bin-count ARG          Number of bins for latency histogram->  --run-count ARG          number of times to repeat->  --run-timed ARG          number of seconds to repeat->  --timeout-time ARG       How long to wait for all requests to finish->  --display-mode ARG       Display results interactively->  --log-level ARG          Display results interactively->  --match ARG              Only run tests that match the glob->  --request-name-size ARG  Request name size for the terminal display->  --output-path ARG        Save a JSON file of the the statistics to given path->  --silent                 Disable all output->  --record-query           Take in consideration the query string for the report-+>   -h,--help                Show this help text+>   --concurrency ARG        Number of threads for concurrent requests+>   --bin-count ARG          Number of bins for latency histogram+>   --run-count ARG          number of times to repeat+>   --run-timed ARG          number of seconds to repeat+>   --timeout-time ARG       How long to wait for all requests to finish+>   --log-level ARG          Log to stderr events of criticality greater than the+>                            LOG_LEVEL+>   --log-format ARG         Log format to use+>   --match ARG              Only run tests that match the glob+>   --request-name-size ARG  Request name size for the terminal display+>   --output-path ARG        Save a JSON file of the the statistics to given path+>   --silent                 Disable all output+>   --record-query           Take in consideration the query string for the report+>   --list-test-groups       Shows the list of tests to run and exit -} defaultMain :: [(String, Environment -> IO ())] -> IO () defaultMain actions = void . flip run actions =<< runParser
src/Wrecker/Options.hs view
@@ -47,7 +47,9 @@       -- ^ This controls the command line display. It can be either Interactive       --   of NonInteractive     , logLevel :: LogLevel-      -- ^+      -- ^ The log severity to shown in stderr+    , logFmt :: LogFormat+      -- ^ The log format to use in stderr (either Json or PlainText)     , match :: String       -- ^ Set this to filter the benchmarks using a pattern     , requestNameColumnSize :: Maybe Int@@ -75,6 +77,7 @@     , timeoutTime = 100000000     , displayMode = NonInteractive     , logLevel = LevelError+    , logFmt = Json     , match = ""     , requestNameColumnSize = Nothing     , outputFilePath = Nothing@@ -91,6 +94,7 @@     , mTimeoutTime :: Maybe Int     , mDisplayMode :: Maybe DisplayMode     , mLogLevel :: Maybe LogLevel+    , mLogFmt :: Maybe LogFormat     , mMatch :: Maybe String     , mRequestNameColumnSize :: Maybe Int     , mOutputFilePath :: Maybe FilePath@@ -109,6 +113,7 @@         , mTimeoutTime = Just $ timeoutTime defaultOptions         , mDisplayMode = Just $ displayMode defaultOptions         , mLogLevel = Just $ logLevel defaultOptions+        , mLogFmt = Just $ logFmt defaultOptions         , mMatch = Just $ match defaultOptions         , mRequestNameColumnSize = requestNameColumnSize defaultOptions         , mOutputFilePath = outputFilePath defaultOptions@@ -125,6 +130,7 @@         , mTimeoutTime = mTimeoutTime x <|> mTimeoutTime y         , mDisplayMode = mDisplayMode x <|> mDisplayMode y         , mLogLevel = mLogLevel x <|> mLogLevel y+        , mLogFmt = mLogFmt x <|> mLogFmt y         , mMatch = mMatch x <|> mMatch y         , mRequestNameColumnSize = mRequestNameColumnSize x <|> mRequestNameColumnSize y         , mOutputFilePath = mOutputFilePath x <|> mOutputFilePath y@@ -143,6 +149,7 @@                        , mTimeoutTime = Just timeoutTime                        , mDisplayMode = Just displayMode                        , mLogLevel = Just logLevel+                       , mLogFmt = Just logFmt                        , mMatch = Just match                        , mRequestNameColumnSize = requestNameColumnSize                        , mOutputFilePath = outputFilePath@@ -150,7 +157,7 @@                        , murlDisplay = Just urlDisplay                        , mRecordQuery = Just recordQuery                        , mListTestGroups = Just listTestGroups-                       } -> Just $ Options {..}+                       } -> Just Options {..}         _ -> Nothing  optionalOption :: Read a => Mod OptionFields a -> Parser (Maybe a)@@ -180,8 +187,12 @@          Interactive <$ switch (long "interactive")) <*>     --     optionalOption-        (long "log-level" <> help "Log to stderr events of criticality greater than the LOG_LEVEL") <*>+        (long "log-level" <>+         help+             "Log to stderr events of criticality greater than the LOG_LEVEL (LevelWarn | LevelError | LevelInfo | LevelDebug)") <*>     --+    optionalOption (long "log-format" <> help "Log format to use (Json | PlainText)") <*>+    --     optionalStrOption (long "match" <> help "Only run tests that match the glob") <*>     --     optionalOption (long "request-name-size" <> help "Request name size for the terminal display") <*>@@ -199,36 +210,7 @@     --     optionalSwitch (long "list-test-groups" <> help "Shows the list of tests to run and exit") --- {- | Run the command line parse and return the 'Options'--'runParser' can parse the following options--> $ wrecker-based-app --help->-> wrecker - HTTP stress tester and benchmarker->-> Usage: example [--concurrency ARG] [--bin-count ARG] ([--run-count ARG] |->                [--run-timed ARG]) [--timeout-time ARG] [--display-mode ARG]->                [--log-level ARG] [--match ARG] [--request-name-size ARG]->                [--output-path ARG] [--silent] [--record-query]->  Welcome to wrecker->-> Available options:->  -h,--help                Show this help text->  --concurrency ARG        Number of threads for concurrent requests->  --bin-count ARG          Number of bins for latency histogram->  --run-count ARG          number of times to repeat->  --run-timed ARG          number of seconds to repeat->  --timeout-time ARG       How long to wait for all requests to finish->  --display-mode ARG       Display results interactively->  --log-level ARG          Display results interactively->  --match ARG              Only run tests that match the glob->  --request-name-size ARG  Request name size for the terminal display->  --output-path ARG        Save a JSON file of the the statistics to given path->  --silent                 Disable all output->  --record-query           Take in consideration the query string for the report->  --list-test-groups       Shows the list of tests to run and exit -} runParser :: IO Options runParser = do
src/Wrecker/Runner.hs view
@@ -43,6 +43,7 @@     , context :: ConnectionContext       -- ^ Provided as a convience, this is a shared TLS context to reuse for       --   better performance.+    , logger :: Logger     }  {- | Typically 'wrecker' will control benchmarking actions. However in some situations@@ -55,14 +56,13 @@ newStandaloneRecorder :: IO (NextRef AllStats, Immortal.Thread, Recorder) newStandaloneRecorder = do     recorder <- Recorder.newRecorder True 10000-    logger <- newStdErrLogger 1000 LevelError-    (ref, thread) <- sinkRecorder logger recorder+    (ref, thread) <- sinkRecorder recorder     return (ref, thread, recorder) -sinkRecorder :: Logger -> Recorder -> IO (NextRef AllStats, Immortal.Thread)-sinkRecorder logger recorder = do+sinkRecorder :: Recorder -> IO (NextRef AllStats, Immortal.Thread)+sinkRecorder recorder = do     ref <- newNextRef emptyAllStats-    immortal <- Immortal.createWithLabel "collectEvent" $ \_ -> collectEvent logger ref recorder+    immortal <- Immortal.createWithLabel "collectEvent" $ \_ -> collectEvent ref recorder     return (ref, immortal)  updateSampler :: NextRef AllStats -> Event -> IO AllStats@@ -71,13 +71,12 @@         let !new = stepAllStats x (eRunIndex event) (Recorder.name $ eResult event) (eResult event)         in (new, new) -collectEvent :: Logger -> NextRef AllStats -> Recorder -> IO ()-collectEvent logger ref recorder =+collectEvent :: NextRef AllStats -> Recorder -> IO ()+collectEvent ref recorder =     fix $ \next -> do         mevent <- Recorder.readEvent recorder         for_ mevent $ \event -> do-            sampler <- updateSampler ref event-            logDebug logger $ show sampler+            _ <- updateSampler ref event             next  runAction :: Logger -> Int -> Int -> RunType -> (Environment -> IO ()) -> Environment -> IO ()@@ -125,18 +124,18 @@     recorder <- Recorder.newRecorder recordQuery 100000     context <- Connection.initConnectionContext     sampler <- newNextRef emptyAllStats-    logger <- newStdErrLogger 100000 logLevel+    logger <- newStdErrLogger logLevel logFmt     -- Collect events and     forkIO $         handle (\(e :: SomeException) -> void $ logError logger $ show e) $-        collectEvent logger sampler recorder+        collectEvent sampler recorder     consumer sampler     logDebug logger "Starting Runs"     let env = Environment {..}     runAction logger timeoutTime concurrency runStyle action env `finally`         (do logDebug logger "Shutting Down"             Recorder.stopRecorder recorder-            shutdownLogger 1000000 logger+            shutdownLogger logger             final sampler)     readLast sampler 
wrecker.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: ba28c486ce0f76d696c6aabcb155909519ce09949843c4bb1e3159edb06b09ac+-- hash: 1a942b8332864cd112ccea2578c97845dd6909f862d8c624f9383e8d42f88cec  name:           wrecker-version:        1.2.4.0+version:        1.3.0.0 synopsis:       An HTTP Performance Benchmarker description:    'wrecker' is a library and executable for creating HTTP benchmarks. It is designed for                 benchmarking a series of dependent requests.@@ -52,6 +52,7 @@     , data-default-class >=0.0.1     , deepseq >=1.3     , exceptions >=0.8+    , fast-logger >=2.4.10     , filepath >=1.3     , http-client >=0.5.5     , http-client-tls >=0.3.3@@ -76,7 +77,6 @@     , time >=1.4     , tls >=1.2     , transformers >=0.3-    , unagi-chan >=0.4.0     , unix >=2.7     , unordered-containers >=0.2.5     , vector >=0.10.12