packages feed

honeycomb 0.0.0.3 → 0.1.0.0

raw patch · 7 files changed

+182/−49 lines, 7 filesdep ~aesonPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: aeson

API changes (from Hackage documentation)

+ Honeycomb.API.Auth: ApiKeyAccess :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ApiKeyAccess
+ Honeycomb.API.Auth: Auth :: ApiKeyAccess -> NameAndSlug -> NameAndSlug -> Auth
+ Honeycomb.API.Auth: FailureCode :: Int -> LazyByteString -> FailureResponse
+ Honeycomb.API.Auth: JsonDecodeFailed :: Text -> FailureResponse
+ Honeycomb.API.Auth: NameAndSlug :: Text -> Text -> NameAndSlug
+ Honeycomb.API.Auth: [apiKeyAccess] :: Auth -> ApiKeyAccess
+ Honeycomb.API.Auth: [boards] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [columns] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [createDatasets] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [environment] :: Auth -> NameAndSlug
+ Honeycomb.API.Auth: [events] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [markers] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [name] :: NameAndSlug -> Text
+ Honeycomb.API.Auth: [privateBoards] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [queries] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [recipients] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [slos] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: [slug] :: NameAndSlug -> Text
+ Honeycomb.API.Auth: [team] :: Auth -> NameAndSlug
+ Honeycomb.API.Auth: [triggers] :: ApiKeyAccess -> Bool
+ Honeycomb.API.Auth: data ApiKeyAccess
+ Honeycomb.API.Auth: data Auth
+ Honeycomb.API.Auth: data FailureResponse
+ Honeycomb.API.Auth: data NameAndSlug
+ Honeycomb.API.Auth: getAuth :: (MonadIO m, MonadHoneycombConfig client m) => m Auth
- Honeycomb: class HasHoneycombClient a
+ Honeycomb: class HasConfig a => HasHoneycombClient a

Files

honeycomb.cabal view
@@ -1,19 +1,19 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.34.7. -- -- see: https://github.com/sol/hpack ----- hash: 71e86a9d866e470b3be18e84cf0f065d7cd0e6d870980972dc38f8eb2488fd6a+-- hash: 2a670d8927ccbe14b8715231c27dedb4b077025fdc2dd914a06603979fa1a011  name:           honeycomb-version:        0.0.0.3+version:        0.1.0.0 description:    Please see the README on GitHub at <https://github.com/githubuser/honeycomb#readme> homepage:       https://github.com/iand675/hs-honeycomb#readme bug-reports:    https://github.com/iand675/hs-honeycomb/issues-author:         Ian Duncan+author:         Ian Duncan, Jade Lovelace maintainer:     ian@iankduncan.com-copyright:      2021 Ian Duncan+copyright:      2021 Ian Duncan, 2022 Mercury Technologies, Inc license:        BSD3 license-file:   LICENSE build-type:     Simple@@ -31,9 +31,12 @@       Honeycomb.API.Events       Honeycomb.API.Markers       Honeycomb.API.Types+      Honeycomb.API.Auth       Honeycomb.Config       Honeycomb.Types   other-modules:+      Honeycomb.Aeson+      Honeycomb.API.Auth.Types       Honeycomb.API.Boards       Honeycomb.API.Columns       Honeycomb.API.Datasets@@ -51,7 +54,7 @@       OverloadedStrings       RecordWildCards   build-depends:-      aeson+      aeson >=2.0     , async     , auto-update     , base >=4.7 && <5@@ -92,7 +95,7 @@       RecordWildCards   ghc-options: -threaded -rtsopts -with-rtsopts=-N   build-depends:-      aeson+      aeson >=2.0     , async     , auto-update     , base >=4.7 && <5
src/Honeycomb.hs view
@@ -11,7 +11,7 @@ Warning, not all configuration options actually do what they claim yet. -} module Honeycomb-  ( +  (   -- * Initializing and shutting down a 'HoneycombClient'     HoneycombClient   , initializeHoneycomb@@ -46,6 +46,7 @@ import Control.Concurrent import Lens.Micro ((%~), (^.), (&)) import Lens.Micro.Extras (view)+import qualified Data.Aeson.KeyMap as KeyMap  initializeHoneycomb :: MonadIO m => Config.Config -> m HoneycombClient initializeHoneycomb conf = liftIO $ do@@ -99,7 +100,7 @@       x <- uniformR (1, n) clientGen       pure (1 == x, x)   when shouldSend $ do-    let event_ = API.Event specifiedSampleRate (timestamp e) (fields e)+    let event_ = API.Event specifiedSampleRate (timestamp e) (KeyMap.fromHashMapText $ fields e)         localOptions = honeycombClientL %~ (\c -> c { clientConfig = replaceDataset $ replaceHost $ replaceWriteKey clientConfig })         blockingEvent = runReaderT (API.sendEvent event_) (c & localOptions)     liftIO $ if Config.sendBlocking clientConfig
+ src/Honeycomb/API/Auth.hs view
@@ -0,0 +1,25 @@+module Honeycomb.API.Auth (module Honeycomb.API.Auth.Types, getAuth) where++import Control.Exception (throwIO)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Reader.Class (asks)+import Data.Aeson (eitherDecode)+import qualified Data.Text as T+import Honeycomb+  ( HasHoneycombClient (honeycombClientL),+    MonadHoneycomb,+  )+import Honeycomb.API.Auth.Types+import Honeycomb.Client.Internal (MonadHoneycombConfig, get)+import Lens.Micro.Extras (view)+import Network.HTTP.Client (Response (responseBody))+import Network.HTTP.Simple (getResponseBody, getResponseStatusCode, httpLBS)++getAuth :: (MonadIO m, MonadHoneycombConfig client m) => m Auth+getAuth = do+  r <- get httpLBS ["1", "auth"] []+  case getResponseStatusCode r of+    200 -> case eitherDecode (responseBody r) of+      Right r -> pure r+      Left r -> liftIO . throwIO . JsonDecodeFailed . T.pack $ r+    other -> liftIO . throwIO $ FailureCode other (getResponseBody r)
+ src/Honeycomb/API/Auth/Types.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE TemplateHaskell #-}++module Honeycomb.API.Auth.Types where++import Control.Exception+import Data.Aeson.TH (defaultOptions, deriveFromJSON)+import Data.ByteString (ByteString)+import Data.ByteString.Lazy (LazyByteString)+import Data.Text (Text)+import Honeycomb.Aeson (snakeCaseOptions)++data NameAndSlug = NameAndSlug+  { name :: Text+  , slug :: Text+  }+  deriving stock (Show, Eq)++$(deriveFromJSON snakeCaseOptions ''NameAndSlug)++data ApiKeyAccess = ApiKeyAccess+  { events :: Bool+  , markers :: Bool+  , triggers :: Bool+  , boards :: Bool+  , queries :: Bool+  , columns :: Bool+  , createDatasets :: Bool+  , slos :: Bool+  , recipients :: Bool+  , privateBoards :: Bool+  }+  deriving stock (Show, Eq)++-- XXX: yes, this is intentionally defaultOptions, because for some reason the+-- API is generally snake case but the "createDatasets" is camel case+$(deriveFromJSON defaultOptions ''ApiKeyAccess)++-- | Response to the auth API+--  @+--  {+--    "api_key_access": {+--      "events": true,+--      "markers": true,+--      "triggers": true,+--      "boards": true,+--      "queries": true,+--      "columns": false,+--      "createDatasets": true+--    },+--    "environment": {+--      "name": "Production",+--      "slug": "production"+--    },+--    "team": {+--      "name": "Honeycomb Docs",+--      "slug": "honeycomb-docs"+--    }+--  }+--  @+data Auth = Auth+  { apiKeyAccess :: ApiKeyAccess+  , environment :: NameAndSlug+  , team :: NameAndSlug+  }+  deriving stock (Show, Eq)++$(deriveFromJSON snakeCaseOptions ''Auth)++data FailureResponse+  = FailureCode Int LazyByteString+  | JsonDecodeFailed Text+  deriving stock (Show)+  deriving anyclass (Exception)
+ src/Honeycomb/Aeson.hs view
@@ -0,0 +1,11 @@+module Honeycomb.Aeson (snakeCaseOptions) where+import Data.Aeson++snakeCaseOptions :: Options+snakeCaseOptions =+  defaultOptions+    { fieldLabelModifier = camelTo2 '_'+    , constructorTagModifier = camelTo2 '_'+    }++
src/Honeycomb/Client/Internal.hs view
@@ -1,55 +1,61 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DataKinds #-} {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE FlexibleInstances #-}+ module Honeycomb.Client.Internal where  import Chronos import Control.Concurrent.Async-import Data.Aeson (Value, ToJSON, FromJSON, eitherDecode, encode)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Reader.Class+import Data.Aeson (FromJSON, ToJSON, Value, eitherDecode, encode)+import qualified Data.ByteString.Lazy as L import Data.HashMap.Strict as S import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Vector (Vector) import Data.Word (Word64)+import Honeycomb.Config import qualified Honeycomb.Config as Config-import Network.HTTP.Client-import System.Random.MWC import Honeycomb.Types-import Data.Vector (Vector)-import Network.HTTP.Types-import qualified Data.Text.Encoding as T-import qualified Data.Text as T-import qualified Data.ByteString.Lazy as L import Lens.Micro-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Reader.Class-import UnliftIO.STM (TBQueue) import Lens.Micro.Extras-import Honeycomb.Config+import Network.HTTP.Client+import Network.HTTP.Types+import System.Random.MWC+import UnliftIO.STM (TBQueue)  data HoneycombClient = HoneycombClient   { clientConfig :: Config   , clientGen :: GenIO-  -- | Subject to change+  , clientEventBuffer :: TBQueue (IO ())+  -- ^ Subject to change   -- TODO this respects dispatching to custom host/dataset/writekey/etc, but needs a means of   -- using the bulk events API instead of dispatching a bunch of single event calls.-  , clientEventBuffer :: TBQueue (IO ())-  -- , clientQueueMap :: Map ThreadId -  , clientWorkers :: [Async ()]+  , -- , clientQueueMap :: Map ThreadId+    clientWorkers :: [Async ()]   } -class HasHoneycombClient a where+class HasConfig a => HasHoneycombClient a where   honeycombClientL :: Lens' a HoneycombClient  instance HasHoneycombClient HoneycombClient where   honeycombClientL = lens id (\_ new -> new)  instance HasConfig HoneycombClient where-  configL = lens clientConfig (\c conf -> c { clientConfig = conf })+  configL = lens clientConfig (\c conf -> c {clientConfig = conf})  type MonadHoneycomb env m = (MonadIO m, HasHoneycombClient env, MonadReader env m) +-- | Weaker version of 'MonadHoneycomb' which only provides a config. Useful for+--   just doing HTTP requests without using the events sender.+type MonadHoneycombConfig env m = (HasConfig env, MonadReader env m)+ data Event = Event   { fields :: S.HashMap Text Value   , teamWriteKey :: Maybe Text@@ -59,28 +65,40 @@   , timestamp :: Maybe Time   } +defaultHoneycombRequest :: Text -> [Text] -> [Header] -> Text -> Request+defaultHoneycombRequest apiHost pathPieces hs key =+  defaultRequest+    { host = T.encodeUtf8 apiHost+    , port = 443+    , path = T.encodeUtf8 $ T.intercalate "/" pathPieces+    , secure = True+    , requestHeaders =+        hs+          ++ [ (hUserAgent, "libhoneycomb-haskell/0.0.0.1")+             , (hContentType, "application/json")+             , ("X-Honeycomb-Team", T.encodeUtf8 key)+             ]+    } -post :: (MonadIO m, MonadHoneycomb env m, ToJSON a) => (Request -> m (Response b)) -> [Text] -> RequestHeaders -> a -> m (Response b)+post :: (MonadIO m, MonadHoneycombConfig env m, ToJSON a) => (Request -> m (Response b)) -> [Text] -> RequestHeaders -> a -> m (Response b) post f pathPieces hs x = do-  Config{..} <- asks (view (honeycombClientL . configL))-  let req = defaultRequest -        { method = methodPost-        , host = "api.honeycomb.io"-        , port = 443-        , path = T.encodeUtf8 $ T.intercalate "/" pathPieces-        , secure = True-        , requestHeaders = hs ++-            [ (hUserAgent, "libhoneycomb-haskell/0.0.0.1")-            , (hContentType, "application/json")-            , ("X-Honeycomb-Team", T.encodeUtf8 teamWritekey)-            ]-        -- TODO-        , requestBody = RequestBodyLBS $ encode x-        }+  Config {..} <- asks (view configL)+  let req =+        (defaultHoneycombRequest apiHost pathPieces hs teamWritekey)+          { method = methodPost+          , -- TODO+            requestBody = RequestBodyLBS $ encode x+          }   f req -get :: (MonadIO m, MonadHoneycomb env m, FromJSON a) => (Request -> m (Response b)) -> [Text] -> [(Text, Text)] -> m a-get = undefined+get :: (MonadIO m, MonadHoneycombConfig env m, HasConfig env) => (Request -> m (Response b)) -> [Text] -> RequestHeaders -> m (Response b)+get f pathPieces hs = do+  Config {..} <- asks (view configL)+  let req =+        (defaultHoneycombRequest apiHost pathPieces hs teamWritekey)+          { method = methodGet+          }+  f req  put :: (MonadIO m, MonadHoneycomb env m, FromJSON a) => (Request -> m (Response b)) -> [Text] -> [(Text, Text)] -> m a put = undefined
src/Honeycomb/Config.hs view