Skip to content

Instantly share code, notes, and snippets.

@shirren
Created August 16, 2018 04:42
Show Gist options
  • Save shirren/332523d2f455eafc18a9ec931cc6f12f to your computer and use it in GitHub Desktop.
Save shirren/332523d2f455eafc18a9ec931cc6f12f to your computer and use it in GitHub Desktop.
Haskell example to retrieve metrics from Keen.io via its rest interface
{-# OPTIONS -Wno-unused-top-binds #-}
{-# OPTIONS -Wname-shadowing #-}
module Analysis.Keen where
import Data.Aeson
import qualified Data.ByteString.Char8 as BC
import Data.Text (Text)
import Data.Semigroup
import Network.HTTP.Simple
( Request
, defaultRequest
, getResponseBody
, httpJSON
, setRequestBodyJSON
, setRequestHeader
, setRequestHost
, setRequestMethod
, setRequestPath
, setRequestPort
, setRequestSecure
)
-- Keen api read key.
-- TODO: Read this value from the evironment.
readKey :: BC.ByteString
readKey = "INSERT_KEEN_READ_KEY"
-- Keen base url.
keenHost :: BC.ByteString
keenHost = "api.keen.io"
-- ADT to represent a Keen result
newtype KeenResult = KeenResult {
keenResult :: Int
} deriving Show
instance FromJSON KeenResult
where
parseJSON (Object o) = KeenResult <$> (o .: "result")
instance Semigroup KeenResult
where
(<>) (KeenResult result1) (KeenResult result2) = KeenResult $ result1 + result2
-- A Keen request can be a filtered request in which case it is also
-- built from the Filter ADT.
data KeenFilter = KeenInFilter {
propertyName :: Text,
operator :: Text,
propertyValue :: [Text]
}
instance ToJSON KeenFilter
where
toJSON (KeenInFilter prop op val) = object
[ "property_name" .= prop
, "operator" .= op
, "property_value" .= val
]
-- Simple function to set default value on operator.
keenInFilter :: Text -> [Text] -> KeenFilter
keenInFilter name = KeenInFilter name "in"
-- Definition of Keen request ADT which is a sum type of either just an
-- event and time frame, or event, timeframe and a list of filters.
data KeenRequest = KeenRequest Text Text Text |
KeenFilterRequest {
event :: Text,
timeframe :: Text,
timezone :: Text,
filters :: [KeenFilter]
} |
KeenGroupByFilterRequest {
event :: Text,
groupBy :: Text,
timeframe :: Text,
timezone :: Text,
filters :: [KeenFilter]
}
instance ToJSON KeenRequest
where
toJSON (KeenRequest event timeframe timezone) = object
[ "event_collection" .= event
, "timeframe" .= timeframe
, "timezone" .= timezone
]
toJSON (KeenFilterRequest event timeframe timezone filters) = object
[ "event_collection" .= event
, "timeframe" .= timeframe
, "timezone" .= timezone
, "filters" .= filters
]
toJSON (KeenGroupByFilterRequest event groupBy timeframe timezone filters) = object
[ "event_collection" .= event
, "group_by" .= groupBy
, "timeframe" .= timeframe
, "timezone" .= timezone
, "filters" .= filters
]
-- Build a secure keen request.
buildRequest :: BC.ByteString -> BC.ByteString -> KeenRequest -> Request
buildRequest method path body = setRequestMethod method
$ setRequestHost keenHost
$ setRequestHeader "Authorization" [readKey]
$ setRequestPath completePath
$ setRequestBodyJSON body
$ setRequestSecure True
$ setRequestPort 443 defaultRequest
where
completePath = mconcat [apiPath, "/", projectId, "/queries/", path]
apiPath = "/3.0/projects"
projectId = "your_project_id"
-- Send a keen request to the Keen server and obtain the response. As we
-- are making a Http request, the response is of type IO.
sendKeenRequest :: Request -> IO KeenResult
sendKeenRequest request = getResponseBody <$> response
where
response = httpJSON request
-- Utility to generate a generic count request.
buildCountRequest :: KeenRequest -> Request
buildCountRequest = buildRequest "POST" "count"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment