Git Product home page Git Product logo

clickhouse-grafana's Introduction

Altinity Grafana datasource plugin for ClickHouse (grafana Grafana 4.6+ supported)

Altinity ClickHouse datasource plugin provides a support for ClickHouse as a backend database.

Initially plugin developed by Vertamedia, maintaned by Altinity since 2020.

Quick start

Grafana 10+ setup notes for plugin version before 3.0.0

Old versions of Altinity ClickHouse datasource plugin for Grafana written in Angular. So you can watch warning like

Angular plugin
This data source plugin uses a deprecated, legacy platform based on AngularJS and will stop working in future releases of Grafana.

Don't worry about warning message, plugin will still working until Grafana 11 will release, after it upgrade to Altinity ClickHouse datasource plugin for Grafana to 3.x version is required.

Grafana 7+ setup notes for plugin version before 2.2.0

When 2.0.x and 2.1.x vertamedia-clickhouse-grafana plugin versions released Grafana team didn't provide worked signing method for community plugins. Current sign process describe on grafana.com

so, for properly setup 2.0.x and 2.1.x plugins you need change configuration option

[plugins]
allow_loading_unsigned_plugins=vertamedia-clickhouse-datasource

or setup environment variable

GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=vertamedia-clickhouse-datasource

You can install plugin from grafana.com

OR

Copy files to your Grafana plugin directory. Restart Grafana, check data sources list at Configuration -> Datasources -> New, choose ClickHouse option.

Datasources Add new datasource Datasource types

Features

  • Access to CH via HTTP / HTTPS
  • Query setup
  • Raw SQL editor
  • Query formatting
  • Macros support
  • Additional functions
  • Templates
  • Table view
  • SingleStat view
  • Ad-hoc filters
  • Annotations
  • Alerts support
  • Logs support
  • Flamegraph support
  • Traces support

Access to ClickHouse via HTTP / HTTPS

Page configuration is standard

settings

There is a small feature - ClickHouse treats HTTP Basic Authentication credentials as a database user and will try to run queries using its name.

CHProxy (optional)

Using of CHProxy will bring additional features:

  • Easily setup HTTPS access to ClickHouse as shown here to provide secure access.
  • Limit concurrency and execution time for requests from Grafana as shown here to prevent ClickHouse overloading from Grafana.
  • Protection against request bursts for dashboards with numerous graphs. CHProxy allows queueing requests and execute them sequentially. To learn more - read about params max_queue_size and max_queue_time at CHProxy page.
  • Response caching for the most frequent queries as shown here.

Caching will protect ClickHouse from excessive refreshes and will be optimal option for popular dashboards.

Hint - if you need to cache requests like last 24h where timestamp changes constantly then try to use Round option at Raw Editor

Query setup

Query setup interface:

query editor image

First row FROM contains two options: database and table. Table values depends on a selected database. Next rows contains selectors for time filtering:

Column timestamp time

Timestamp column Date column

Timestmap column are required for time-based macros and functions because all analytics based on these values. Plugin will try to detect Date, Date32 column automatically

Button Go to Query is just a toggler to Raw SQL Editor

Raw SQL Editor

Raw Editor allows custom SQL queries to be written:

raw editor image

Raw Editor allows typing queries, get info about functions and macros, format queries as Clickhouse do. To Execute query on server press "Run Query" or just leave focus from SQL editor textarea.

Under the Editor you can find options which allows setup rounding, time column step and Add metadata to SQL query which allows know which dashboard and user produce workload to your ClickHouse server.

Press Show Generated SQL for see a raw query (all macros and functions have already been replaced) which will be sent directly to ClickHouse. generated sql

Macros support

Plugin supports the following marcos:

  • $table - replaced with selected table name from Query Builder
  • $dateCol - replaced with Column:Date value from Query Builder
  • $dateTimeCol - replaced with Column:DateTime or Column:TimeStamp value from Query Builder
  • $from - replaced with (timestamp with ms)/1000 value of UI selected "Time Range:From"
  • $to - replaced with (timestamp with ms)/1000 value of UI selected "Time Range:To"
  • $interval - replaced with selected "Group by a time interval" value (as a number of seconds)
  • $timeFilter - replaced with currently selected "Time Range". Requires Column:Date and Column:DateTime or Column:TimeStamp to be selected.
  • $timeFilterByColumn($column) - replaced with currently selected "Time Range" for a column passed as $column argument. Use it in queries or query variables as ...WHERE $timeFilterColumn($column)... or ...WHERE $timeFilterColumn(created_at)....
  • $timeSeries - replaced with special ClickHouse construction to convert results as time-series data. Use it as "SELECT $timeSeries...".
  • $naturalTimeSeries - replaced with special ClickHouse construction to convert results as time-series with in a logical/natural breakdown. Use it as "SELECT $naturalTimeSeries...".
  • $unescape - unescapes variable value by removing single quotes. Used for multiple-value string variables: "SELECT $unescape($column) FROM requests WHERE $unescape($column) = 5"
  • $adhoc - replaced with a rendered ad-hoc filter expression, or "1" if no ad-hoc filters exist. Since ad-hoc applies automatically only to outer queries the macros can be used for filtering in inner queries.

A description of macros is available by typing their names in Raw Editor

Functions

Functions are just templates of SQL queries, and you can check the final query at Raw SQL Editor mode. If you need some additional complexity - just copy raw sql into Raw Editor and make according changes. Remember that macros are still available to use.

There are some limits in function use because of poor query analysis:

  • Column:Date and Column:DateTime or Column:TimeStamp must be set in Query Builder
  • Query must begin from function name
  • Only one function can be used per query

Plugin supports the following functions:

$rate(cols...) - converts query results as "change rate per interval"

Example usage:

$rate(countIf(Type = 200) AS good, countIf(Type != 200) AS bad) FROM requests

Query will be transformed into:

SELECT
    t,
    good / runningDifference(t / 1000) AS goodRate,
    bad / runningDifference(t / 1000) AS badRate
FROM
(
    SELECT
        (intDiv(toUInt32(EventTime), 60)) * 1000 AS t,
        countIf(Type = 200) AS good,
        countIf(Type != 200) AS bad
    FROM requests
    WHERE ((EventDate >= toDate(1482796747)) AND (EventDate <= toDate(1482853383))) AND ((EventTime >= toDateTime(1482796747)) AND (EventTime <= toDateTime(1482853383)))
    GROUP BY t
    ORDER BY t
)

$columns(key, value) - query values as array of [key, value], where key will be used as label

Example usage:

$columns(OSName, count(*) c)
FROM requests
INNER JOIN oses USING (OS)

Query will be transformed into:

SELECT
    t,
    groupArray((OSName, c)) AS groupArr
FROM
(
    SELECT
        (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
        OSName,
        count(*) AS c
    FROM requests
    INNER JOIN oses USING (OS)
    WHERE ((EventDate >= toDate(1482796627)) AND (EventDate <= toDate(1482853383))) AND ((EventTime >= toDateTime(1482796627)) AND (EventTime <= toDateTime(1482853383)))
    GROUP BY
        t,
        OSName
    ORDER BY
        t,
        OSName
)
GROUP BY t
ORDER BY t

This will help to build the next graph:

req_by_os image


$rateColumns(key, value) - is a combination of $columns and $rate

Example usage:

$rateColumns(OS, count(*) c) FROM requests

Query will be transformed into:

SELECT
    t,
    arrayMap(lambda(tuple(a), (a.1, a.2 / runningDifference(t / 1000))), groupArr)
FROM
(
    SELECT
        t,
        groupArray((OS, c)) AS groupArr
    FROM
    (
        SELECT
            (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
            OS,
            count(*) AS c
        FROM requests
        WHERE ((EventDate >= toDate(1482796867)) AND (EventDate <= toDate(1482853383))) AND ((EventTime >= toDateTime(1482796867)) AND (EventTime <= toDateTime(1482853383)))
        GROUP BY
            t,
            OS
        ORDER BY
            t,
            OS
    )
    GROUP BY t
    ORDER BY t
)

$rateColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need calculate rate for higher cardinality dimension and then aggregate by lower cardinality dimension

Example usage:

$rateColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic

Query will be transformed into:

SELECT
    t,
    datacenter,
    sum(tx_kbytesRate) AS tx_bytesRateAgg,
    sum(rx_bytesRate) AS rx_bytesRateAgg
FROM
(
    SELECT
        t,
        datacenter,
        dc_interface,
        tx_kbytes / runningDifference(t / 1000) AS tx_kbytesRate,
        rx_bytes / runningDifference(t / 1000) AS rx_bytesRate
    FROM
    (
        SELECT
            (intDiv(toUInt32(event_time), 60) * 60) * 1000 AS t,
            datacenter,
            concat(datacenter,interface) AS dc_interface,
            max(tx_bytes * 1024) AS tx_kbytes,
            max(rx_bytes) AS rx_bytes
        FROM traffic
        WHERE ((event_date >= toDate(1482796867)) AND (event_date <= toDate(1482853383))) 
          AND ((event_time >= toDateTime(1482796867)) AND (event_time <= toDateTime(1482853383)))
        GROUP BY
            t,
            datacenter,
            dc_interface
        ORDER BY
            t,
            datacenter,
            dc_interface
    )
)
GROUP BY
  t,
  datacenter
ORDER BY 
  datacenter,
  t

look issue 386 for reasons for implementation


$perSecond(cols...) - converts query results as "change rate per interval" for Counter-like(growing only) metrics

Example usage:

$perSecond(Requests) FROM requests

Query will be transformed into:

SELECT
    t,
    if(runningDifference(max_0) < 0, nan, runningDifference(max_0) / runningDifference(t / 1000)) AS max_0_PerSecond
FROM
(
    SELECT
        (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
        max(Requests) AS max_0
    FROM requests
    WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
    AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
    GROUP BY t
    ORDER BY t
)

// see issue 78 for the background


$perSecondColumns(key, value) - is a combination of $columns and $perSecond for Counter-like metrics

Example usage:

$perSecondColumns(Protocol, Requests) FROM requests WHERE Protocol in ('udp','tcp')

Query will be transformed into:

SELECT
    t,
    groupArray((perSecondColumns, max_0_PerSecond)) AS groupArr
FROM
(
    SELECT
        t,
        Protocol,
        if(runningDifference(max_0) < 0 OR neighbor(perSecondColumns,-1,perSecondColumns) != perSecondColumns, nan, runningDifference(max_0) / runningDifference(t / 1000)) AS max_0_PerSecond
    FROM
    (
        SELECT
            (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
            Protocol AS perSecondColumns,
            max(Requests) AS max_0
        FROM requests
        WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
        AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
        AND (Protocol IN ('udp', 'tcp'))
        GROUP BY
            t,
            Protocol
        ORDER BY
            t,
            Protocol
    )
)
GROUP BY t
ORDER BY t

// see issue 80 for the background


$perSecondColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need to calculate perSecond for higher cardinality dimension and then aggregate by lower cardinality dimension

Example usage:

$perSecondColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic

Query will be transformed into:

SELECT
    t,
    datacenter,
    sum(tx_kbytesPerSecond) AS tx_bytesPerSecondAgg,
    sum(rx_bytesPerSecond) AS rx_bytesPerSecondAgg
FROM
(
    SELECT
        t,
        datacenter,
        dc_interface,
        if(runningDifference(tx_kbytes) < 0 OR neighbor(tx_kbytes,-1,tx_kbytes) != tx_kbytes, nan, runningDifference(tx_kbytes) / runningDifference(t / 1000)) AS tx_kbytesPerSecond,
        if(runningDifference(rx_bytes) < 0 OR neighbor(rx_bytes,-1,rx_bytes) != rx_bytes, nan, runningDifference(rx_bytes) / runningDifference(t / 1000)) AS rx_bytesPerSecond
    FROM
    (
        SELECT
            (intDiv(toUInt32(event_time), 60) * 60) * 1000 AS t,
            datacenter,
            concat(datacenter,interface) AS dc_interface,
            max(tx_bytes * 1024) AS tx_kbytes,
            max(rx_bytes) AS rx_bytes
        FROM traffic
        WHERE ((event_date >= toDate(1482796867)) AND (event_date <= toDate(1482853383))) 
          AND ((event_time >= toDateTime(1482796867)) AND (event_time <= toDateTime(1482853383)))
        GROUP BY
            t,
            datacenter,
            dc_interface
        ORDER BY
            t,
            datacenter,
            dc_interface
    )
)
GROUP BY
  t,
  datacenter
ORDER BY 
  datacenter,
  t

look issue 386 for reasons for implementation


$delta(cols...) - converts query results as "delta value inside interval" for Counter-like(growing only) metrics, will negative if counter reset

Example usage:

$delta(Requests) FROM requests

Query will be transformed into:

SELECT
    t,
    runningDifference(max_0) AS max_0_Delta
FROM
(
    SELECT
        (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
        max(Requests) AS max_0
    FROM requests
    WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
    AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
    GROUP BY t
    ORDER BY t
)

// see issue 455 for the background


$deltaColumns(key, value) - is a combination of $columns and $delta for Counter-like metrics

Example usage:

$deltaColumns(Protocol, Requests) FROM requests WHERE Protocol in ('udp','tcp')

Query will be transformed into:

SELECT
    t,
    groupArray((deltaColumns, max_0_Delta)) AS groupArr
FROM
(
    SELECT
        t,
        deltaColumns,
        if (neighbor(deltaColumns,-1,deltaColumns) != deltaColumns, 0, runningDifference(max_0)) AS max_0_Delta
    FROM
    (
        SELECT
            (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
            Protocol AS deltaColumns,
            max(Requests) AS max_0
        FROM requests
        WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
        AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
        AND (Protocol IN ('udp', 'tcp'))
        GROUP BY
            t,
            Protocol
        ORDER BY
            t,
            Protocol
    )
)
GROUP BY t
ORDER BY t

// see issue 455 for the background


$deltaColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need to calculate delta for higher cardinality dimension and then aggregate by lower cardinality dimension

Example usage:

$deltaColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic

Query will be transformed into:

SELECT
    t,
    datacenter,
    sum(tx_kbytesDelta) AS tx_bytesDeltaAgg,
    sum(rx_bytesDelta) AS rx_bytesDeltaAgg
FROM
(
    SELECT
        t,
        datacenter,
        dc_interface,
        if(neighbor(tx_kbytes,-1,tx_kbytes) != tx_kbytes, 0, runningDifference(tx_kbytes) / 1) AS tx_kbytesDelta,
        if(neighbor(rx_bytes,-1,rx_bytes) != rx_bytes, 0, runningDifference(rx_bytes) / 1) AS rx_bytesDelta
    FROM
    (
        SELECT
            (intDiv(toUInt32(event_time), 60) * 60) * 1000 AS t,
            datacenter,
            concat(datacenter,interface) AS dc_interface,
            max(tx_bytes * 1024) AS tx_kbytes,
            max(rx_bytes) AS rx_bytes
        FROM traffic
        WHERE ((event_date >= toDate(1482796867)) AND (event_date <= toDate(1482853383))) 
          AND ((event_time >= toDateTime(1482796867)) AND (event_time <= toDateTime(1482853383)))
        GROUP BY
            t,
            datacenter,
            dc_interface
        ORDER BY
            t,
            datacenter,
            dc_interface
    )
)
GROUP BY
  t,
  datacenter
ORDER BY 
  datacenter,
  t

look issue 386 for reasons for implementation


$increase(cols...) - converts query results as "non-negative delta value inside interval" for Counter-like(growing only) metrics, will zero if counter reset and delta less zero

Example usage:

$increase(Requests) FROM requests

Query will be transformed into:

SELECT
    t,
    if(runningDifference(max_0) < 0, 0, runningDifference(max_0) ) AS max_0_Increase
FROM
(
    SELECT
        (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
        max(Requests) AS max_0
    FROM requests
    WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
    AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
    GROUP BY t
    ORDER BY t
)

// see issue 455 for the background


$increaseColumns(key, value) - is a combination of $columns and $increase for Counter-like metrics

Example usage:

$increaseColumns(Protocol, Requests) FROM requests WHERE Protocol in ('udp','tcp')

Query will be transformed into:

SELECT
    t,
    groupArray((increaseColumns, max_0_Increase)) AS groupArr
FROM
(
    SELECT
        t,
        Protocol,
        if (runningDifference(max_0) < 0 OR neighbor(increaseColumns,-1,increaseColumns) != increaseColumns, 0, runningDifference(max_0)) AS max_0_Increase
    FROM
    (
        SELECT
            (intDiv(toUInt32(EventTime), 60) * 60) * 1000 AS t,
            Protocol AS increaseColumns,
            max(Requests) AS max_0
        FROM requests
        WHERE ((EventDate >= toDate(1535711819)) AND (EventDate <= toDate(1535714715)))
        AND ((EventTime >= toDateTime(1535711819)) AND (EventTime <= toDateTime(1535714715)))
        AND (Protocol IN ('udp', 'tcp'))
        GROUP BY
            t,
            Protocol
        ORDER BY
            t,
            Protocol
    )
)
GROUP BY t
ORDER BY t

// see issue 455 for the background


$increaseColumnsAggregated(key, subkey, aggFunction1, value1, ... aggFunctionN, valueN) - if you need to calculate increase for higher cardinality dimension and then aggregate by lower cardinality dimension

Example usage:

$increaseColumnsAggregated(datacenter, concat(datacenter,interface) AS dc_interface, sum, tx_bytes * 1014 AS tx_kbytes, sum, max(rx_bytes) AS rx_bytes) FROM traffic

Query will be transformed into:

SELECT
    t,
    datacenter,
    sum(tx_kbytesIncrease) AS tx_bytesIncreaseAgg,
    sum(rx_bytesIncrease) AS rx_bytesIncreaseAgg
FROM
(
    SELECT
        t,
        datacenter,
        dc_interface,
        if(runningDifference(tx_kbytes) < 0 OR neighbor(tx_kbytes,-1,tx_kbytes) != tx_kbytes, nan, runningDifference(tx_kbytes) / 1) AS tx_kbytesIncrease,
        if(runningDifference(rx_bytes) < 0 OR neighbor(rx_bytes,-1,rx_bytes) != rx_bytes, nan, runningDifference(rx_bytes) / 1) AS rx_bytesIncrease
    FROM
    (
        SELECT
            (intDiv(toUInt32(event_time), 60) * 60) * 1000 AS t,
            datacenter,
            concat(datacenter,interface) AS dc_interface,
            max(tx_bytes * 1024) AS tx_kbytes,
            max(rx_bytes) AS rx_bytes
        FROM traffic
        WHERE ((event_date >= toDate(1482796867)) AND (event_date <= toDate(1482853383))) 
          AND ((event_time >= toDateTime(1482796867)) AND (event_time <= toDateTime(1482853383)))
        GROUP BY
            t,
            datacenter,
            dc_interface
        ORDER BY
            t,
            datacenter,
            dc_interface
    )
)
GROUP BY
  t,
  datacenter
ORDER BY 
  datacenter,
  t

look issue 386 for reasons for implementation


Templating

Query Variable

If you add a template variable of the type Query, you can write a ClickHouse query that can return things like measurement names, key names or key values that are shown as a dropdown select box.

For example, you can have a variable that contains all values for the hostname column in a table if you specify a query like this in the templating variable Query setting.

SELECT hostname FROM host

To use time range dependent macros like timeFilterByColumn($column) in your query the refresh mode of the template variable needs to be set to On Time Range Change.

SELECT event_name FROM event_log WHERE $timeFilterByColumn(time_column)

Another option is a query that can create a key/value variable. The query should return two columns that are named __text and __value. The __text column value should be unique (if it is not unique then the first value will use). The options in the dropdown will have a text and value that allows you to have a friendly name as text and an id as the value. An example query with hostname as the text and id as the value:

SELECT hostname AS __text, id AS __value FROM host

You can also create nested variables. For example if you had another variable named region. Then you could have the hosts variable only show hosts from the current selected region with a query like this (if region is a multi-value variable then use the IN comparison operator rather than = to match against multiple values):

SELECT hostname FROM host WHERE region IN ($region)

Conditional Predicate

If you are using templating to feed your predicate, you will face performance degradation when everything will select as the predicate, and it's not necessary. It's also true for textbox when nothing is entered, you have to write specific sql code to handle that.

To resolve this issue a new macro $conditionalTest(SQL Predicate,$variable) can be used to remove some part of the query. If the variable is type query with all selected or if the variable is a textbox with nothing enter, then the SQL Predicate is not include in the generated query.

To give an example: with 2 variables $var query with include All option $text textbox $text_with_single_quote textbox with single quote

The following query

 SELECT
   $timeSeries as t,
   count()
   FROM $table
   WHERE $timeFilter
    $conditionalTest(AND toLowerCase(column) in ($var),$var)
    $conditionalTest(AND toLowerCase(column2) like '%$text%',$text)
    $conditionalTest(AND toLowerCase(column3) ilike ${text_with_single_quote:sqlstring},$text_with_single_quote)
   GROUP BY t
   ORDER BY t

if the $var is selected as "All" value, and the $text variable is empty, the query will be converted into:

  SELECT
    $timeSeries as t,
    count()
     FROM $table
     WHERE $timeFilter
   GROUP BY t
   ORDER BY t

If the $var template variable have select some elements, and the $text template variable has at least one char, the query will be converted into:

SELECT
    $timeSeries as t,
    count()
     FROM $table
     WHERE $timeFilter
   AND toLowerCase(column) in ($var)
   AND toLowerCase(column2) like '%$text%'
   GROUP BY t
   ORDER BY t

Working with panels

Remember that pie chart plugin is not welcome for using in grafana - see Grafana BLog - Friends don't let friends abuse pie charts

top users

To create "Top 5" diagram we will need two queries: one for 'Top 5' rows and one for 'Other' row.

Top5:

SELECT
    1 AS t, /* fake timestamp value */
    UserName,
    sum(Requests) AS Reqs
FROM requests
GROUP BY t, UserName
ORDER BY Reqs DESC
LIMIT 5

Other:

SELECT
    1 AS t, /* fake timestamp value */
    UserName,
    sum(Requests) AS Reqs
FROM requests
GROUP BY t, UserName
ORDER BY Reqs DESC
LIMIT 5,10000000000000 /* select some ridiculous number after first 5 */

There are don't contain any tricks in displaying time-series data. To print summary data, omit time column, and format the result as "Table" and press "Run query".

SELECT
    UserName,
    sum(Requests) as Reqs
FROM requests
GROUP BY
    UserName
ORDER BY
    Reqs

table view

vertical histogram

To make the vertical histogram from graph panel we will need to edit some settings:

  • Display -> Draw Modes -> Bars
  • Axes -> X-Axis -> Mode -> Series

You can use next query:

$columns(
    Size,
    sum(Items) Items)
FROM some_table

// It is also possible to use query without macros

worldmap

If you have a table with country/city codes:

SELECT
    1,
    Country AS c,
    sum(Requests) AS Reqs
FROM requests
GLOBAL ANY INNER JOIN
(
    SELECT Country, CountryCode
    FROM countries
) USING (CountryCode)
WHERE $timeFilter
GROUP BY
    c
ORDER BY Reqs DESC

If you are using geohash set following options:

Format

You can make following query with Table formatting:

geohash-query

Ad-hoc filters

If there is an Ad-hoc variable, plugin will fetch all columns of all tables of all databases (except system database) as tags. So in dropdown menu will be options like database.table.column. If you specify the default database it will only fetch tables and columns from that database, and the dropdown menu will have an option like table.column. If there are ENUM columns, the plugin will fetch their options and use them as tag values. Also, plugin will fetch 300 unique values for fields with other types.

Plugin will apply Ad-hoc filters to all queries on the dashboard if their settings $database and $table are the same as database.table specified in Ad-hoc control. If the ad-hoc filter doesn't specify a table, it will apply to all queries regardless of the table. This is useful if the dashboard contains queries to multiple different tables.

ad-hoc

There are no option to apply OR operator for multiple Ad-hoc filters - see grafana/grafana#10918 There are no option to use IN operator for Ad-hoc filters due to Grafana limitations

There may be cases when CH contains too many tables and columns so their fetching could take notably amount of time. So, if you need to have multiple dashboards with different databases using of default database won't help. The best way to solve this will be to have parametrized ad-hoc variable in dashboard settings. Currently, it's not supported by Grafana interface (see issue). As a temporary workaround, plugin will try to look for variable with name adhoc_query_filter and if it exists will use its value as query to fetch columns. For this purpose we recommend creating some variable constant with the name adhoc_query_filter and set the value similar to the following one:

SELECT database, table, name, type FROM system.columns WHERE table='myTable' ORDER BY database, table

That should help to control data fetching by ad-hoc queries.

Template variable values via Query

To use time range dependent macros like $from and $to in your query the refresh mode of the template variable needs to be set to On Time Range Change.

SELECT ClientID FROM events WHERE EventTime > toDateTime($from) AND EventTime < toDateTime($to)

Annotations

Plugin support Annotations with regions. To enable this feature open Dashboard settings and add new annotation query with clickhouse datasource with properly field names.

Annotation query add

Annotation query example

Annotation with regions graph panel

Alerts support

Grafana provide two kind of alerts. Unified alerts and graph panel related alerts (legacy). Both kind of alerts supports by our plugin can't be used together. Use GF_UNIFIED_ALERTING_ENABLED=1 (preferable) or GF_ALERTING_ENABLED=1 environment variables for switch.

Panel related alerts (legacy)

To enable alerts open "alerts" tab in panel, and define alert expression as described on grafana.com

Alerts in graph panel

Be careful with Template variables values, currently grafana doesn't support template variables in alert queries itself. Also, grafana UI doesn't pass template variables values to a backend, after you change it on frontend UI.

So, the clickhouse grafana plugin can use template variables values, because we have "Generated SQL" which pass to backend "as is" To ensure template variables values will properly pass to a backend part of the plugin. Please choose the required template variables values for your alerts in UI dropdown, ensure values properly rendered in "Generated SQL" (maybe need change SQL queries in query editor) and save a whole dashboard to the Grafana server

WARNING: Test alert button doesn't save a current state of alert rules to a backend part of the plugin.

If the "Generated SQL" properly passed into backend part of plugin, you will see something like this: Graph panel with alerts

Unified Alerts support

Unified alerts could be provisioned with YAML file, look to https://github.com/Altinity/clickhouse-grafana/tree/master/docker/grafana/provisioning/alerting/

Unified alerts menu

Unified alerts panel

To export exists unified alerts to YAML use Export alerts

Unified alerts export

Alerts troubleshooting

To troubleshoot alerts in clickhouse grafana plugin when enable level=debug in log section grafana.ini or via GF_LOG_LEVEL=debug environment variable.

Logs support

To render your ClickHouse data as Logs, please use special format in "Format as" dropdown in Query Editor called "Logs". This option helps Grafana recognizes data as logs and shows logs visualization automatically in Explore UI. On dashboards you can use Logs panel as well.

Format as Logs

To return suitable for logs data - query should return at least one time field (assumed that it will be first field) and one text field from the ClickHouse.

Plugin is also transforming all text fields, except log line, into the labels using following rules:

  • Log line will be taken either from dedicated content field or from first in order text field in result
  • All other text fields will be treated as a labels

There are few dedicated fields that are recognized by Grafana:

  • level (string) - set the level for each log line
  • id (string) - by default, Grafana offers basic support for deduplicating log lines, that can be improved by adding this field to explicitly assign identifiers to each log line

All other fields returned from data source will be recognized by Grafana as detected fields

Flamegraph support

Format as: Flamegraph

To show Traces you need query in format as "Flame Graph" According to https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/flame-graph/#data-api, you need to have recordset with 4 fields

  • level - Numeric - the level of the stack frame. The root frame is level 0.
  • label - String - the function name or other symbol which identify
  • value - Numeric - the number of samples or bytes that were recorded in this stack trace
  • self - Numeric - the number of samples or bytes that were recorded in only this stack frame excluding the children, for clickhouse this is usually zero cause we can't calculate)

Moreover, rows shall be ordered by stack trace and level

If you setup query_profiler_real_time_period_ns in profile or query level settings when you can try to visualize it as FlameGraph with the following query
Look to system.trace_log table description for how to get data for FlameGraph Look to flamegraph dashboard example for example of dashboard with FlameGraph

Flamegraph query example:

SELECT length(trace)  - level_num AS level, label, count() AS value, 0 self
FROM system.trace_log
  ARRAY JOIN arrayEnumerate(trace) AS level_num,
  arrayMap(x -> if(addressToSymbol(x) != '', demangle(addressToSymbol(x)), 'unknown') , trace) AS label
WHERE trace_type='Real' AND $timeFilter
GROUP BY level, label, trace
ORDER BY trace, level

Traces support

To show Traces you need query with format as "Traces" with following Format as Traces

Trace example

For example, if <opentelemetry_start_trace_probability>1</opentelemetry_start_trace_probability> in user profile and system.opentelemetry_span_log is not emtpy, then you can show traces about clickhouse query execution Look to system.opentelemetry_span_log table description for how to get data for FlameGraph Look to tracing dashboard example for example of dashboard with FlameGraph

Tracing visualization requires following field names (case sensitive):

  • traceID - String
  • spanID - String
  • operationName - String
  • parentSpanID - String
  • serviceName - String
  • duration - UInt64 - duration in milliseconds
  • startTime - UInt64 - start time in milliseconds
  • tags - map(String, String) - tags for span
  • serviceTags - map(String, String) - tags for service (for example 'hostName')

Traces query example for system.opentelemetry_span_log

SELECT
  trace_id AS traceID,
  span_id AS spanID,
  operation_name AS operationName,
  parent_span_id AS parentSpanID,
  'clickhouse' AS serviceName,
  intDiv(finish_time_us - start_time_us, 1000) AS duration,
  intDiv(start_time_us,1000) AS startTime,
  attribute AS tags,
  map('hostName',hostname) AS serviceTags
FROM
  system.opentelemetry_span_log
WHERE $timeFilter
ORDER BY traceID, startTime

Configure the Datasource with Provisioning

It’s now possible to configure datasources using config files with Grafana’s provisioning system. You can read more about how it works and all the settings you can set for datasources on the provisioning docs page.

Here are some provisioning example:

apiVersion: 1

datasources:
 - name: Clickhouse
   type: vertamedia-clickhouse-datasource
   access: proxy
   url: http://localhost:8123
   # <bool> enable/disable basic auth
   basicAuth: false
   # <string> basic auth username
   basicAuthUser: "default"
   # <bool> enable/disable with credentials headers
   withCredentials: false
   # <bool> mark as default datasource. Max one per org
   isDefault: false
   # <map> fields that will be converted to json and stored in json_data
   jsonData:
     # <bool> enable/disable sending 'add_http_cors_header=1' parameter
     addCorsHeader: false
     # <bool> enable/disable using POST method for sending queries
     usePOST: false
     # <bool> enable/disable using Accept-Encoding header in each request
     useCompression: false
     # <string> compression type allowed values: gzip, zstd, br, deflate
     compressionType: ""
     # <string> default database name
     defaultDatabase: ""
     # <bool> enable/disable tls authorization
     tlsAuth: false
     # <bool> enable/disable tls authorization with custom ca
     tlsAuthWithCACert: false
     # <bool> enable/disable authorization with X-ClickHouse-* headers
     useYandexCloudAuthorization: false
     # <string> X-ClickHouse-Key header value for authorization
     xHeaderUser: ""
     # <string> the same value as url when `useYandexCloudAuthorization: true` 
     # @todo remove this workaround when merge https://github.com/grafana/grafana/pull/80858
     dataSourceUrl: "http://localhost:8123"
   secureJsonData:
     # <string> X-ClickHouse-User header value for authorization
     xHeaderKey: ""
     # <string> basic auth password
     basicAuthPassword: ""
     # <string> custom certificate authority for TLS https connection, base64 encoded 
     tlsCACert: ""
     # <string> custom client certificate for TLS https connection, base64 encoded 
     tlsClientCert: ""
     # <string> custom client secret key for TLS https connection, base64 encoded 
     tlsClientKey: ""

Some settings and security params are the same for all datasources. You can find them here.

FAQ

Why time series last point is not the real last point?

Plugin extrapolates last datapoint if time range is last N to avoid displaying of constantly decreasing graphs when timestamp in a table is rounded to minute or bigger. If it so then in 99% cases last datapoint will be much less than previous one, because last minute is not finished yet. That's why plugin checks prev datapoints and tries to predict last datapoint value just as it was already written into db. This behavior could be turned off via "Extrapolation" checkbox in query editor.

Which table schema used in SQL query examples?

All examples in this plugin use following table schema:

CREATE TABLE IF NOT EXISTS countries(
    Country LowCardinality(String),
    CountryCode LowCardinality(String)
) ENGINE MergeTree()
ORDER BY (CountryCode, Country);

CREATE TABLE IF NOT EXISTS oses (
    OSName LowCardinality(String),
    OS LowCardinality(String)
) ENGINE MergeTree()
ORDER BY (OS);

CREATE TABLE IF NOT EXISTS requests(
    EventTime DateTime,
    EventDate Date,
    Protocol LowCardinality(String),
    UserName LowCardinality(String),
    OS LowCardinality(String),
    CountryCode LowCardinality(String),
    Type UInt8,
    Requests UInt32
) ENGINE=MergeTree()
ORDER BY (EventDate, EventTime, Type, OS, Protocol, UserName)
PARTITION BY toYYYYMM(EventDate);

What about alerts support?

Alerts feature requires changes in Grafana's backend, which can be extended only for Grafana 6.5+. Grafana's maintainers are working on this feature. Current alerts support for clickhouse-grafana datasource plugin in beta.

For clickhouse grafana plugin 2.2.3+ support only for amd64 architecture for Linux, macOS, Windows and arm64 Linux, macOS (m1). Only amd64 prior 2.2.3 version.

Contributing

If you have any idea for an improvement or found a bug do not hesitate to open an issue or submit a pull request. We will appreciate any help from the community which will make working with such amazing products as ClickHouse and Grafana more convenient.

Development

see CONTRIBUTING.md for Development and Pull request Contributing instructions

License


MIT License, please see LICENSE for details.

clickhouse-grafana's People

Contributors

alex-zaitsev avatar amonakhov avatar atsirin avatar bmanth60 avatar carlanton avatar delphid avatar dependabot[bot] avatar dfulachier avatar dschaller avatar fgbogdan avatar fiery-fenix avatar gimm3fuel avatar hagen1778 avatar it1804 avatar lunaticusgreen avatar negasus avatar nikolina697 avatar nvartolomei avatar pierrenowak avatar sbengo avatar shankerwangmiao avatar simpod avatar slach avatar stephan-hof avatar th-ha avatar valyala avatar vavrusa avatar vbichov avatar wych42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clickhouse-grafana's Issues

Problem with symbols encoding

Im trying to make a simple query:

SELECT
    $timeSeries as t,
    avg(response_time)
FROM logs.nginx
GROUP BY t
WHERE $timeFilter

This transformed into:

SELECT (intDiv(toUInt32(time_iso), 5) * 5) * 1000 as t, avg(response_time) FROM logs.nginx GROUP BY t WHERE log_date >= toDate(1501751601) AND time_iso >= toDateTime(1501751601)

And I got an error:

Code: 62, e.displayText() = DB::Exception: Syntax error: failed at position 120: WHERE log_date &gt;= toDate(1501751601) AND time_iso &gt;= toDateTime(1501751601) FORMAT JSON, expected end of query, e.what() = DB::Exception&#10;

In tabix.io this query is OK

Where is SQL Query Editor?

Hello guys,

We installed Grafana and your plugin. We can successfully create a data source, but can't find the query editor. Any suggestions?

Wrong $timeFilter expansion

When grafana time selector is set for example to 'Yesterday' (2017-11-18 00:00:00 to 2017-11-18 23:59:59), 'WHERE $timeFilter' is expanded to:

WHERE event_date BETWEEN toDate(1510963200) AND toDate(1511049600) AND event_time BETWEEN toDateTime(1510963200) AND toDateTime(1511049600)

so event_date will be from 18-11-2017 to 19-11-2017 and event_time will be from 18-11-2017 00:00:00 to 19-11-2017 00:00:00 inclusive.

The right part of the time expression should be either exclusive or value of timestamp decreased by 1 second.

Matching the alias prefix with the keyword "format"

I have a request

SELECT
    $timeSeries as t,
    count() as formatt
FROM $table
WHERE $timeFilter
GROUP BY t
ORDER BY t

Translated to

SELECT     (intDiv(toUInt32(dateTime), 600) * 600) * 1000 as t,     count() as FROM Table WHERE date >= toDate(1521110168) AND dateTime >= toDateTime(1521110168) GROUP BY t ORDER BY t FORMAT t

Allow to use variables as column names

Hello,

I have a table with number of columns of similar meaning (for example, count of errors by types, where each column represent certain error type).
Example:

┌───────date─┬────────────datetime─┬────metric1─┬────metric2─┬────metric3─┐
│ 2018-03-06 │ 2018-03-06 10:20:11 │ 3731493556 │ 3731493556 │ 3731493556 │
│ 2018-03-06 │ 2018-03-06 10:20:12 │  273977558 │  273977558 │  273977558 │
│ 2018-03-06 │ 2018-03-06 10:20:13 │ 4026407843 │ 4026407843 │ 4026407843 │
└────────────┴─────────────────────┴────────────┴────────────┴────────────┘

I want to place graphs based on data from all of these columns on single dashboard without hard-coding column names. As a result, if any column is added or removed, dashboard is rebuild automatically.
By default, datasource (or grafana itself, I don't remember exactly whose behavior it is) adds quotes to variable value if 'Multi-value' or 'Include All option' is used, so you cannot do something like SELECT $metric FROM table_name since SELECT 'metric1' FROM table_name will actually be executed.

For datasource v0.1 I hackishly implemented my own function $getColumnNameFromString, which simply removed all quotes from given variable, and used it like this:
select $timeSeries, $getColumnNameFromString($metric) from stats_table where $timeFilter for graphs repeated by $metric.

I would greatly appreciate if you could provide similar functionality (hopefully, in more convenient way than I have described).

Missing files

Hi, it seems you forgot to push sql_series.ts and the repo only contains generated .js and .d.js files.

Choose table Bug

before I choose a database and a table, it auto jumps to the demo sql.

Worldmap Panel Issue

Hi, I have a click house table with the following schema:
UserID UInt32 lat Float64 lon Float64 city String country String countryCode String day Date DateTimeValue DateTime

Data Sample:
screen shot 2018-04-30 at 12 13 26

I will like to set WorldMap based on countryCode field.

So I did this:

screen shot 2018-04-30 at 12 09 10

I am getting the following answer in the Query Inspector:
screen shot 2018-04-30 at 12 54 11

{ "xhrStatus": "complete", "request": { "method": "GET", "url": "api/datasources/proxy/1/?query=select%20countryCode%2C%20%20count(*)%20%20from%20rizk.userlogin%20%20where%20day%20%3E%3D%20toDate(1525085178)%20AND%20DateTimeValue%20%3E%3D%20toDateTime(1525085178)%20group%20by%20countryCode%20%20%20FORMAT%20JSON" }, "response": { "meta": [ { "name": "countryCode", "type": "String" }, { "name": "count()", "type": "UInt64" } ], "data": [ { "countryCode": "GB", "count()": "5" }, { "countryCode": "NO", "count()": "13" }, { "countryCode": "NL", "count()": "8" }, { "countryCode": "AT", "count()": "1" }, { "countryCode": "DE", "count()": "17" }, { "countryCode": "FI", "count()": "27" }, { "countryCode": "SE", "count()": "15" }, { "countryCode": "NZ", "count()": "2" } ], "rows": 8, "statistics": { "elapsed": 0.001184305, "rows_read": 11146, "bytes_read": 137586 } } }

But as you can see the point are not displayed on the map.

template issue

Aleksey Shirokikh, [23.11.17 20:28]
@alexanderzobnin а можно в шаблонизатор графаны подставить такое вот
select
dictGetString('managedobject', 'name', managed_object) AS text,
managed_object as value
from
noc.subscriber
group by managed_object

Aleksey Shirokikh, [23.11.17 20:28]
я хочу выбирать красивое имя а в квери подставлять то чо надо

Aleksey Shirokikh, [23.11.17 20:29]
это запрос в кх

Alexander Zobnin, [23.11.17 20:29]
это SQL датасорс?

Aleksey Shirokikh, [23.11.17 20:30]
нет это vertamedia/ch

Aleksey Shirokikh, [23.11.17 20:33]
сейчас возвращается оба результата

Aleksey Shirokikh, [23.11.17 20:33]
что очевидно не помогает

Aleksey Shirokikh, [23.11.17 20:33]
и я смотрю на
https://github.com/Vertamedia/clickhouse-grafana/blob/5e8adabfb6c9e396f08c638d44cbb8306ef3df60/specs/lib/template_srv_stub.ts
и будто бы да

Alexander Zobnin, [23.11.17 20:34]
Видимо, нет, посмотрел в их код, они возвращают { text: value}

Aleksey Shirokikh, [23.11.17 20:34]
а как надо что бы да ?

Alexander Zobnin, [23.11.17 20:41]
Чтобы {text: myText, value: myValue}

Alexander Zobnin, [23.11.17 20:42]
Как здесь https://github.com/grafana/grafana/blob/master/public/app/plugins/datasource/postgres/response_parser.ts#L62

Time series last point is not the real last point

Hello
I've seen some weird behavior using clickhouse-grafana data source, it gets the last point from backend correctly, but it shows another value on the graph. But for other points it's showing the correct value. And this patterns is repeated for every last point.
Here are the screenshots
rsz_screenshot_from_2018-03-04_16-51-53
rsz_1screenshot_from_2018-03-04_16-40-00
rsz_screenshot_from_2018-03-04_16-33-31

[Bug] Incorrent works with multiple vars

$KPI = some_kpi_name
$d_kpi = _d
$n_kpi = _n

This example works ok:
SELECT $timeSeries as t, ($KPI$d_kpi/$KPI$n_kpi)*100 FROM $table WHERE $timeFilter and ucell_oid = $ucell_oid ORDER BY t

this is not:

$rateColumns(
    net_oid AS nets, 
     (SUM($KPI$n_kpi)/SUM($KPI$d_kpi))*100 c)
FROM $table  
ALL  INNER JOIN obj_ucell USING ucell_oid

After transform i get space between $KPI and $d_kpi

[question]: есть ли возможность получить из одной "Metrics" несколько линий графика (series)?

Пробовал задать Templating/Variables, но это получилось использовать только как sql-фильтр вроде
... and('All' in ($geo_country) or geo_country in ($geo_country)) ...

PS: в плагине grafana-zabbix, например, возможность множить линии графика была.

adhoc filters

Hello,
is it possible to add AdHoc filters similar to InfluxDB plugin?

Regards,
Vladimir

Add interval to $timeFilter

Macro $timeFilter generates something like

time_date BETWEEN toDate(1524736800) AND toDate(1524823200)
AND time BETWEEN toDateTime(1524736800) AND toDateTime(1524823200)

I need to make a comparison between values from last week (-7 days against now)

The way I plan to approach is to make a SELECT for NOW and then join the same SELECT with timeFilter shifted by 7 days back. Is there a way to nicely shift $timeFilter by interval?

Or do I have to type something like

$timeCol BETWEEN toDate($from - 604800) AND toDate($to - 604800)
AND $dateTimeCol BETWEEN toDateTime($from - 604800) AND toDateTime($to - 604800)

Thanks

Support extra filtering query

I think it's easier to explain what I mean by example.

We are trying to store graphite data in clickhouse, but because if clickhouse's nature we need to construct our queries in something like that:

SELECT Path, Value, Time from graphite where Path IN ('path1', 'path2', 'path3')

Those 'path1', 'path2' stored in clickhouse in another table.

What we do now:
select groupUniqArray(Path) from graphite_tree where Path like 'path%'

and then use the results in an 'IN' clause.

With current grafana clickhouse plugin I was unable to find a way to get data and then reuse it in another query.

Minimum step

There should be an additional "Minimum step" field that sets a lower bound for the auto interval/step.

Depending on timestamp precision, it can be necessary to specify a minimum step - there's no point in doing per-second aggregates when the precision of the underlying data is a multiple of that.

When using $columns with JOIN getting Code: 62, e.displayText() = DB::Exception: Syntax error

I have tried the query from #33 (comment)

$columns(
    concat(toString(myid), '-','x') l,
    count(*) c)
FROM $table
ANY INNER JOIN mysecondtable USING myid

However I'm getting error

Code: 62, e.displayText() = DB::Exception: Syntax error: failed at position 1: $columns( concat(toString(myid), '-', 'test') l, count(*) c) FROM mytable ANY INNER JOIN mysecondtable USING myid FORMAT JSON. Unrecognized token, e.what() = DB::Exception

It seems like the plugin didn't transform it into query for some reason. Using v1.3.1. Thanks for help!

When I do this, it works

$columns(
    concat(toString(myid), '-','x') l,
    count(*) c)
FROM $table

$columns support multiple columns

The doc has shown an example of $columns:

$columns(OSName, count(*) c) FROM requests

Sometimes, I need to group multi columns to find out differences, such as OS platform and version, I 'm wondering if this usage could be supported:

$columns(key_1, key_2, value) or $columns((key_1, key_2), value)

which query values as array of [key, value], where key will be used as label, and key is a combination of key_1 key_2.

[Feature request] Округление даты в макросе $from для улучшения cache hit ratio

плагин отправляет запросы вида

SELECT t,
       groupArray((App,C/10))
FROM
  (SELECT (intDiv(toUInt32(EventTime), 3600) * 3600) * 1000 AS t,
          CASE
              WHEN ApplicationID = 12 THEN 'XXX'
              WHEN ApplicationID = 30 THEN 'XXX mobile'
              ELSE 'Other'
          END AS App,
          SUM(Impressions) AS C
   FROM metrics.metrics
   WHERE EventDate >= toDate(1500715771)
     AND EventTime >= toDateTime(1500715771)
   GROUP BY t,
            App
   ORDER BY t,
            App)
GROUP BY t
ORDER BY t FORMAT JSON

$from вставляется в toDate и toDateTime (toDate(1500715771), toDateTime(1500715771))

$from меняется каждые N секунд указаные в параметре рефреша

проблема в том, что если открыто 10 окон то будет 10 разных $from т.к. открыты они были в разное время (допустим с шагом в 1 секунду)

хотелось бы таймстамп начала "сессии" затранкейтить чтоб уменьшить количество уникальных запросов и закешировать их на nginx

When joining with quoted identifier, it skips it in generated query

When doing joins like this

ANY LEFT JOIN table USING `column`

The generated part of query is

ANY LEFT JOIN table USING FORMAT JSON

Instead it should be

ANY LEFT JOIN table USING `column` FORMAT JSON

I believe it has something to do with https://github.com/Vertamedia/clickhouse-grafana/blob/f56fb8d0d257d067dc22925ab0e573547224b64b/src/scanner.ts#L252

It doesn't skip double quoted identifiers.

ANY LEFT JOIN table USING "column"
->
ANY LEFT JOIN table USING "column" FORMAT JSON

But when stringRe value is modified to "('[^']*')|(`[^`]*`)|(\"[^\"]*\")", it skips them too. However reversed quotation marks should be used anyway http://clickhouse-docs.readthedocs.io/en/latest/query_language/syntax.html#identifiers

Options for datasource configuration (yaml)

New grafana allows administrators to use conf/provisioning/datasources/something_here.yaml mechanism to provide datasources through configuration tools (e.g. ansible).

I'm trying to construct a valid yaml to describe a proper configuration, but it's hard. Could you add example into documentation somewhere, please?

My current best efforts:

apiVersion: 1

datasources:
  - name: ClickHouse
    type: vertamedia-clickhouse-datasource
    access: proxy
    basicAuth: true
    url: http://127.0.0.1:8123

Things I don't know how to set up:

defaultDatabase:
User:
Password: (both for basicAuth mode).

Thanks!

Issues with table transform "table"

Hello!

I have a query like:

SELECT
    datetime,
    queryName,
    responseCode
FROM $table
WHERE
    $timeFilter
    and queryName = 'stableit.ru'
LIMIT 5

And I just want to get a response in table format (i.e. single column for each field).

But by default I have following format:
vertica_issue

I tried to select "Table transform: table" but it does not work and reverts to "Table transform: Time Series to rows" immediately.

Is it possible you use your awesome plugin this way?

Plugin version: latest from Grafana.net.

Latest version broke some of queries

May be it was broken in 1.4.1 or in 1.4.0.

Plugin got query and send it to Clickhouse without some symbols.
See resulting query. There is no comma here "AS t toRelativeMinuteNum"

Settings
image

Query

SELECT
    concat( smsc_id, ' (', server, ')' ) AS t,
    toRelativeMinuteNum(now()) - toRelativeMinuteNum(max(dt)) AS c
FROM $table
WHERE
    dt_part >= toDate(now()) - 1
    AND dt >= now() - 86400 * 1
    AND status = 'online'
GROUP BY t
HAVING c > 10
UNION ALL
SELECT
  concat( smsc_id, ' (', server, ')' ) AS t,
  toRelativeMinuteNum(now()) - toRelativeMinuteNum(min(dt)) AS c 
FROM $table WHERE dt_part >= toDate(now()) - 7 AND dt >= now() - 86400 * 7 AND smsc_id NOT IN (
    SELECT smsc_id
    FROM $table
    WHERE
        dt_part >= toDate(now()) - 7
        AND dt >= now() - 86400 * 7
        AND status = 'online'
    GROUP BY smsc_id)
    GROUP BY t

Resulting query

SELECT     concat(smsc_id, ' (', server, ')') AS t,     toRelativeMinuteNum(now()) - toRelativeMinuteNum(max(dt)) AS c FROM gate.kannel_status WHERE     dt_part >= toDate(now()) - 1     AND dt >= now() - 86400 * 1     AND status = 'online' GROUP BY t HAVING c > 10 UNION ALL     SELECT concat(smsc_id, ' (', server, ')') AS t     toRelativeMinuteNum(now()) - toRelativeMinuteNum(min(dt)) AS c FROM gate.kannel_status WHERE dt_part >= toDate(now()) - 7 AND dt >= now() - 86400 * 7 AND smsc_id NOT IN (     SELECT smsc_id     FROM gate.kannel_status     WHERE         dt_part >= toDate(now()) - 7         AND dt >= now() - 86400 * 7         AND status = 'online'     GROUP BY smsc_id)     GROUP BY t

Target table

CREATE TABLE gate.kannel_status ( dt_part Date,  dt DateTime,  server String,  smsc_id String,  status Enum8(\'online\' = 1, \'connecting\' = 2, \'reconnecting\' = 3, \'dead\' = 4)) ENGINE = MergeTree(dt_part, dt, 8192)

Shouldn't $timeCol macro be $dateCol?

$timeCol macro now represents date column

replaced with Date:Col value from Query Builder

Shouldn't it be named $dateCol then to avoid confusion?

Interval or timebucket

Hi, is there a way to user a interval variable type?
I like to have 30 minutes min interval. Thanks.

Allow "(" in unescape macros

With this one can pre-program not only possible fields to display but also some functions like max(field1, field2)

If you do that now resulting SQL will contain max(field1, field2'): note single quote.

don't support latest clickhouse which doesn't require date column

The latest clickhouse support customized partition, so date column is not a must, but the plugin data ranger filter is still based on date column if we don't have data column and use datatime column for both Colum:date and Column:datetime variable, so for range fiter:
where (event_time >= toDate(1518030541)) AND (event_time <= toDate(1522869530)) always return 0 records, should change to
where (event_time >= toDateTime(1518030541)) AND (event_time <= toDateTime(1522869530))

event_time is datetime column.

Thanks

Not correctly formed sql when used select as a nested expression

For

SELECT 
  *
FROM (
  SELECT
    (
      SELECT sum(cnt)
      FROM $table
      WHERE $timeFilter
    ) as cnt
)

Generate

SELECT * FROM (     SELECT (SELECT sum(cnt)FROM DB.TableWHERE date >= toDate(1519467969) AND dateTime >= toDateTime(1519467969)) as cnt )

Missing white space between 'DB.Table' and 'WHERE'

Errors while using 1.2.1 ver

  • Panel data error: metrics_panel_ctrl.ts:171 {message: "AST parser error: undefined"}
  • Error: this.queryCtrl.getCollapsedText is not a function
  • результирующая readonly строка запроса с развернутыми макросами рендерится одной строкой без wrap и обрезается

Use time range filter in a template query

Is it possible to use time range filter (i.e. $from, $to or $timeFilter) in template query?
In Grafana documentation I see "Set this only to On Time Range Change if your variable options query contains a time range filter or is dependent on dashboard time range."
But when I try to use time range filter ($from, $to or $timeFilter) in template query it sends query to CH as is, without replacing $from, $to or $timeFilter

formatted sql from $columns with quantile function is wrong

quantile function requires a float number between 0 - 1, e.g. 0.95, but it is formatted as 0 .95, note this space between 0 and .95.

$columns(process_name, quantile(0.95)(duration) duration) FROM xx
SELECT 
  t, groupArray((process_name, duration)) as groupArr
FROM ( 
  SELECT 
    (intDiv(toUInt32(event_datetime), 5) * 5) * 1000 as t, 
    process_name, 
    quantile(0 .95)(duration) duration 
  FROM xx 
  WHERE event_date >= toDate(1514966917) AND event_datetime >= toDateTime(1514966917) 
  GROUP BY t, process_name  ORDER BY t, process_name
) GROUP BY t ORDER BY t FORMAT JSON

Key column detection breaks tables without timeseries key

Changes introduced in #60 introduce a regression. Maybe make it configurable? Really useful otherwise, thanks for this!

(ping @vavrusa)

Example query:

SELECT
    1,
    srcPort,
    ipProto,
    count(*) * anyLast(sampleRate) AS packets,
    uniqHLL12(ipv4Dst) AS numDst,
    bar(packets, 0, 100000000, 10) AS bar
FROM $table
WHERE $timeFilter
GROUP BY srcPort, ipProto
ORDER BY packets DESC
LIMIT 100

image

$columns broken in version 1.4.3

Macros $columns stop working for new panels between version 1.4.1 and version 1.4.3


SELECT
    $timeSeries as t,
    $columns(severity s, count() c)
FROM $table
WHERE facility=22 AND $timeFilter

Converts to

SELECT     (intDiv(toUInt32(time), 60) * 60) * 1000 as t,     $columns(severity s, count() c) FROM test_logs.test_events WHERE facility=22 AND date >= toDate(1524144310) AND time >= toDateTime(1524144310)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.