Initial commit
This commit is contained in:
commit
a08d3e6867
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/bower_components/
|
||||
/node_modules/
|
||||
/.pulp-cache/
|
||||
/output/
|
||||
/generated-docs/
|
||||
/.psc*
|
||||
/.purs*
|
||||
/.psa*
|
19
bower.json
Normal file
19
bower.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "purescript-metrics",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"output"
|
||||
],
|
||||
"dependencies": {
|
||||
"purescript-prelude": "^3.1.1",
|
||||
"purescript-console": "^3.0.0",
|
||||
"purescript-aff": "^3.1.0",
|
||||
"purescript-maybe": "^3.0.0",
|
||||
"purescript-foreign-generic": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"purescript-psci-support": "^3.0.0"
|
||||
}
|
||||
}
|
213
src/System/Metrics.purs
Normal file
213
src/System/Metrics.purs
Normal file
@ -0,0 +1,213 @@
|
||||
module System.Metrics
|
||||
( Store
|
||||
, MetricSampler(..)
|
||||
, Value(..)
|
||||
, newStore
|
||||
, register
|
||||
, registerOrGet
|
||||
, get
|
||||
, registerCounter
|
||||
, registerGauge
|
||||
, registerHistogram
|
||||
, registerMeter
|
||||
, registerTimer
|
||||
, createOrGetCounter
|
||||
, createOrGetGuage
|
||||
, createOrGetHistogramWithExponentialDecaySampling
|
||||
, createOrGetHistogramWithUniformSampling
|
||||
, createOrGetMeter
|
||||
, createOrGetTimer
|
||||
, sampleOne
|
||||
, sample
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Aff (Aff)
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Control.Monad.Eff.Class (liftEff)
|
||||
import Control.Monad.Eff.Exception (EXCEPTION, throw)
|
||||
import Control.Monad.Eff.Ref (REF, Ref, modifyRef', newRef, readRef)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Generic.Rep.Show (genericShow)
|
||||
import Data.Map as Map
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Traversable (sequence)
|
||||
import System.Metrics.Counter (Counter)
|
||||
import System.Metrics.Counter as Counter
|
||||
import System.Metrics.Gauge (Gauge)
|
||||
import System.Metrics.Gauge as Gauge
|
||||
import System.Metrics.Histogram (Histogram)
|
||||
import System.Metrics.Histogram as Histogram
|
||||
import System.Metrics.Meter (Meter)
|
||||
import System.Metrics.Meter as Meter
|
||||
import System.Metrics.Timer (Timer)
|
||||
import System.Metrics.Timer as Timer
|
||||
|
||||
-- | A mutable metric store.
|
||||
newtype Store = Store (Ref State)
|
||||
|
||||
-- | The 'Store' state.
|
||||
type State = Map.Map String MetricSampler
|
||||
|
||||
data MetricSampler = CounterS Counter
|
||||
| GaugeS Gauge
|
||||
| HistogramS Histogram
|
||||
| MeterS Meter
|
||||
| TimerS Timer
|
||||
|
||||
-- | Create a new, empty metric store.
|
||||
newStore ::forall eff. Eff (ref :: REF | eff) Store
|
||||
newStore = do
|
||||
ref <- newRef Map.empty
|
||||
pure $ Store ref
|
||||
|
||||
register :: forall eff.
|
||||
String -> MetricSampler -> Store -> Eff (ref :: REF | eff) Boolean
|
||||
register name sampler (Store store) = modifyRef' store $ \state ->
|
||||
case Map.lookup name state of
|
||||
Just s -> { state : state, value : false }
|
||||
Nothing -> { state : Map.insert name sampler state, value : true }
|
||||
|
||||
registerOrGet :: forall eff.
|
||||
String -> MetricSampler -> Store -> Eff (ref :: REF | eff) MetricSampler
|
||||
registerOrGet name sampler (Store store) = modifyRef' store $ \state ->
|
||||
case Map.lookup name state of
|
||||
Just s -> { state : state, value : s }
|
||||
Nothing -> { state : Map.insert name sampler state, value : sampler }
|
||||
|
||||
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'.
|
||||
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.
|
||||
createOrGetCounter :: forall eff.
|
||||
String
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Counter
|
||||
createOrGetCounter name store = do
|
||||
counter <- Counter.new
|
||||
registerOrGet name (CounterS counter) store >>= case _ of
|
||||
CounterS c -> pure c
|
||||
_ -> throw $ "Metric name is already registered: " <> name
|
||||
|
||||
-- | Register an integer-valued metric.
|
||||
-- |
|
||||
-- | Also see 'createGuage'.
|
||||
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.
|
||||
String
|
||||
-> (forall e. Aff e Int)
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Gauge
|
||||
createOrGetGuage 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
|
||||
|
||||
registerHistogram :: forall eff.
|
||||
String -> Histogram -> Store -> Eff (ref :: REF | eff) Boolean
|
||||
registerHistogram name hist = register name (HistogramS hist)
|
||||
|
||||
createOrGetHistogramWithExponentialDecaySampling
|
||||
:: forall eff.
|
||||
String
|
||||
-> Int
|
||||
-> Number
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Histogram
|
||||
createOrGetHistogramWithExponentialDecaySampling name size alpha store = do
|
||||
hist <- Histogram.newWithExponentialDecaySampling size alpha
|
||||
registerOrGet name (HistogramS hist) store >>= case _ of
|
||||
HistogramS c -> pure c
|
||||
_ -> throw $ "Metric name is already registered: " <> name
|
||||
|
||||
createOrGetHistogramWithUniformSampling
|
||||
:: forall eff.
|
||||
String
|
||||
-> Int
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Histogram
|
||||
createOrGetHistogramWithUniformSampling name size store = do
|
||||
hist <- Histogram.newWithUniformSampling size
|
||||
registerOrGet name (HistogramS hist) store >>= case _ of
|
||||
HistogramS c -> pure c
|
||||
_ -> throw $ "Metric name is already registered: " <> name
|
||||
|
||||
registerMeter :: forall eff. String -> Meter -> Store -> Eff (ref :: REF | eff) Boolean
|
||||
registerMeter name meter = register name (MeterS meter)
|
||||
|
||||
createOrGetMeter
|
||||
:: forall eff.
|
||||
String
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Meter
|
||||
createOrGetMeter name store = do
|
||||
meter <- Meter.new
|
||||
registerOrGet name (MeterS meter) store >>= case _ of
|
||||
MeterS c -> pure c
|
||||
_ -> throw $ "Metric name is already registered: " <> name
|
||||
|
||||
registerTimer :: forall eff. String -> Timer -> Store -> Eff (ref :: REF | eff) Boolean
|
||||
registerTimer name timer = register name (TimerS timer)
|
||||
|
||||
createOrGetTimer
|
||||
:: forall eff.
|
||||
String
|
||||
-> Store
|
||||
-> Eff (ref :: REF, exception :: EXCEPTION | eff) Timer
|
||||
createOrGetTimer name store = do
|
||||
timer <- Timer.new
|
||||
registerOrGet name (TimerS timer) store >>= case _ of
|
||||
TimerS c -> pure c
|
||||
_ -> throw $ "Metric name is already registered: " <> name
|
||||
|
||||
type Sample = Map.Map String Value
|
||||
|
||||
data Value = CounterV Int
|
||||
| GaugeV Int
|
||||
| HistogramV Histogram.Summary
|
||||
| MeterV Meter.Summary
|
||||
| TimerV Timer.Summary
|
||||
|
||||
derive instance eqVal :: Eq Value
|
||||
derive instance genVal :: Generic Value _
|
||||
instance showVal :: Show Value where
|
||||
show = genericShow
|
||||
|
||||
sampleOne :: forall eff. MetricSampler -> Aff (ref :: REF | eff) Value
|
||||
sampleOne (CounterS c) = CounterV <$> liftEff (Counter.read c)
|
||||
sampleOne (GaugeS g) = GaugeV <$> Gauge.read g
|
||||
sampleOne (HistogramS h) = HistogramV <$> liftEff (Histogram.read h)
|
||||
sampleOne (MeterS h) = MeterV <$> liftEff (Meter.read h)
|
||||
sampleOne (TimerS h) = TimerV <$> liftEff (Timer.read h)
|
||||
|
||||
sample :: forall eff. Store -> Aff (ref :: REF | eff) Sample
|
||||
sample (Store store) = do
|
||||
state <- liftEff $ readRef store
|
||||
sequence $ map sampleOne state
|
||||
|
||||
-- main = do
|
||||
-- store <- newStore
|
||||
-- counter <- createOrGetCounter "testc" store
|
||||
-- gauge <- createOrGetGuage "testg" (pure 3) store
|
||||
-- hist <- createOrGetHistogramWithExponentialDecaySampling "hizz" 1028 0.015 store
|
||||
-- meter <- createOrGetMeter "mmm" store
|
||||
-- timer <- createOrGetTimer "ttt" 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
|
28
src/System/Metrics/Counter.js
Normal file
28
src/System/Metrics/Counter.js
Normal file
@ -0,0 +1,28 @@
|
||||
var Counter = require("metrics/metrics/counter");
|
||||
|
||||
var _new = function() {
|
||||
return new Counter();
|
||||
};
|
||||
|
||||
var read = function(c) {
|
||||
return function() {
|
||||
return c.count;
|
||||
};
|
||||
};
|
||||
|
||||
var _inc = function(c, v) {
|
||||
return function() {
|
||||
c.inc(v);
|
||||
};
|
||||
};
|
||||
|
||||
var reset = function(c) {
|
||||
return function() {
|
||||
c.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
exports._new = _new;
|
||||
exports.read = read;
|
||||
exports._inc = _inc;
|
||||
exports.reset = reset;
|
18
src/System/Metrics/Counter.purs
Normal file
18
src/System/Metrics/Counter.purs
Normal file
@ -0,0 +1,18 @@
|
||||
module System.Metrics.Counter (Counter, new, read, inc) where
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Control.Monad.Eff.Ref (REF)
|
||||
import Data.Function.Uncurried (Fn2, runFn2)
|
||||
import Prelude (Unit)
|
||||
|
||||
foreign import data Counter :: Type
|
||||
foreign import _new :: forall eff. Eff (ref :: REF | eff) Counter
|
||||
foreign import read :: forall eff. Counter -> Eff (ref :: REF | eff) Int
|
||||
foreign import reset :: forall eff. Counter -> Eff (ref :: REF | eff) Unit
|
||||
foreign import _inc :: forall eff. Fn2 Counter Int (Eff (ref :: REF | eff) Unit)
|
||||
|
||||
new :: forall eff. Eff (ref :: REF | eff) Counter
|
||||
new = _new
|
||||
|
||||
inc :: forall eff. Counter -> Int -> Eff (ref :: REF | eff) Unit
|
||||
inc c = runFn2 _inc c
|
11
src/System/Metrics/Gauge.purs
Normal file
11
src/System/Metrics/Gauge.purs
Normal file
@ -0,0 +1,11 @@
|
||||
module System.Metrics.Gauge (Gauge, new, read) where
|
||||
|
||||
import Control.Monad.Aff (Aff)
|
||||
|
||||
newtype Gauge = Gauge (forall eff. Aff eff Int)
|
||||
|
||||
new :: (forall eff. Aff eff Int) -> Gauge
|
||||
new = Gauge
|
||||
|
||||
read :: forall eff. Gauge -> Aff eff Int
|
||||
read (Gauge f) = f
|
60
src/System/Metrics/Histogram.js
Normal file
60
src/System/Metrics/Histogram.js
Normal file
@ -0,0 +1,60 @@
|
||||
var Histogram = require("metrics/metrics/histogram");
|
||||
|
||||
var clear = function(h) {
|
||||
return function() {
|
||||
h.clear();
|
||||
};
|
||||
};
|
||||
|
||||
var _update = function(h, v) {
|
||||
return function() {
|
||||
h.update(v);
|
||||
};
|
||||
};
|
||||
|
||||
var _percentiles = function(h, ptiles) {
|
||||
return function() {
|
||||
var scoresM = h.percentiles(ptiles);
|
||||
var scores = [];
|
||||
for (var i = 0; i < ptiles.length; i++) {
|
||||
scores.push(scoresM[ptiles[i]]);
|
||||
}
|
||||
if (scores[0]) {
|
||||
return scores;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
var _variance = function(h) { return function() { return h.variance(); }; };
|
||||
var _mean = function(h) { return function() { return h.mean(); }; };
|
||||
var _stdDev = function(h) { return function() { return h.stdDev(); }; };
|
||||
var _min = function(h) { return function() { return h.min; }; };
|
||||
var _max = function(h) { return function() { return h.max; }; };
|
||||
var _sum = function(h) { return function() { return h.sum; }; };
|
||||
var count = function(h) { return function() { return h.count; }; };
|
||||
|
||||
var _newWithExponentialDecaySampling = function(size, alpha) {
|
||||
return function() {
|
||||
return Histogram.createExponentialDecayHistogram(size, alpha);
|
||||
};
|
||||
};
|
||||
|
||||
var newWithUniformSampling = function(size) {
|
||||
return function() {
|
||||
return Histogram.createUniformHistogram(size);
|
||||
};
|
||||
};
|
||||
|
||||
exports.clear = clear;
|
||||
exports._update = _update;
|
||||
exports._percentiles = _percentiles;
|
||||
exports._variance = _variance;
|
||||
exports._mean = _mean;
|
||||
exports._stdDev = _stdDev;
|
||||
exports._min = _min;
|
||||
exports._max = _max;
|
||||
exports._sum = _sum;
|
||||
exports.count = count;
|
||||
exports._newWithExponentialDecaySampling = _newWithExponentialDecaySampling;
|
||||
exports.newWithUniformSampling = newWithUniformSampling;
|
114
src/System/Metrics/Histogram.purs
Normal file
114
src/System/Metrics/Histogram.purs
Normal file
@ -0,0 +1,114 @@
|
||||
module System.Metrics.Histogram
|
||||
( Histogram
|
||||
, Summary
|
||||
, newWithExponentialDecaySampling
|
||||
, newWithUniformSampling
|
||||
, clear
|
||||
, update
|
||||
, percentiles
|
||||
, variance
|
||||
, mean
|
||||
, stdDev
|
||||
, min
|
||||
, max
|
||||
, sum
|
||||
, count
|
||||
, read
|
||||
) where
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Control.Monad.Eff.Ref (REF)
|
||||
import Data.Array (index)
|
||||
import Data.Function.Uncurried (Fn2, runFn2)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Generic.Rep.Show (genericShow)
|
||||
import Data.Maybe (Maybe)
|
||||
import Data.Nullable (Nullable, toMaybe)
|
||||
import Prelude
|
||||
|
||||
foreign import data Histogram :: Type
|
||||
foreign import _newWithExponentialDecaySampling ::
|
||||
forall eff. Fn2 Int Number (Eff (ref :: REF | eff) Histogram)
|
||||
foreign import newWithUniformSampling ::
|
||||
forall eff. Int -> Eff (ref :: REF | eff) 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
|
||||
:: forall eff. Fn2 Histogram (Array Number) (Eff (ref :: REF | eff) (Nullable (Array Number)))
|
||||
foreign import _variance :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
|
||||
foreign import _mean :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
|
||||
foreign import _stdDev :: forall eff. Histogram -> Eff (ref :: REF | eff) (Nullable Number)
|
||||
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)
|
||||
foreign import count :: forall eff. Histogram -> Eff (ref :: REF | eff) Int
|
||||
|
||||
newWithExponentialDecaySampling :: forall eff. Int -> Number -> Eff (ref :: REF | eff) Histogram
|
||||
newWithExponentialDecaySampling = runFn2 _newWithExponentialDecaySampling
|
||||
|
||||
update :: forall eff. Histogram -> Number -> Eff (ref :: REF | eff) Unit
|
||||
update = runFn2 _update
|
||||
|
||||
percentiles :: forall eff. Histogram -> Array Number -> Eff (ref :: REF | eff) (Maybe (Array Number))
|
||||
percentiles h ptiles = toMaybe <$> runFn2 _percentiles h ptiles
|
||||
|
||||
variance :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
variance h = toMaybe <$> _variance h
|
||||
|
||||
mean :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
mean h = toMaybe <$> _mean h
|
||||
|
||||
stdDev :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
stdDev h = toMaybe <$> _stdDev h
|
||||
|
||||
min :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
min h = toMaybe <$> _min h
|
||||
|
||||
max :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
max h = toMaybe <$> _max h
|
||||
|
||||
sum :: forall eff. Histogram -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
sum h = toMaybe <$> _sum h
|
||||
|
||||
newtype Summary = Summary {
|
||||
min :: Maybe Number
|
||||
, max :: Maybe Number
|
||||
, sum :: Maybe Number
|
||||
, variance :: Maybe Number
|
||||
, mean :: Maybe Number
|
||||
, stdDev :: Maybe Number
|
||||
, count :: Int
|
||||
, median :: Maybe Number
|
||||
, p75 :: Maybe Number
|
||||
, p95 :: Maybe Number
|
||||
, p99 :: Maybe Number
|
||||
, p999 :: Maybe Number
|
||||
}
|
||||
|
||||
derive instance eqSummary :: Eq Summary
|
||||
derive instance genericSummary :: Generic Summary _
|
||||
instance showSummary :: Show Summary where
|
||||
show = genericShow
|
||||
|
||||
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]
|
||||
Summary <$> ({ min: _
|
||||
, max: _
|
||||
, sum: _
|
||||
, variance: _
|
||||
, mean: _
|
||||
, stdDev: _
|
||||
, count: _
|
||||
, median: ptiles >>= flip index 0
|
||||
, p75: ptiles >>= flip index 1
|
||||
, p95: ptiles >>= flip index 2
|
||||
, p99: ptiles >>= flip index 3
|
||||
, p999: ptiles >>= flip index 4
|
||||
} <$> min h
|
||||
<*> max h
|
||||
<*> sum h
|
||||
<*> variance h
|
||||
<*> mean h
|
||||
<*> stdDev h
|
||||
<*> count h)
|
49
src/System/Metrics/Meter.js
Normal file
49
src/System/Metrics/Meter.js
Normal file
@ -0,0 +1,49 @@
|
||||
var Meter = require("metrics/metrics/meter");
|
||||
|
||||
var _new = function() {
|
||||
return new Meter();
|
||||
};
|
||||
|
||||
var _markN = function(m, n) {
|
||||
return function() {
|
||||
m.mark(n);
|
||||
};
|
||||
};
|
||||
|
||||
var fifteenMinuteRate = function(m) {
|
||||
return function() {
|
||||
return m.fifteenMinuteRate();
|
||||
};
|
||||
};
|
||||
|
||||
var fiveMinuteRate = function(m) {
|
||||
return function() {
|
||||
return m.fiveMinuteRate();
|
||||
};
|
||||
};
|
||||
|
||||
var oneMinuteRate = function(m) {
|
||||
return function() {
|
||||
return m.oneMinuteRate();
|
||||
};
|
||||
};
|
||||
|
||||
var meanRate = function(m) {
|
||||
return function() {
|
||||
return m.meanRate();
|
||||
};
|
||||
};
|
||||
|
||||
var count = function(m) {
|
||||
return function() {
|
||||
return m.count;
|
||||
};
|
||||
};
|
||||
|
||||
exports._new = _new;
|
||||
exports._markN = _markN;
|
||||
exports.fifteenMinuteRate = fifteenMinuteRate;
|
||||
exports.fiveMinuteRate = fiveMinuteRate;
|
||||
exports.oneMinuteRate = oneMinuteRate;
|
||||
exports.meanRate = meanRate;
|
||||
exports.count = count;
|
63
src/System/Metrics/Meter.purs
Normal file
63
src/System/Metrics/Meter.purs
Normal file
@ -0,0 +1,63 @@
|
||||
module System.Metrics.Meter
|
||||
( Meter
|
||||
, Summary
|
||||
, new
|
||||
, markN
|
||||
, mark
|
||||
, fifteenMinuteRate
|
||||
, fiveMinuteRate
|
||||
, oneMinuteRate
|
||||
, meanRate
|
||||
, count
|
||||
, read
|
||||
) where
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Control.Monad.Eff.Ref (REF)
|
||||
import Data.Function.Uncurried (Fn2, runFn2)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Generic.Rep.Show (genericShow)
|
||||
import Prelude (class Eq, class Show, Unit, (<$>), (<*>))
|
||||
|
||||
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)
|
||||
foreign import fifteenMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
|
||||
foreign import fiveMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
|
||||
foreign import oneMinuteRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
|
||||
foreign import meanRate :: forall eff. Meter -> Eff (ref :: REF | eff) Number
|
||||
foreign import count :: forall eff. Meter -> Eff (ref :: REF | eff) Int
|
||||
|
||||
new :: forall eff. Eff (ref :: REF | eff) Meter
|
||||
new = _new
|
||||
|
||||
markN :: forall eff. Meter -> Int -> Eff (ref :: REF | eff) Unit
|
||||
markN = runFn2 _markN
|
||||
|
||||
mark :: forall eff. Meter -> Eff (ref :: REF | eff) Unit
|
||||
mark m = markN m 1
|
||||
|
||||
newtype Summary = Summary {
|
||||
count :: Int
|
||||
, m1 :: Number
|
||||
, m5 :: Number
|
||||
, m15 :: Number
|
||||
, mean :: Number
|
||||
}
|
||||
|
||||
derive instance eqSummary :: Eq Summary
|
||||
derive instance genericSummary :: Generic Summary _
|
||||
instance showSummary :: Show Summary where
|
||||
show = genericShow
|
||||
|
||||
read :: forall eff. Meter -> Eff (ref :: REF | eff) Summary
|
||||
read m = Summary <$> ({ count: _
|
||||
, m1: _
|
||||
, m5: _
|
||||
, m15: _
|
||||
, mean: _
|
||||
} <$> count m
|
||||
<*> oneMinuteRate m
|
||||
<*> fiveMinuteRate m
|
||||
<*> fifteenMinuteRate m
|
||||
<*> meanRate m)
|
92
src/System/Metrics/Timer.purs
Normal file
92
src/System/Metrics/Timer.purs
Normal file
@ -0,0 +1,92 @@
|
||||
module System.Metrics.Timer
|
||||
( Timer
|
||||
, Summary
|
||||
, new
|
||||
, update
|
||||
, fifteenMinuteRate
|
||||
, fiveMinuteRate
|
||||
, oneMinuteRate
|
||||
, meanRate
|
||||
, clear
|
||||
, percentiles
|
||||
, mean
|
||||
, stdDev
|
||||
, min
|
||||
, max
|
||||
, sum
|
||||
, count
|
||||
, read
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Control.Monad.Eff (Eff)
|
||||
import Control.Monad.Eff.Ref (REF)
|
||||
import Data.Generic.Rep (class Generic)
|
||||
import Data.Generic.Rep.Show (genericShow)
|
||||
import Data.Maybe (Maybe)
|
||||
import Data.Time.Duration (class Duration, Milliseconds(..), fromDuration)
|
||||
import System.Metrics.Histogram (Histogram)
|
||||
import System.Metrics.Histogram as Histogram
|
||||
import System.Metrics.Meter (Meter)
|
||||
import System.Metrics.Meter as Meter
|
||||
|
||||
newtype Timer = Timer { meter :: Meter, histogram :: Histogram }
|
||||
|
||||
new :: forall eff. Eff (ref :: REF | eff) Timer
|
||||
new = Timer <$> ({ meter: _, histogram: _ }
|
||||
<$> Meter.new
|
||||
<*> Histogram.newWithExponentialDecaySampling 1028 0.015)
|
||||
|
||||
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
|
||||
|
||||
fifteenMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
|
||||
fifteenMinuteRate (Timer { meter }) = Meter.fifteenMinuteRate meter
|
||||
|
||||
fiveMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
|
||||
fiveMinuteRate (Timer { meter }) = Meter.fiveMinuteRate meter
|
||||
|
||||
oneMinuteRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
|
||||
oneMinuteRate (Timer { meter }) = Meter.oneMinuteRate meter
|
||||
|
||||
meanRate :: forall eff. Timer -> Eff (ref :: REF | eff) Number
|
||||
meanRate (Timer { meter }) = Meter.meanRate meter
|
||||
|
||||
clear :: forall eff. Timer -> Eff (ref :: REF | eff) Unit
|
||||
clear (Timer { histogram }) = Histogram.clear histogram
|
||||
|
||||
percentiles :: forall eff. Timer -> Array Number -> Eff (ref :: REF | eff) (Maybe (Array Number))
|
||||
percentiles (Timer { histogram }) = Histogram.percentiles histogram
|
||||
|
||||
mean :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
mean (Timer { histogram }) = Histogram.mean histogram
|
||||
|
||||
stdDev :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
stdDev (Timer { histogram }) = Histogram.stdDev histogram
|
||||
|
||||
min :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
min (Timer { histogram }) = Histogram.min histogram
|
||||
|
||||
max :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
max (Timer { histogram }) = Histogram.max histogram
|
||||
|
||||
sum :: forall eff. Timer -> Eff (ref :: REF | eff) (Maybe Number)
|
||||
sum (Timer { histogram }) = Histogram.sum histogram
|
||||
|
||||
count :: forall eff. Timer -> Eff (ref :: REF | eff) Int
|
||||
count (Timer { histogram }) = Histogram.count histogram
|
||||
|
||||
newtype Summary = Summary { duration :: Histogram.Summary, rate :: Meter.Summary }
|
||||
|
||||
derive instance eqSummary :: Eq Summary
|
||||
derive instance genericSummary :: Generic Summary _
|
||||
instance showSummary :: Show Summary where
|
||||
show = genericShow
|
||||
|
||||
read :: forall eff. Timer -> Eff (ref :: REF | eff) Summary
|
||||
read (Timer { meter, histogram }) =
|
||||
Summary <$> ({ duration: _, rate: _} <$> Histogram.read histogram <*> Meter.read meter)
|
Loading…
Reference in New Issue
Block a user