{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module System.Metrics.Prometheus.Ridley.Metrics.Network.Unix
( networkMetrics
, getNetworkMetrics
, mkInterfaceGauge
) where
import Control.Monad
import Control.Monad.IO.Class
import qualified Data.Map.Strict as M
import Data.Maybe
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Prelude hiding (FilePath)
import qualified System.Metrics.Prometheus.Metric.Gauge as P
import qualified System.Metrics.Prometheus.MetricId as P
import qualified System.Metrics.Prometheus.RegistryT as P
import System.Metrics.Prometheus.Ridley.Metrics.Network.Types
import System.Metrics.Prometheus.Ridley.Types
getNetworkMetrics :: IO [IfData]
getNetworkMetrics = do
interfaces <- drop 2 . T.lines . T.strip <$> T.readFile "/proc/net/dev"
return $! mapMaybe mkInterface interfaces
where
mkInterface :: T.Text -> Maybe IfData
mkInterface rawLine = case T.words . T.strip $ rawLine of
[iface, ibytes, ipackets, ierrs, idrop, _, _, _, imulticast, obytes, opackets, oerrs, _, _, _, _, _] ->
Just $ IfData {
ifi_ipackets = read $ T.unpack ipackets
, ifi_opackets = read $ T.unpack opackets
, ifi_ierrors = read $ T.unpack ierrs
, ifi_oerrors = read $ T.unpack oerrs
, ifi_ibytes = read $ T.unpack ibytes
, ifi_obytes = read $ T.unpack obytes
, ifi_imcasts = read $ T.unpack imulticast
, ifi_omcasts = 0
, ifi_iqdrops = read $ T.unpack idrop
, ifi_name = T.unpack $ T.init iface
, ifi_error = 0
}
_ -> Nothing
updateNetworkMetric :: NetworkMetric -> IfData -> Bool -> IO ()
updateNetworkMetric NetworkMetric{..} IfData{..} _ = do
P.set (fromIntegral ifi_ipackets) receive_packets
P.set (fromIntegral ifi_opackets) transmit_packets
P.set (fromIntegral ifi_ierrors) receive_errs
P.set (fromIntegral ifi_oerrors) transmit_errs
P.set (fromIntegral ifi_ibytes) receive_bytes
P.set (fromIntegral ifi_obytes) transmit_bytes
P.set (fromIntegral ifi_imcasts) receive_multicast
P.set (fromIntegral ifi_omcasts) transmit_multicast
P.set (fromIntegral ifi_iqdrops) receive_drop
updateNetworkMetrics :: NetworkMetrics -> Bool -> IO ()
updateNetworkMetrics nmetrics mustFlush = do
ifaces <- getNetworkMetrics
forM_ ifaces $ \d@IfData{..} -> do
let key = T.pack ifi_name
case M.lookup key nmetrics of
Nothing -> return ()
Just m -> updateNetworkMetric m d mustFlush
networkMetrics :: NetworkMetrics -> RidleyMetricHandler
networkMetrics g = RidleyMetricHandler {
metric = g
, updateMetric = updateNetworkMetrics
, flush = False
}
mkInterfaceGauge :: MonadIO m => P.Labels -> NetworkMetrics -> IfData -> P.RegistryT m NetworkMetrics
mkInterfaceGauge currentLabels imap d@IfData{..} = do
let iname = T.pack ifi_name
let finalLabels = P.addLabel "interface" iname currentLabels
metric <- NetworkMetric <$> P.registerGauge "network_receive_packets" finalLabels
<*> P.registerGauge "network_transmit_packets" finalLabels
<*> P.registerGauge "network_receive_errs" finalLabels
<*> P.registerGauge "network_transmit_errs" finalLabels
<*> P.registerGauge "network_receive_bytes" finalLabels
<*> P.registerGauge "network_transmit_bytes" finalLabels
<*> P.registerGauge "network_receive_multicast" finalLabels
<*> P.registerGauge "network_transmit_multicast" finalLabels
<*> P.registerGauge "network_receive_drop" finalLabels
liftIO $ updateNetworkMetric metric d False
return $! M.insert iname metric $! imap