Stability | experimental |
---|---|
Portability | GHC |
Safe Haskell | None |
Language | Haskell2010 |
- write :: Timestamp time => WriteParams -> Line time -> IO ()
- writeBatch :: (Timestamp time, Foldable f) => WriteParams -> f (Line time) -> IO ()
- writeByteString :: WriteParams -> ByteString -> IO ()
- data WriteParams
- writeParams :: Database -> WriteParams
- retentionPolicy :: Lens' WriteParams (Maybe Key)
- data Line time = Line !Key !(Map Key Text) !(Map Key LineField) !(Maybe time)
- measurement :: Lens' (Line time) Key
- tagSet :: Lens' (Line time) (Map Key Text)
- fieldSet :: Lens' (Line time) (Map Key LineField)
- timestamp :: Lens' (Line time) (Maybe time)
- data Field (n :: Nullability) where
- type LineField = Field NonNullable
- type QueryField = Field Nullable
- class Timestamp time where
- precisionScale :: Fractional a => Precision ty -> a
- precisionName :: Precision ty -> Text
- data Query
- query :: QueryResults a => QueryParams -> Query -> IO (Vector a)
- queryChunked :: QueryResults a => QueryParams -> Optional Int -> Query -> FoldM IO (Vector a) r -> IO r
- formatQuery :: Format Query r -> r
- (%) :: Format b c -> Format a b -> Format a c
- data QueryParams
- queryParams :: Database -> QueryParams
- authentication :: HasCredentials a => Lens' a (Maybe Credentials)
- class QueryResults a where
- parseResultsWith :: (Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a) -> Value -> Parser (Vector a)
- getField :: Monad m => Text -> Vector Text -> Vector Value -> m Value
- getTag :: Monad m => Text -> HashMap Text Value -> m Value
- parseUTCTime :: Precision ty -> Value -> Parser UTCTime
- parsePOSIXTime :: Precision ty -> Value -> Parser POSIXTime
- parseQueryField :: Value -> Parser QueryField
- manage :: QueryParams -> Query -> IO ()
- data Precision (ty :: RequestType) where
- Nanosecond :: Precision ty
- Microsecond :: Precision ty
- Millisecond :: Precision ty
- Second :: Precision ty
- Minute :: Precision ty
- Hour :: Precision ty
- RFC3339 :: Precision QueryRequest
- data Database
- formatDatabase :: Format Database r -> r
- data Key
- formatKey :: Format Key r -> r
- data Server
- defaultServer :: Server
- host :: Lens' Server Text
- port :: Lens' Server Int
- ssl :: Lens' Server Bool
- data Credentials
- credentials :: Text -> Text -> Credentials
- user :: Lens' Credentials Text
- password :: Lens' Credentials Text
- data InfluxException
- class HasServer a where
- class HasDatabase a where
- class HasPrecision (ty :: RequestType) a | a -> ty where
- class HasManager a where
Documentation
Getting started
This tutorial assumes the following language extensions and imports.
>>>
:set -XOverloadedStrings
>>>
:set -XRecordWildCards
>>>
import Database.InfluxDB
>>>
import qualified Database.InfluxDB.Format as F
>>>
import Control.Lens
>>>
import qualified Data.Map as Map
>>>
import Data.Time
>>>
import qualified Data.Vector as V
The examples below roughly follows the README in the official Go client library.
Creating a database
This library assumes the lens
package in some APIs. Here we use ?~
to set the authentication
parameters of type Maybe
.Credentials
Also note that in order to construct a Query
, we use formatQuery
with the
database
formatter. There are many other formatters defined in
Database.InfluxDB.Format.
>>>
let db = "square_holes"
>>>
let bubba = credentials "bubba" "bumblebeetuna"
>>>
let p = queryParams db & authentication ?~ bubba
>>>
manage p $ formatQuery ("CREATE DATABASE "%F.database) db
Writing data
write
or writeBatch
can be used to write data. In general writeBatch
should be used for efficiency when writing multiple data points.
>>>
let wp = writeParams db & authentication ?~ bubba & precision .~ Second
>>>
let cpuUsage = "cpu_usage"
>>>
:{
writeBatch wp [ Line cpuUsage (Map.singleton "cpu" "cpu-total") (Map.fromList [ ("idle", FieldFloat 10.1) , ("system", FieldFloat 53.3) , ("user", FieldFloat 46.6) ]) (Nothing :: Maybe UTCTime) ] :}
Note that the type signature of the timestamp is necessary. Otherwise it doesn't type check.
Querying data
First we define a placeholder data type called CPUUsage
and a QueryResults
instance. getField
, parseUTCTime
and parseQueryField
etc are avilable to
make JSON decoding easier.
>>>
:{
data CPUUsage = CPUUsage { time :: UTCTime , cpuIdle, cpuSystem, cpuUser :: Double } deriving Show instance QueryResults CPUUsage where parseResults prec = parseResultsWithDecoder strictDecoder $ \_ _ columns fields -> do time <- getField "time" columns fields >>= parseUTCTime prec FieldFloat cpuIdle <- getField "idle" columns fields >>= parseQueryField FieldFloat cpuSystem <- getField "system" columns fields >>= parseQueryField FieldFloat cpuUser <- getField "user" columns fields >>= parseQueryField return CPUUsage {..} :}>>>
query p $ formatQuery ("SELECT * FROM "%F.key) cpuUsage :: IO (V.Vector CPUUsage)
[CPUUsage {time = 2017-06-17 15:41:40.52659044 UTC, cpuIdle = 10.1, cpuSystem = 53.3, cpuUser = 46.6}]
Note that the type signature on query here is also necessary to type check.
Writing data
InfluxDB has two ways to write data into it, via HTTP and UDP. This module only exports functions for the HTTP API. For UDP, you can use a qualified import:
import qualified Database.InfluxDB.Write.UDP as UDP
write :: Timestamp time => WriteParams -> Line time -> IO () Source #
Write a Line
.
>>>
let p = writeParams "test-db"
>>>
write p $ Line "room_temp" Map.empty (Map.fromList [("temp", FieldFloat 25.0)]) (Nothing :: Maybe UTCTime)
writeBatch :: (Timestamp time, Foldable f) => WriteParams -> f (Line time) -> IO () Source #
Write multiple Line
s in a batch.
This is more efficient than calling write
multiple times.
>>>
let p = writeParams "test-db"
>>>
:{
writeBatch p [ Line "temp" (Map.singleton "city" "tokyo") (Map.fromList [("temp", FieldFloat 25.0)]) (Nothing :: Maybe UTCTime) , Line "temp" (Map.singleton "city" "osaka") (Map.fromList [("temp", FieldFloat 25.2)]) (Nothing :: Maybe UTCTime) ] :}
writeByteString :: WriteParams -> ByteString -> IO () Source #
Write a raw ByteString
Write parameters
data WriteParams Source #
The full set of parameters for the HTTP writer.
HasCredentials WriteParams Source # | Authentication info for the write
|
HasManager WriteParams Source # |
|
HasDatabase WriteParams Source # |
|
HasServer WriteParams Source # |
|
HasPrecision WriteRequest WriteParams Source # |
|
writeParams :: Database -> WriteParams Source #
Smart constructor for WriteParams
Default parameters:
retentionPolicy :: Lens' WriteParams (Maybe Key) Source #
Target retention policy for the write.
InfluxDB writes to the default
retention policy if this parameter is set
to Nothing
.
>>>
let p = writeParams "foo" & retentionPolicy .~ Just "two_hours"
>>>
p ^. retentionPolicy
Just "two_hours"
The Line protocol
Placeholder for the Line Protocol
See https://docs.influxdata.com/influxdb/v1.2/write_protocols/line_protocol_tutorial/ for the concrete syntax.
measurement :: Lens' (Line time) Key Source #
Name of the measurement that you want to write your data to.
tagSet :: Lens' (Line time) (Map Key Text) Source #
Tag(s) that you want to include with your data point. Tags are optional in
the Line Protocol, so you can set it empty
.
fieldSet :: Lens' (Line time) (Map Key LineField) Source #
Field(s) for your data point. Every data point requires at least one field
in the Line Protocol, so it shouldn't be empty
.
timestamp :: Lens' (Line time) (Maybe time) Source #
Timestamp for your data point. You can put whatever type of timestamp that
is an instance of the Timestamp
class.
data Field (n :: Nullability) where Source #
type LineField = Field NonNullable Source #
Field type for the line protocol. The line protocol doesn't accept null values.
type QueryField = Field Nullable Source #
Field type for queries. Queries can contain null values.
class Timestamp time where Source #
A Timestamp
is something that can be converted to a valid
InfluxDB timestamp, which is represented as a 64-bit integer.
precisionScale :: Fractional a => Precision ty -> a Source #
Scale of the type precision.
>>>
precisionScale RFC3339
1.0e-9>>>
precisionScale Microsecond
1.0e-6
precisionName :: Precision ty -> Text Source #
Name of the time precision.
>>>
precisionName Nanosecond
"n"
Querying data
query
and queryChunked
can be used to query data. If your dataset fits your
memory, query
is easier to use. If it doesn't, use queryChunked
to stream
data.
An InfluxDB query.
A spec of the format is available at https://docs.influxdata.com/influxdb/v1.2/query_language/spec/.
A Query
can be constructed using either
- the
IsString
instance with-XOverloadedStrings
- or
formatQuery
.
>>>
:set -XOverloadedStrings
>>>
"SELECT * FROM series" :: Query
"SELECT * FROM series">>>
import qualified Database.InfluxDB.Format as F
>>>
formatQuery ("SELECT * FROM "%F.key) "series"
"SELECT * FROM \"series\""
NOTE: Currently this library doesn't support type-safe query construction.
query :: QueryResults a => QueryParams -> Query -> IO (Vector a) Source #
Query data from InfluxDB.
It may throw InfluxException
.
:: QueryResults a | |
=> QueryParams | |
-> Optional Int | Chunk size By |
-> Query | |
-> FoldM IO (Vector a) r | |
-> IO r |
Same as query
but it instructs InfluxDB to stream chunked responses
rather than returning a huge JSON object. This can be lot more efficient than
query
if the result is huge.
It may throw InfluxException
.
Query construction
There are various utility functions available in Database.InfluxDB.Format. This module is designed to be imported as qualified:
import Database.InfluxDB import qualified Database.InfluxDB.Format as F
formatQuery :: Format Query r -> r Source #
Format a Query
.
>>>
formatQuery "SELECT * FROM series"
"SELECT * FROM series">>>
formatQuery ("SELECT * FROM "%key) "series"
"SELECT * FROM \"series\""
Query parameters
data QueryParams Source #
The full set of parameters for the query API
HasCredentials QueryParams Source # | Authentication info for the query
|
HasManager QueryParams Source # |
|
HasDatabase QueryParams Source # |
|
HasServer QueryParams Source # |
|
HasPrecision QueryRequest QueryParams Source # | Returning JSON responses contain timestamps in the specified precision/format.
|
queryParams :: Database -> QueryParams Source #
Smart constructor for QueryParams
Default parameters:
authentication :: HasCredentials a => Lens' a (Maybe Credentials) Source #
User name and password to be used when sending requests to InfluxDB.
Parsing results
class QueryResults a where Source #
Types that can be converted from an JSON object returned by InfluxDB.
For example the h2o_feet
series in
the official document
can be encoded as follows:
>>>
:{
data H2OFeet = H2OFeet { time :: UTCTime , levelDesc :: T.Text , location :: T.Text , waterLevel :: Double } instance QueryResults H2OFeet where parseResults prec = parseResultsWith $ \_ _ columns fields -> do time <- getField "time" columns fields >>= parseUTCTime prec String levelDesc <- getField "level_description" columns fields String location <- getField "location" columns fields FieldFloat waterLevel <- getField "water_level" columns fields >>= parseQueryField return H2OFeet {..} :}
parseResults :: Precision QueryRequest -> Value -> Parser (Vector a) Source #
Parse a JSON object as an array of values of expected type.
QueryResults Void Source # | |
QueryResults ShowSeries Source # | |
QueryResults ShowQuery Source # | |
((~) * a Value, (~) * b Value) => QueryResults (a, b) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value) => QueryResults (a, b, c) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value, (~) * d Value) => QueryResults (a, b, c, d) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value, (~) * d Value, (~) * e Value) => QueryResults (a, b, c, d, e) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value, (~) * d Value, (~) * e Value, (~) * f Value) => QueryResults (a, b, c, d, e, f) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value, (~) * d Value, (~) * e Value, (~) * f Value, (~) * g Value) => QueryResults (a, b, c, d, e, f, g) Source # | |
((~) * a Value, (~) * b Value, (~) * c Value, (~) * d Value, (~) * e Value, (~) * f Value, (~) * g Value, (~) * h Value) => QueryResults (a, b, c, d, e, f, g, h) Source # | |
:: (Maybe Text -> HashMap Text Text -> Vector Text -> Array -> Parser a) | A parser that takes
to construct a value. |
-> Value | |
-> Parser (Vector a) |
A helper function to parse a JSON response in
parseResults
.
Get a field value from a column name
Get a tag value from a tag name
parseUTCTime :: Precision ty -> Value -> Parser UTCTime Source #
Parse either a POSIX timestamp or RFC3339 formatted timestamp as UTCTime
.
parsePOSIXTime :: Precision ty -> Value -> Parser POSIXTime Source #
Parse either a POSIX timestamp or RFC3339 formatted timestamp as
POSIXTime
.
parseQueryField :: Value -> Parser QueryField Source #
Parse a QueryField
.
Database management
manage :: QueryParams -> Query -> IO () Source #
Send a database management query to InfluxDB.
>>>
let db = "manage-test"
>>>
let p = queryParams db
>>>
manage p $ F.formatQuery ("CREATE DATABASE "%F.database) db
Common data types and classes
data Precision (ty :: RequestType) where Source #
Predefined set of time precision.
RFC3339
is only available for QueryRequest
s.
Nanosecond :: Precision ty | POSIX time in ns |
Microsecond :: Precision ty | POSIX time in μs |
Millisecond :: Precision ty | POSIX time in ms |
Second :: Precision ty | POSIX time in s |
Minute :: Precision ty | POSIX time in minutes |
Hour :: Precision ty | POSIX time in hours |
RFC3339 :: Precision QueryRequest | Nanosecond precision time in a human readable format, like
|
Database name.
formatDatabase
can be used to construct a
Database
.
formatDatabase :: Format Database r -> r Source #
Format a Database
.
>>>
formatDatabase "test-db"
"test-db"
String type that is used for measurements, tag keys and field keys.
:: Text | User name |
-> Text | Password |
-> Credentials |
user :: Lens' Credentials Text Source #
User name to access InfluxDB.
>>>
let creds = credentials "john" "passw0rd"
>>>
creds ^. user
"john"
Exception
data InfluxException Source #
Exceptions used in this library.
In general, the library tries to convert exceptions from the dependent libraries to the following types of errors.
ServerError String | Server side error. You can expect to get a successful response once the issue is resolved on the server side. |
ClientError String Request | Client side error. You need to fix your query to get a successful response. |
UnexpectedResponse String ByteString | Received an unexpected response. The This can happen e.g. when the response from InfluxDB is incompatible with what this library expects due to an upstream format change etc. |
HTTPException HttpException | HTTP communication error. Typical HTTP errors (4xx and 5xx) are covered by |
class HasServer a where Source #
HasServer PingParams Source # |
|
HasServer QueryParams Source # |
|
HasServer WriteParams Source # |
|
class HasDatabase a where Source #
HasDatabase QueryParams Source # |
|
HasDatabase ShowQuery Source # | > v <- query (queryParams "_internal") "SHOW QUERIES" :: IO (V.Vector ShowQuery) > v ^.. each.database ["_internal"] |
HasDatabase WriteParams Source # |
|
class HasPrecision (ty :: RequestType) a | a -> ty where Source #
HasPrecision QueryRequest QueryParams Source # | Returning JSON responses contain timestamps in the specified precision/format.
|
HasPrecision WriteRequest WriteParams Source # |
|
HasPrecision WriteRequest WriteParams Source # | Timestamp precision. In the UDP API, all timestamps are sent in nanosecond but you can specify lower precision. The writer just rounds timestamps to the specified precision. |
class HasManager a where Source #
manager :: Lens' a (Either ManagerSettings Manager) Source #
HTTP manager settings or a manager itself.
If it's set to ManagerSettings
, the library will create a Manager
from
the settings for you.
HasManager PingParams Source # |
|
HasManager QueryParams Source # |
|
HasManager WriteParams Source # |
|