Upgrade to Pro — share decks privately, control downloads, hide ads and more …

InfluxDB 2.0 and Flux

Paul Dix
March 28, 2019

InfluxDB 2.0 and Flux

Presented at CloudConf 2019, this talk is an introduction to InfluxDB 2.0 and the new programming and query language, Flux (#fluxlang).

Paul Dix

March 28, 2019
Tweet

More Decks by Paul Dix

Other Decks in Technology

Transcript

  1. InfluxDB 2.0 and #fluxlang
    Paul Dix

    paul@influxdata.com

    @pauldix

    View full-size slide

  2. an open source time series database

    View full-size slide

  3. What is time series data?

    View full-size slide

  4. Stock trades and quotes

    View full-size slide

  5. Two kinds of time series
    data…

    View full-size slide

  6. Regular time series
    t0 t1 t2 t3 t4 t6 t7
    Samples at regular intervals

    View full-size slide

  7. Irregular time series
    t0 t1 t2 t3 t4 t6 t7
    Events whenever they come in

    View full-size slide

  8. Data that you ask
    questions about over time

    View full-size slide

  9. Solve common problems

    View full-size slide

  10. data collector

    View full-size slide

  11. processing, ETL, monitoring, alerting

    View full-size slide

  12. UI, visualization, management

    View full-size slide

  13. TICK
    for time series data

    View full-size slide

  14. Common Schema

    View full-size slide

  15. Line Protocol
    cpu,host=serverA,num=1,region=west idle=1.667,system=2342.2 1492214400000000000

    View full-size slide

  16. Line Protocol
    Measurement
    cpu,host=serverA,num=1,region=west idle=1.667,system=2342.2 1492214400000000000

    View full-size slide

  17. Line Protocol
    cpu,host=serverA,num=1,region=west idle=1.667,system=2342.2 1492214400000000000
    Tags

    View full-size slide

  18. Line Protocol
    cpu,host=serverA,num=1,region=west idle=1.667,system=2342.2 1492214400000000000
    Fields

    View full-size slide

  19. float64, int64, bool, string

    View full-size slide

  20. Line Protocol
    cpu,host=serverA,num=1,region=west idle=1.667,system=2342.2 1492214400000000000
    nanosecond
    epoch

    View full-size slide

  21. Query Language

    View full-size slide

  22. SQL-ish
    select percentile(90, value) from cpu
    where time > now() - 1d
    group by time(10m)

    View full-size slide

  23. No Common API

    View full-size slide

  24. Different Languages for Query
    & Monitoring

    View full-size slide

  25. • MIT Licensed

    • TSDB (write, query)

    • UI & Visualizations, Dashboards

    • Pull Metrics (Prometheus & OpenMetrics)

    • Tasks (background processing, ETL, monitoring/alerting)

    View full-size slide

  26. Officially Supported Client
    Libraries
    Go, Node.js, Ruby, Python, PHP, Java, C#, C, Kotlin

    View full-size slide

  27. Visualization Libraries

    View full-size slide

  28. Data Model
    • Organization

    • Dashboards

    • Tasks

    • Buckets

    • Scrapers & Telegraf configs

    • Labels

    • Users

    View full-size slide

  29. • Query planner

    • Query optimizer

    • Turing complete language, VM, and query engine

    • Multi-language support in Engine

    • Multi-data source support

    • InfluxDB, CLI, REPL, Go library

    View full-size slide

  30. Flux Language Elements

    View full-size slide

  31. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")

    View full-size slide

  32. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Comments

    View full-size slide

  33. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Named Arguments

    View full-size slide

  34. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    String Literals

    View full-size slide

  35. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Buckets, not DBs

    View full-size slide

  36. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Duration Literal

    View full-size slide

  37. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:2018-11-07T00:00:00Z)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Time Literal

    View full-size slide

  38. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Pipe forward operator

    View full-size slide

  39. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_system")
    Anonymous Function

    View full-size slide

  40. // get all data from the telegraf db
    from(bucket:”telegraf/autogen”)
    // filter that by the last hour
    |> range(start:-1h)
    // filter further by series with a specific measurement and field
    |> filter(fn: (r) => (r._measurement == "cpu" or r._measurement == “cpu")
    and r.host == “serverA")
    Predicate Function

    View full-size slide

  41. // variables
    some_int = 23

    View full-size slide

  42. // variables
    some_int = 23
    some_float = 23.2

    View full-size slide

  43. // variables
    some_int = 23
    some_float = 23.2
    some_string = “cpu"

    View full-size slide

  44. // variables
    some_int = 23
    some_float = 23.2
    some_string = “cpu"
    some_duration = 1h

    View full-size slide

  45. // variables
    some_int = 23
    some_float = 23.2
    some_string = “cpu"
    some_duration = 1h
    some_time = 2018-10-10T19:00:00

    View full-size slide

  46. // variables
    some_int = 23
    some_float = 23.2
    some_string = “cpu"
    some_duration = 1h
    some_time = 2018-10-10T19:00:00
    some_array = [1, 6, 20, 22]

    View full-size slide

  47. // variables
    some_int = 23
    some_float = 23.2
    some_string = “cpu"
    some_duration = 1h
    some_time = 2018-10-10T19:00:00
    some_array = [1, 6, 20, 22]
    some_object = {foo: "hello" bar: 22}

    View full-size slide

  48. // defining a pipe forwardable function
    square = (tables=<-) =>
    tables
    |> map(fn: (r) => {r with _value: r._value * r._value})

    View full-size slide

  49. // defining a pipe forwardable function
    square = (tables=<-) =>
    tables
    |> map(fn: (r) => {r with _value: r._value * r._value})
    Accepts a pipe forward
    assigns to tables variable

    View full-size slide

  50. // defining a pipe forwardable function
    square = (tables=<-) =>
    tables
    |> map(fn: (r) => {r with _value: r._value * r._value})
    from(bucket:"foo")
    |> range(start: -1h)
    |> filter(fn: (r) => r._measurement == "samples")
    |> square()
    |> filter(fn: (r) => r._value > 23.2)

    View full-size slide

  51. // defining a pipe forwardable function
    square = (tables=<-) =>
    tables
    |> map(fn: (r) => {r with _value: r._value * r._value})
    from(bucket:"foo")
    |> range(start: -1h)
    |> filter(fn: (r) => r._measurement == "samples")
    |> square()
    |> filter(fn: (r) => r._value > 23.2)
    Calling the function

    View full-size slide

  52. Data Model & Working with
    Tables

    View full-size slide

  53. Example Series
    _measurement=mem,host=A,region=west,_field=free
    _measurement=mem,host=B,region=west,_field=free
    _measurement=cpu,host=A,region=west,_field=usage_system
    _measurement=cpu,host=A,region=west,_field=usage_user

    View full-size slide

  54. Example Series
    _measurement=mem,host=A,region=west,_field=free
    _measurement=mem,host=B,region=west,_field=free
    _measurement=cpu,host=A,region=west,_field=usage_system
    _measurement=cpu,host=A,region=west,_field=usage_user
    Measurement

    View full-size slide

  55. Example Series
    _measurement=mem,host=A,region=west,_field=free
    _measurement=mem,host=B,region=west,_field=free
    _measurement=cpu,host=A,region=west,_field=usage_system
    _measurement=cpu,host=A,region=west,_field=usage_user
    Field

    View full-size slide

  56. Table
    _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 10

    View full-size slide

  57. _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 10
    Column

    View full-size slide

  58. _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 10
    Record

    View full-size slide

  59. _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 10
    Group Key
    _measurement=mem,host=A,region=west,_field=free

    View full-size slide

  60. _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 10
    Every record has
    the same value!
    _measurement=mem,host=A,region=west,_field=free

    View full-size slide

  61. Table Per Series
    _measurement host region _field _time _value
    mem A west free 2018-06-14T09:15:00 10
    mem A west free 2018-06-14T09:14:50 11
    _measurement host region _field _time _value
    mem B west free 2018-06-14T09:15:00 20
    mem B west free 2018-06-14T09:14:50 22
    _measurement host region _field _time _value
    cpu A west usage_user 2018-06-14T09:15:00 45
    cpu A west usage_user 2018-06-14T09:14:50 49
    _measurement host region _field _time _value
    cpu A west usage_system 2018-06-14T09:15:00 35
    cpu A west usage_system 2018-06-14T09:14:50 38

    View full-size slide

  62. input tables -> function -> output tables

    View full-size slide

  63. input tables -> function -> output tables
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum()

    View full-size slide

  64. input tables -> function -> output tables
    What to sum on?
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum()

    View full-size slide

  65. input tables -> function -> output tables
    Default columns argument
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum(columns: [“_value”])

    View full-size slide

  66. input tables -> function -> output tables
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free 2018-06-
    14T09:1
    10
    mem A west free 2018-06-
    14T09:1
    11
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free 2018-06-
    14T09:15
    20
    mem B west free 2018-06-
    14T09:14
    22
    Input in table form
    // example query
    from(bucket:”telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum()

    View full-size slide

  67. input tables -> function -> output tables
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free 2018-06-
    14T09:1
    10
    mem A west free 2018-06-
    14T09:1
    11
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free 2018-06-
    14T09:15
    20
    mem B west free 2018-06-
    14T09:14
    22
    sum()
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum()

    View full-size slide

  68. input tables -> function -> output tables
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:50, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> sum()
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free 2018-06-
    14T09:1
    10
    mem A west free 2018-06-
    14T09:1
    11
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free 2018-06-
    14T09:15
    20
    mem B west free 2018-06-
    14T09:14
    22
    sum()
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free 2018-06-
    14T09:1
    21
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free 2018-06-
    14T09:15
    42

    View full-size slide

  69. N to N table mapping
    (1 to 1 mapping)

    View full-size slide

  70. N to M table mapping

    View full-size slide

  71. window
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s)
    30s of data (4 samples)

    View full-size slide

  72. window
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s)
    split into 20s windows

    View full-size slide

  73. window
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s)
    Input

    View full-size slide

  74. window
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    window(
    every:20s)
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s)

    View full-size slide

  75. window
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    window(
    every:20s)
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s) _meas
    ureme
    host region _field _time _valu
    e
    mem A west free …14:30 10
    mem A west free …14:40 11
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free …14:50 23
    mem B west free …15:00 24
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free …14:30 20
    mem B west free …14:40 22
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free …14:50 12
    mem A west free …15:00 13

    View full-size slide

  76. window
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    window(
    every:20s)
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> window(every:20s) _meas
    ureme
    host region _field _time _valu
    e
    mem A west free …14:30 10
    mem A west free …14:40 11
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free …14:50 23
    mem B west free …15:00 24
    _meas
    ureme
    host region _field _time _valu
    e
    mem B west free …14:30 20
    mem B west free …14:40 22
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free …14:50 12
    mem A west free …15:00 13
    N to M tables

    View full-size slide

  77. Window based on time
    _start and _stop columns

    View full-size slide

  78. group
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> group(keys:[“region"])

    View full-size slide

  79. group
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> group(keys:[“region"])
    new group key

    View full-size slide

  80. group
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> group(keys:[“region"])

    View full-size slide

  81. group
    _meas host region _field _time _valu
    mem A west free …14:30 10
    mem A west free …14:40 11
    mem A west free …14:50 12
    mem A west free …15:00 13
    _meas host region _field _time _valu
    mem B west free …14:30 20
    mem B west free …14:40 22
    mem B west free …14:50 23
    mem B west free …15:00 24
    group(
    keys:
    [“region”])
    // example query
    from(bucket:"telegraf")
    |> range(start:2018-06-14T09:14:30, stop:2018-06-14T09:15:01)
    |> filter(fn: r => r._measurement == “mem" and
    r._field == “free”)
    |> group(keys:[“region"])
    _meas
    ureme
    host region _field _time _valu
    e
    mem A west free …14:30 10
    mem B west free …14:30 20
    mem A west free …14:40 11
    mem B west free …14:40 21
    mem A west free …14:50 12
    mem B west free …14:50 22
    mem B west free …15:00 13
    mem B west free …15:00 23
    N to M tables
    M == cardinality(group keys)

    View full-size slide

  82. Group based on columns

    View full-size slide

  83. New Language?

    View full-size slide

  84. Domain Specific Languages

    View full-size slide

  85. Many Data Sources

    View full-size slide

  86. Optimize for each

    View full-size slide

  87. Cross compilation

    View full-size slide

  88. Distributed Engine

    View full-size slide

  89. Tables Everywhere

    View full-size slide

  90. from(bucket: "foo")
    |> range(start: -10m)
    |> filter(fn: (r) => r._measurement == "cpu")
    |> group(columns: ["_measurement"])
    |> sort(columns: ["_value"])
    Sorting by value!

    View full-size slide

  91. Group by anything

    View full-size slide

  92. Measurements, tags, fields
    don’t matter

    View full-size slide

  93. Beyond Queries

    View full-size slide

  94. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)

    View full-size slide

  95. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    tasks

    View full-size slide

  96. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    cron scheduling

    View full-size slide

  97. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    packages & imports

    View full-size slide

  98. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    String interpolation

    View full-size slide

  99. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    Ship data elsewhere

    View full-size slide

  100. option task = {
    name: "email alert digest",
    cron: "0 5 * * 0"
    }
    import "smtp"
    body = ""
    from(bucket: "alerts")
    |> range(start: -24h)
    |> filter(fn: (r) => (r.level == "warn" or r.level == "critical") and r._field == "message")
    |> group(columns: ["alert"])
    |> count()
    |> group()
    |> map(fn: (r) => body = body + "Alert {r.alert} triggered {r._value} times\n")
    smtp.to(
    config: loadSecret(name: "smtp_digest"),
    to: "[email protected]",
    title: "Alert digest for {now()}",
    body: message)
    Store secrets in a
    store like Vault

    View full-size slide

  101. Monitoring as Code

    View full-size slide

  102. • Finalizing Spec

    • Error Handling

    • Test Runner & CLI

    • User Packages

    • Flow Control (if/else)
    Status

    View full-size slide

  103. Status
    • Alpha 7 this week

    • API, Tasks, Dashboards

    • Client Libraries (soon)

    • Monitoring & Alerting (soon)

    View full-size slide

  104. https://influxdata.com/download

    2.0

    View full-size slide

  105. Thank you
    Paul Dix

    @pauldix

    paul@influxdata.com

    View full-size slide