{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Main where import Control.Concurrent (threadDelay) import Control.Monad (forM, forM_, forever) import qualified Data.Text.Lazy as T import qualified Data.Text.Encoding as TEnc import qualified Data.Text.Format as TF import LuminescentDreams.Logger import Options.Applicative import System.Statgrab data Config = Config { interval :: Int , watchCpu :: Bool , watchLoad :: Bool , watchMemory :: Bool , watchFilesystems :: [String] } deriving (Show) main :: IO () main = do cli@Config{..} <- execParser (info (helper <*> cliParser) (fullDesc <> progDesc "regularly stat the system")) print cli let logger = Logger (putStrLn . T.unpack) LogInfo let modules = mconcat [ if watchCpu then [cpuModule logger] else [] , if watchLoad then [loadModule logger] else [] , if watchMemory then [memoryModule logger] else [] , [filesystemModule watchFilesystems logger] ] forever $ do forM modules $ \m -> m threadDelay (interval * 1000000) cliParser :: Parser Config cliParser = Config <$> option auto (long "interval" <> help "number of seconds between stats" <> value 5) <*> switch (long "cpu" <> help "enable cpu monitoring") <*> switch (long "load" <> help "enable system load monitoring") <*> switch (long "mem" <> help "enable memory monitoring") <*> many (strOption (long "fs" <> help "enable filesystem monitoring")) cpuModule :: Logger -> IO () cpuModule logger = runStats snapshot >>= \CPU{..} -> logMsg logger LogInfo [("stats", "cpu")] (show cpuTotal) loadModule :: Logger -> IO () loadModule logger = runStats snapshot >>= \Load{..} -> logMsg logger LogInfo [("stats", "load")] $ T.unpack $ TF.format "{}, {}, {}" (load1, load5, load15) memoryModule :: Logger -> IO () memoryModule logger = runStats snapshot >>= \Memory{..} -> logMsg logger LogInfo [("stats", "memory")] $ T.unpack $ TF.format "{}, {}, {}, {}" ( bytesToMb memUsed , bytesToMb memCache , bytesToMb memFree , bytesToMb memTotal ) filesystemModule :: [String] -> Logger -> IO () filesystemModule fsNames logger = do let fsNamesBs = map (TEnc.encodeUtf8 . T.toStrict . T.pack) fsNames sts <- filter (\FileSystem{..} -> fsMountPoint `elem` fsNamesBs) <$> runStats snapshots forM_ sts $ \FileSystem{..} -> logMsg logger LogInfo [("stats", "filesystem")] $ T.unpack $ TF.format "{}: {}/{} [{}]" ( TEnc.decodeUtf8 fsMountPoint , bytesToGb fsUsed , bytesToGb fsSize , bytesToGb fsAvail ) bytesToMb :: Integer -> Float bytesToMb s = fromIntegral s / 1024 / 1024 bytesToGb :: Integer -> Float bytesToGb s = fromIntegral s / 1024 / 1024 / 1024