prometheus-proc 0.1.0.0 → 0.1.1.0
raw patch · 3 files changed
+93/−27 lines, 3 filesdep +directorydep +textPVP ok
version bump matches the API change (PVP)
Dependencies added: directory, text
API changes (from Hackage documentation)
Files
- ChangeLog.md +12/−0
- prometheus-proc.cabal +6/−4
- src/Prometheus/Metric/Proc.hs +75/−23
ChangeLog.md view
@@ -1,3 +1,15 @@+# 0.1.1.0 -- 2019-05-23++* Change all use of `Int` to `Int64`. `Int` is only guaranteed to be able to+ represent values up to 2^29-1, but entries in /proc/stat can often exceed that+ (for example processes with a high resident memory usage) on 32-bit machines.++* Export `process_open_fds`, a count of the number of entries in+ `/proc/$PID/fd`.++* Export `process_max_fds`, which exports the soft ulimit of the maximum number+ of file descriptors this process may open.+ # 0.1.0.0 -- 2019-01-15 * Initial release.
prometheus-proc.cabal view
@@ -1,5 +1,5 @@ name: prometheus-proc-version: 0.1.0.0+version: 0.1.1.0 synopsis: Export metrics from /proc for the current process homepage: https://github.com/fimad/prometheus-haskell license: BSD3@@ -18,10 +18,12 @@ library exposed-modules: Prometheus.Metric.Proc build-depends: base >=4.10 && <4.13+ , directory >= 1.2.5.0 && < 1.4 , filepath >=1.4 && <1.5- , unix-memory >=0.1 && <0.2- , unix >=2.7 && <2.8- , regex-applicative >=0.3 && <0.4 , prometheus-client >= 1.0.0 && < 1.1+ , regex-applicative >=0.3 && <0.4+ , text >= 0.7 && < 1.3+ , unix >=2.7 && <2.8+ , unix-memory >=0.1 && <0.2 hs-source-dirs: src default-language: Haskell2010
src/Prometheus/Metric/Proc.hs view
@@ -2,6 +2,7 @@ {-# language NamedFieldPuns #-} {-# language OverloadedStrings #-} {-# language RecordWildCards #-}+{-# language ViewPatterns #-} {-| @@ -12,14 +13,21 @@ module Prometheus.Metric.Proc ( ProcMetrics(..), procMetrics ) where import Data.Char ( isSpace )-import Data.Maybe ( catMaybes )+import Data.Int ( Int64 )+import Data.List ( isPrefixOf )+import Data.Maybe ( catMaybes, maybeToList ) import Data.String ( fromString )+import Data.Text ( Text, unpack )+import Data.Text.IO ( readFile ) import Foreign.C+import Prelude hiding ( readFile ) import Prometheus+import System.Directory ( listDirectory ) import System.FilePath import System.IO.Unsafe import System.Posix.Memory ( sysconfPageSize ) import System.Posix.Process ( getProcessID )+import System.Posix.Types ( ProcessID ) import qualified Text.Regex.Applicative as RE import qualified Text.Regex.Applicative.Common as RE @@ -62,14 +70,56 @@ getProcessID mprocStat <-- RE.match parseProcStat <$> readFile ( "/" </> "proc" </> show pid </> "stat" )+ RE.match parseProcStat . unpack <$> readFile ( procPidDir pid </> "stat" ) + processOpenFds <-+ collectProcessOpenFds pid++ processMaxFds <-+ collectProcessMaxFds pid+ return- ( foldMap ( toMetrics ) mprocStat )+ ( [ processOpenFds ]+ <> maybeToList processMaxFds+ <> foldMap ( procStatToMetrics ) mprocStat+ ) -toMetrics :: ProcStat -> [ SampleGroup ]-toMetrics ProcStat{ utime, stime, starttime, vsize, rss } =+collectProcessOpenFds :: ProcessID -> IO SampleGroup+collectProcessOpenFds pid = do+ fmap+ ( metric "process_open_fds" "Number of open file descriptors." GaugeType . length )+ ( listDirectory ( procPidDir pid </> "fd" ) )+++collectProcessMaxFds :: ProcessID -> IO ( Maybe SampleGroup )+collectProcessMaxFds pid = do+ limitLines <-+ lines . unpack <$> readFile ( procPidDir pid </> "limits" )++ case filter ( "Max open files" `isPrefixOf` ) limitLines of+ ( words -> _max : _open : _files : n : _ ) : _ ->+ return+ ( Just+ ( metric+ "process_max_fds"+ "Maximum number of open file descriptors."+ GaugeType+ ( read n :: Int )+ )+ )++ _ ->+ return Nothing+++procPidDir :: ProcessID -> FilePath+procPidDir pid =+ "/" </> "proc" </> show pid+++procStatToMetrics :: ProcStat -> [ SampleGroup ]+procStatToMetrics ProcStat{ utime, stime, starttime, vsize, rss } = catMaybes [ Just process_cpu_seconds_total , process_start_time_seconds@@ -110,21 +160,23 @@ "process_resident_memory_bytes" "Resident memory size in bytes." GaugeType- ( rss * sysconfPageSize )+ ( rss * fromIntegral sysconfPageSize ) - metric metricName metricHelp metricType value =- SampleGroup- Info{..}- metricType- [ Sample- metricName- []- ( fromString ( show value ) )- ] +metric :: Show a => Text -> Text -> SampleType -> a -> SampleGroup+metric metricName metricHelp metricType value =+ SampleGroup+ Info{..}+ metricType+ [ Sample+ metricName+ []+ ( fromString ( show value ) )+ ] + -- | Convert a number of clock ticks into the corresponding duration in seconds.-fromTicks :: Int -> Double+fromTicks :: Int64 -> Double fromTicks ticks = fromIntegral ticks / fromIntegral clk_tck @@ -141,27 +193,27 @@ -} {-# NOINLINE mbtime #-}-mbtime :: Maybe Int+mbtime :: Maybe Int64 mbtime = unsafePerformIO $ do- fmap ( \( _, a, _ ) -> a ) . RE.findFirstInfix ( "btime " *> RE.decimal )+ fmap ( \( _, a, _ ) -> a ) . RE.findFirstInfix ( "btime " *> RE.decimal ) . unpack <$> readFile "/proc/stat" -- | Specific metrics from @/proc/xyz/stat@ that we are interested in. data ProcStat = ProcStat- { utime :: Int+ { utime :: Int64 -- ^ Amount of time that this process has been scheduled in user mode, -- measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).- , stime :: Int+ , stime :: Int64 -- ^ Amount of time that this process has been scheduled in kernel mode, -- measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).- , starttime :: Int+ , starttime :: Int64 -- ^ The time the process started after system boot. In kernels before Linux -- 2.6, this value was expressed in jiffies. Since Linux 2.6, the value is -- expressed in clock ticks (divide by sysconf(_SC_CLK_TCK)).- , vsize :: Int+ , vsize :: Int64 -- ^ Virtual memory size in bytes.- , rss :: Int+ , rss :: Int64 -- ^ Resident Set Size: number of pages the process has in real memory. This -- is just the pages which count toward text, data, or stack space. This -- does not include pages which have not been demand-loaded in, or which are