Adds documentation and README

master v1.0.0
Abhinav Sarkar 2017-11-20 17:06:31 +05:30
parent edfd6468c4
commit e94e6c745f
7 changed files with 170 additions and 17 deletions

23
README.md Normal file
View File

@ -0,0 +1,23 @@
# purescript-metrics
A metrics library for PureScript inspired by the Haskell library [ekg](https://github.com/tibbe/ekg-core). It is a wrapper upon the JavaScript [metrics library](https://github.com/mikejihbe/metrics) which itself is a port of the Java Dropwizard [metrics library](http://metrics.dropwizard.io/).
API documentation can be found in [Pursuit](https://pursuit.purescript.org/packages/purescript-metrics).
## Sample Usage
```haskell
main = do
store <- newStore
counter <- createOrGetCounter "counter" store
gauge <- createOrGetGauge "gauge" (pure 3) store
hist <- createOrGetHistogramWithExponentialDecaySampling "hist" 1028 0.015 store
meter <- createOrGetMeter "meter" store
timer <- createOrGetTimer "timer" store
Counter.inc counter 2
Histogram.update hist 1.2
Histogram.update hist 2.1
Meter.mark meter
Timer.update timer (Milliseconds 1000.0)
launchAff $ sample store >>= logShow
```

View File

@ -12,7 +12,7 @@
, registerMeter
, registerTimer
, createOrGetCounter
, createOrGetGuage
, createOrGetGauge
, createOrGetHistogramWithExponentialDecaySampling
, createOrGetHistogramWithUniformSampling
, createOrGetMeter
@ -52,18 +52,22 @@ newtype Store = Store (Ref State)
-- | The 'Store' state.
type State = Map.Map String MetricSampler
-- | Different types of metric samplers.
data MetricSampler = CounterS Counter
| GaugeS Gauge
| HistogramS Histogram
| MeterS Meter
| TimerS Timer
-- | Create a new, empty metric store.
-- | Creates a new, empty metric store.
newStore ::forall eff. Eff (ref :: REF | eff) Store
newStore = do
ref <- newRef Map.empty
pure $ Store ref
-- | Registers a metric sampler with the given name, to the given metric store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
register :: forall eff.
String -> MetricSampler -> Store -> Eff (ref :: REF | eff) Boolean
register name sampler (Store store) = modifyRef' store $ \state ->
@ -71,6 +75,8 @@ register name sampler (Store store) = modifyRef' store $ \state ->
Just s -> { state : state, value : false }
Nothing -> { state : Map.insert name sampler state, value : true }
-- | Registers and returns a metric sampler with the given name, to the given metric store if another one
-- | is not registered with the given name. Else, returns the metric sampler registered with the given name.
registerOrGet :: forall eff.
String -> MetricSampler -> Store -> Eff (ref :: REF | eff) MetricSampler
registerOrGet name sampler (Store store) = modifyRef' store $ \state ->
@ -78,17 +84,20 @@ registerOrGet name sampler (Store store) = modifyRef' store $ \state ->
Just s -> { state : state, value : s }
Nothing -> { state : Map.insert name sampler state, value : sampler }
-- | Returns a metric sampler registered to the given metric store with the given name.
get :: forall eff. String -> Store -> Eff (ref :: REF | eff) (Maybe MetricSampler)
get name (Store store) = readRef store >>= pure <<< Map.lookup name
-- | Register a non-negative, monotonically increasing, integer-valued metric.
-- |
-- | Also see 'createCounter'.
-- | Register a Counter with the given name to the given store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
registerCounter :: forall eff.
String -> Counter -> Store -> Eff (ref :: REF | eff) Boolean
registerCounter name counter = register name (CounterS counter)
-- | Create and register a zero-initialized counter. Throw exception is the counter is already created.
-- | Creates, registers and returns a Counter with the given name to the given store.
-- | If a Counter is already registered with the given name, returns it.
-- | Throws exception if a non-Counter metric sampler is already registered with the given name.
createOrGetCounter :: forall eff.
String
-> Store
@ -99,29 +108,37 @@ createOrGetCounter name store = do
CounterS c -> pure c
_ -> throw $ "Metric name is already registered: " <> name
-- | Register an integer-valued metric.
-- |
-- | Also see 'createGuage'.
-- | Register a Gauge with the given name to the given store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
registerGauge :: forall eff.
String -> Gauge -> Store -> Eff (ref :: REF | eff) Boolean
registerGauge name gauge = register name (GaugeS gauge)
-- | Create and register a guage. Throw exception is the guage is already created.
createOrGetGuage :: forall eff.
-- | Creates, registers and returns a Gauge with the given name to the given store.
-- | If a Gauge is already registered with the given name, returns it.
-- | Throws exception if a non-Gauge metric sampler is already registered with the given name.
createOrGetGauge :: forall eff.
String
-> (forall e. Aff e Int)
-> Store
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Gauge
createOrGetGuage name f store = do
createOrGetGauge name f store = do
let gauge = Gauge.new f
registerOrGet name (GaugeS gauge) store >>= case _ of
GaugeS g -> pure g
_ -> throw $ "Metric name is already registered: " <> name
-- | Register a Histogram with the given name to the given store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
registerHistogram :: forall eff.
String -> Histogram -> Store -> Eff (ref :: REF | eff) Boolean
registerHistogram name hist = register name (HistogramS hist)
-- | Creates, registers and returns a Histogram with exponential decay sampling, with the given name to the given store.
-- | If a Histogram is already registered with the given name, returns it.
-- | Throws exception if a non-Histogram metric sampler is already registered with the given name.
createOrGetHistogramWithExponentialDecaySampling
:: forall eff.
String
@ -135,6 +152,9 @@ createOrGetHistogramWithExponentialDecaySampling name size alpha store = do
HistogramS c -> pure c
_ -> throw $ "Metric name is already registered: " <> name
-- | Creates, registers and returns a Histogram with uniform sampling, with the given name to the given store.
-- | If a Histogram is already registered with the given name, returns it.
-- | Throws exception if a non-Histogram metric sampler is already registered with the given name.
createOrGetHistogramWithUniformSampling
:: forall eff.
String
@ -147,9 +167,15 @@ createOrGetHistogramWithUniformSampling name size store = do
HistogramS c -> pure c
_ -> throw $ "Metric name is already registered: " <> name
-- | Register a Meter with the given name to the given store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
registerMeter :: forall eff. String -> Meter -> Store -> Eff (ref :: REF | eff) Boolean
registerMeter name meter = register name (MeterS meter)
-- | Creates, registers and returns a Meter with the given name to the given store.
-- | If a Meter is already registered with the given name, returns it.
-- | Throws exception if a non-Meter metric sampler is already registered with the given name.
createOrGetMeter
:: forall eff.
String
@ -161,9 +187,15 @@ createOrGetMeter name store = do
MeterS c -> pure c
_ -> throw $ "Metric name is already registered: " <> name
-- | Register a Timer with the given name to the given store.
-- | Returns true if registration succeeds, false if registration fails because another metric sampler
-- | is already registered with the given name.
registerTimer :: forall eff. String -> Timer -> Store -> Eff (ref :: REF | eff) Boolean
registerTimer name timer = register name (TimerS timer)
-- | Creates, registers and returns a Timer with the given name to the given store.
-- | If a Timer is already registered with the given name, returns it.
-- | Throws exception if a non-Timer metric sampler is already registered with the given name.
createOrGetTimer
:: forall eff.
String
@ -175,8 +207,11 @@ createOrGetTimer name store = do
TimerS c -> pure c
_ -> throw $ "Metric name is already registered: " <> name
-- | A sample of the metics in a metric store represented as a map with the metric names as the keys.
type Sample = Map.Map String Value
-- | Value of different metric samplers. Counter and Gauge values are their Int values.
-- | Histogram, Meter, and Timer values are the summary records of their values.
data Value = CounterV Int
| GaugeV Int
| HistogramV Histogram.Summary
@ -190,6 +225,7 @@ instance showVal :: Show Value where
instance encodeVal :: Encode Value where
encode = genericEncode $ defaultOptions { unwrapSingleConstructors = true }
-- | Samples the value of a metric sampler.
sampleOne :: forall eff. MetricSampler -> Aff (ref :: REF | eff) Value
sampleOne (CounterS c) = CounterV <$> liftEff (Counter.read c)
sampleOne (GaugeS g) = GaugeV <$> Gauge.read g
@ -197,6 +233,7 @@ sampleOne (HistogramS h) = HistogramV <$> liftEff (Histogram.read h)
sampleOne (MeterS h) = MeterV <$> liftEff (Meter.read h)
sampleOne (TimerS h) = TimerV <$> liftEff (Timer.read h)
-- | Samples the value of all metric samplers in the given store.
sample :: forall eff. Store -> Aff (ref :: REF | eff) Sample
sample (Store store) = do
state <- liftEff $ readRef store
@ -205,7 +242,7 @@ sample (Store store) = do
-- main = do
-- store <- newStore
-- counter <- createOrGetCounter "testc" store
-- gauge <- createOrGetGuage "testg" (pure 3) store
-- gauge <- createOrGetGauge "testg" (pure 3) store
-- hist <- createOrGetHistogramWithExponentialDecaySampling "hizz" 1028 0.015 store
-- meter <- createOrGetMeter "mmm" store
-- timer <- createOrGetTimer "ttt" store

View File

@ -1,18 +1,25 @@
module System.Metrics.Counter (Counter, new, read, inc) where
module System.Metrics.Counter (Counter, new, read, reset, inc) where
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Ref (REF)
import Data.Function.Uncurried (Fn2, runFn2)
import Prelude (Unit)
-- | A mutable, integer valued counter.
foreign import data Counter :: Type
foreign import _new :: forall eff. Eff (ref :: REF | eff) Counter
-- | Returns the current value of the counter.
foreign import read :: forall eff. Counter -> Eff (ref :: REF | eff) Int
-- | Resets the counter value to zero.
foreign import reset :: forall eff. Counter -> Eff (ref :: REF | eff) Unit
foreign import _inc :: forall eff. Fn2 Counter Int (Eff (ref :: REF | eff) Unit)
-- | Creates a new counter with zero value.
new :: forall eff. Eff (ref :: REF | eff) Counter
new = _new
-- | Increments the counter value by the given count.
inc :: forall eff. Counter -> Int -> Eff (ref :: REF | eff) Unit
inc c = runFn2 _inc c

View File

@ -2,10 +2,13 @@ module System.Metrics.Gauge (Gauge, new, read) where
import Control.Monad.Aff (Aff)
-- | An integer valued metric.
newtype Gauge = Gauge (forall eff. Aff eff Int)
-- | Creates a new gauge given the underlying measurement function.
new :: (forall eff. Aff eff Int) -> Gauge
new = Gauge
-- | Returns the current value of the gauge.
read :: forall eff. Gauge -> Aff eff Int
read (Gauge f) = f

View File

@ -1,6 +1,6 @@
module System.Metrics.Histogram
( Histogram
, Summary
, Summary(..)
, newWithExponentialDecaySampling
, newWithUniformSampling
, clear
@ -30,11 +30,16 @@ import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe)
import Data.Nullable (Nullable, toMaybe)
-- | A mutable distribution of values in a stream of data.
foreign import data Histogram :: Type
foreign import _newWithExponentialDecaySampling ::
forall eff. Fn2 Int Number (Eff (ref :: REF | eff) Histogram)
-- | Creates a new histogram with uniform sampling with the given size.
foreign import newWithUniformSampling ::
forall eff. Int -> Eff (ref :: REF | eff) Histogram
-- | Clears the histogram.
foreign import clear :: forall eff. Histogram -> Eff (ref :: REF | eff) Unit
foreign import _update :: forall eff. Fn2 Histogram Number (Eff (ref :: REF | eff) Unit)
foreign import _percentiles
@ -45,35 +50,68 @@ foreign import _stdDev :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nulla
foreign import _min :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
foreign import _max :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
foreign import _sum :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
-- | Returns the count of measurements in the histogram.
foreign import count :: forall eff. Histogram -> Eff (ref :: REF | eff) Int
-- | Creates a new histogram with exponential decay sampling with given size and alpha.
newWithExponentialDecaySampling :: forall eff. Int -> Number -> Eff (ref :: REF | eff) Histogram
newWithExponentialDecaySampling = runFn2 _newWithExponentialDecaySampling
-- | Updates the histogram with the given measurement.
update :: forall eff. Histogram -> Number -> Eff (ref :: REF | eff) Unit
update = runFn2 _update
-- | Returns the percentiles of the measurements in the histogram for the given percentiles array.
-- | Returns 'Nothing' if there are no measurements.
percentiles :: forall eff. Histogram -> Array Number -> Eff (ref :: REF | eff) (Maybe (Array Number))
percentiles h ptiles = toMaybe <$> runFn2 _percentiles h ptiles
-- | Returns the variance of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
variance :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
variance h = toMaybe <$> _variance h
-- | Returns the mean of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
mean :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
mean h = toMaybe <$> _mean h
-- | Returns the standard deviation of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
stdDev :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
stdDev h = toMaybe <$> _stdDev h
-- | Returns the minimum of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
min :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
min h = toMaybe <$> _min h
-- | Returns the maximum of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
max :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
max h = toMaybe <$> _max h
-- | Returns the sum of the measurements in the histogram.
-- | Returns 'Nothing' if there are no measurements.
sum :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
sum h = toMaybe <$> _sum h
-- | Summary of the distribution of the measurements in the histogram.
-- | Contains:
-- |
-- | - min: minimum
-- | - max: maximum
-- | - sum: sum
-- | - variance: variance
-- | - mean: mean
-- | - stdDev: standard deviation
-- | - count: count
-- | - median: median
-- | - p75: 75th percentile
-- | - p95: 95th percentile
-- | - p99: 99th percentile
-- | - p999: 99.9th percentile
newtype Summary = Summary {
min :: Maybe Number
, max :: Maybe Number
@ -130,6 +168,7 @@ derive instance genericHSummary' :: Generic Summary' _
instance encodeHSummary' :: Encode Summary' where
encode = genericEncode $ defaultOptions { unwrapSingleConstructors = true }
-- | Returns the summary of the measurements in the histogram.
read :: forall eff. Histogram -> Eff (ref :: REF | eff) Summary
read h = do
ptiles <- percentiles h [0.5, 0.75, 0.95, 0.99, 0.999]

View File

@ -1,6 +1,6 @@
module System.Metrics.Meter
( Meter
, Summary
, Summary(..)
, new
, markN
, mark
@ -21,24 +21,45 @@ import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Prelude
-- | A mutable metric which measures the rate at which a set of events occur.
foreign import data Meter :: Type
foreign import _new :: forall eff. Eff (ref :: REF | eff) Meter
foreign import _markN :: forall eff. Fn2 Meter Int (Eff (ref :: REF | eff) Unit)
-- | Returns the fifteen minute moving-average rate of the events recorded by the meter.
foreign import fifteenMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
-- | Returns the five minute moving-average rate of the events recorded by the meter.
foreign import fiveMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
-- | Returns the one minute moving-average rate of the events recorded by the meter.
foreign import oneMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
-- | Returns the mean rate of the events recorded by the meter.
foreign import meanRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
-- | Returns the count of the events recorded by the meter.
foreign import count :: forall eff. Meter -> Eff (ref :: REF | eff) Int
-- | Create a new meter.
new :: forall eff. Eff (ref :: REF | eff) Meter
new = _new
-- | Marks the meter with occurrance of n events.
markN :: forall eff. Meter -> Int -> Eff (ref :: REF | eff) Unit
markN = runFn2 _markN
-- | Marks the meter with occurrance of one event.
mark :: forall eff. Meter -> Eff (ref :: REF | eff) Unit
mark m = markN m 1
-- | Summary of the measurements in the meter. Contains:
-- |
-- | - count: count
-- | - m1: one minute rate
-- | - m5: five minute rate
-- | - m15: fifteen minute rate
-- | - mean: mean rate
newtype Summary = Summary {
count :: Int
, m1 :: Number
@ -54,6 +75,7 @@ instance showMSummary :: Show Summary where
instance encodeMSummary :: Encode Summary where
encode = genericEncode $ defaultOptions { unwrapSingleConstructors = true }
-- | Returns the summary of the measurements in the meter.
read :: forall eff. Meter -> Eff (ref :: REF | eff) Summary
read m = Summary <$> ({ count: _
, m1: _

View File

@ -1,6 +1,6 @@
module System.Metrics.Timer
( Timer
, Summary
, Summary(..)
, new
, update
, time
@ -38,19 +38,24 @@ import System.Metrics.Histogram as Histogram
import System.Metrics.Meter (Meter)
import System.Metrics.Meter as Meter
-- | A timer is a histogram of the duration of a type of event and a meter of the rate of its occurrence.
newtype Timer = Timer { meter :: Meter, histogram :: Histogram }
-- | Creates a new timer.
new :: forall eff. Eff (ref :: REF | eff) Timer
new = Timer <$> ({ meter: _, histogram: _ }
<$> Meter.new
<*> Histogram.newWithExponentialDecaySampling 1028 0.015)
-- | Updates the timer with the duration of a new event.
update :: forall a eff. Duration a => Timer -> a -> Eff (ref :: REF | eff) Unit
update (Timer { meter, histogram }) d = do
let (Milliseconds ms) = fromDuration d
Histogram.update histogram ms
Meter.mark meter
-- | Runs and times the given function, updates the given timer with the run duration, and returns
-- | the return value of the function.
time :: forall a eff. Timer -> Aff (ref :: REF, now :: NOW | eff) a -> Aff (ref :: REF, now :: NOW | eff) a
time timer f = do
start <- liftEff now
@ -59,42 +64,58 @@ time timer f = do
liftEff $ update timer (unInstant end - unInstant start)
pure r
-- | Returns the fifteen minute moving average rate of the events recorded by the timer.
fifteenMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
fifteenMinuteRate (Timer { meter }) = Meter.fifteenMinuteRate meter
-- | Returns the five minute moving average rate of the events recorded by the timer.
fiveMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
fiveMinuteRate (Timer { meter }) = Meter.fiveMinuteRate meter
-- | Returns the one minute moving average rate of the events recorded by the timer.
oneMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
oneMinuteRate (Timer { meter }) = Meter.oneMinuteRate meter
-- | Returns the mean rate of the events recorded by the timer.
meanRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
meanRate (Timer { meter }) = Meter.meanRate meter
-- | Clears the timer.
clear :: forall eff. Timer -> Eff (ref :: REF | eff) Unit
clear (Timer { histogram }) = Histogram.clear histogram
-- | Returns the percentiles of the measurements in the timer for the given percentiles array.
percentiles :: forall eff. Timer -> Array Number -> Eff (ref :: REF | eff) (Maybe (Array Number))
percentiles (Timer { histogram }) = Histogram.percentiles histogram
-- | Returns the mean of the measurements in the timer.
mean :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
mean (Timer { histogram }) = Histogram.mean histogram
-- | Returns the standard deviation of the measurements in the timer.
stdDev :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
stdDev (Timer { histogram }) = Histogram.stdDev histogram
-- | Returns the minimum of the measurements in the timer.
min :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
min (Timer { histogram }) = Histogram.min histogram
-- | Returns the maximum of the measurements in the timer.
max :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
max (Timer { histogram }) = Histogram.max histogram
-- | Returns the sum of the measurements in the timer.
sum :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
sum (Timer { histogram }) = Histogram.sum histogram
-- | Returns the count of the measurements in the timer.
count :: forall eff. Timer -> Eff (ref :: REF | eff) Int
count (Timer { histogram }) = Histogram.count histogram
-- | Summary of the measurements in the meter. Contains:
-- |
-- | - duration: the summary of the underlying event duration histogram.
-- | - rate: the summary of the underlying event rate meter.
newtype Summary = Summary { duration :: Histogram.Summary, rate :: Meter.Summary }
derive instance eqTSummary :: Eq Summary
@ -104,6 +125,7 @@ instance showTSummary :: Show Summary where
instance encodeTSummary :: Encode Summary where
encode = genericEncode $ defaultOptions { unwrapSingleConstructors = true }
-- | Returns the summary of the measurements in the timer.
read :: forall eff. Timer -> Eff (ref :: REF | eff) Summary
read (Timer { meter, histogram }) =
Summary <$> ({ duration: _, rate: _} <$> Histogram.read histogram <*> Meter.read meter)