ekg-json (empty) → 0.1.0.0
raw patch · 4 files changed
+208/−0 lines, 4 filesdep +aesondep +basedep +ekg-coresetup-changed
Dependencies added: aeson, base, ekg-core, text, unordered-containers
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- System/Metrics/Json.hs +144/−0
- ekg-json.cabal +32/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Johan Tibell++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Johan Tibell nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ System/Metrics/Json.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Encoding of ekg metrics as JSON. The encoding defined by the+-- functions in this module are standardized and used by the ekg web+-- UI. The purpose of this module is to let other web servers and+-- frameworks than the one used by the ekg package expose ekg metrics.+module System.Metrics.Json+ ( -- * Converting metrics to JSON values+ sampleToJson+ , valueToJson++ -- ** Newtype wrappers with instances+ , Sample(..)+ , Value(..)+ ) where++import Data.Aeson ((.=))+import qualified Data.Aeson.Encode as A+import qualified Data.Aeson.Types as A+import qualified Data.HashMap.Strict as M+import Data.Int (Int64)+import qualified Data.Text as T+import qualified System.Metrics as Metrics+import qualified System.Metrics.Distribution as Distribution++------------------------------------------------------------------------+-- * Converting metrics to JSON values+++-- | Encode metrics as nested JSON objects. Each "." in the metric+-- name introduces a new level of nesting. For example, the metrics+-- @[("foo.bar", 10), ("foo.baz", "label")]@ are encoded as+--+-- > {+-- > "foo": {+-- > "bar": {+-- > "type:", "c",+-- > "val": 10+-- > },+-- > "baz": {+-- > "type": "l",+-- > "val": "label"+-- > }+-- > }+-- > }+--+sampleToJson :: Metrics.Sample -> A.Value+sampleToJson metrics =+ buildOne metrics $ A.emptyObject+ where+ buildOne :: M.HashMap T.Text Metrics.Value -> A.Value -> A.Value+ buildOne m o = M.foldlWithKey' build o m++ build :: A.Value -> T.Text -> Metrics.Value -> A.Value+ build m name val = go m (T.splitOn "." name) val++ go :: A.Value -> [T.Text] -> Metrics.Value -> A.Value+ go (A.Object m) [str] val = A.Object $ M.insert str metric m+ where metric = valueToJson val+ go (A.Object m) (str:rest) val = case M.lookup str m of+ Nothing -> A.Object $ M.insert str (go A.emptyObject rest val) m+ Just m' -> A.Object $ M.insert str (go m' rest val) m+ go v _ _ = typeMismatch "Object" v++typeMismatch :: String -- ^ The expected type+ -> A.Value -- ^ The actual value encountered+ -> a+typeMismatch expected actual =+ error $ "when expecting a " ++ expected ++ ", encountered " ++ name +++ " instead"+ where+ name = case actual of+ A.Object _ -> "Object"+ A.Array _ -> "Array"+ A.String _ -> "String"+ A.Number _ -> "Number"+ A.Bool _ -> "Boolean"+ A.Null -> "Null"++-- | Encodes a single metric as a JSON object. Example:+--+-- > {+-- > "type": "c",+-- > "val": 89460+-- > }+--+valueToJson :: Metrics.Value -> A.Value+valueToJson (Metrics.Counter n) = scalarToJson n CounterType+valueToJson (Metrics.Gauge n) = scalarToJson n GaugeType+valueToJson (Metrics.Label l) = scalarToJson l LabelType+valueToJson (Metrics.Distribution l) = distrubtionToJson l++-- | Convert a scalar metric (i.e. counter, gauge, or label) to a JSON+-- value.+scalarToJson :: A.ToJSON a => a -> MetricType -> A.Value+scalarToJson val ty = A.object+ ["val" .= val, "type" .= metricType ty]+{-# SPECIALIZE scalarToJson :: Int64 -> MetricType -> A.Value #-}+{-# SPECIALIZE scalarToJson :: T.Text -> MetricType -> A.Value #-}++data MetricType =+ CounterType+ | GaugeType+ | LabelType+ | DistributionType++metricType :: MetricType -> T.Text+metricType CounterType = "c"+metricType GaugeType = "g"+metricType LabelType = "l"+metricType DistributionType = "d"++-- | Convert a distribution to a JSON value.+distrubtionToJson :: Distribution.Stats -> A.Value+distrubtionToJson stats = A.object+ [ "mean" .= Distribution.mean stats+ , "variance" .= Distribution.variance stats+ , "count" .= Distribution.count stats+ , "sum" .= Distribution.sum stats+ , "min" .= Distribution.min stats+ , "max" .= Distribution.max stats+ , "type" .= metricType DistributionType+ ]++------------------------------------------------------------------------+-- ** Newtype wrappers with instances++-- | Newtype wrapper that provides a 'A.ToJSON' instances for the+-- underlying 'Metrics.Sample' without creating an orphan instance.+newtype Sample = Sample Metrics.Sample+ deriving Show++-- | Uses 'sampleToJson'.+instance A.ToJSON Sample where+ toJSON (Sample s) = sampleToJson s++-- | Newtype wrapper that provides a 'A.ToJSON' instances for the+-- underlying 'Metrics.Value' without creating an orphan instance.+newtype Value = Value Metrics.Value+ deriving Show++-- | Uses 'valueToJson'.+instance A.ToJSON Value where+ toJSON (Value v) = valueToJson v
+ ekg-json.cabal view
@@ -0,0 +1,32 @@+name: ekg-json+version: 0.1.0.0+synopsis: JSON encoding of ekg metrics+description:+ Encodes ekg metrics as JSON, using the same encoding as used by the+ ekg package, thus allowing ekg metrics to be served by other HTTP+ servers than the one used by the ekg package.+homepage: https://github.com/tibbe/ekg-json+bug-reports: https://github.com/tibbe/ekg-json/issues+license: BSD3+license-file: LICENSE+author: Johan Tibell+maintainer: johan.tibell@gmail.com+category: Distribution+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules:+ System.Metrics.Json+ build-depends:+ aeson < 0.11,+ base >= 4.5 && < 4.9,+ ekg-core >= 0.1 && < 0.2,+ text < 1.3,+ unordered-containers < 0.3++ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/tibbe/ekg-json.git