Skip to content

Commit

Permalink
[exporter/clickhouse] Add metrics support (#16477)
Browse files Browse the repository at this point in the history
  • Loading branch information
Frapschen authored Jan 20, 2023
1 parent a7ab5d3 commit 8821292
Show file tree
Hide file tree
Showing 15 changed files with 2,085 additions and 19 deletions.
16 changes: 16 additions & 0 deletions .chloggen/export-metrics-to-clickhouse.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: clickhouseexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: export metrics to clickhouse

# One or more tracking issues related to the change
issues: [16478]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ exporter/awsxrayexporter/ @open-telemetry/collect
exporter/azuremonitorexporter/ @open-telemetry/collector-contrib-approvers @pcwiese
exporter/azuredataexplorerexporter/ @open-telemetry/collector-contrib-approvers @asaharan @ag-ramachandran
exporter/carbonexporter/ @open-telemetry/collector-contrib-approvers @pjanotti
exporter/clickhouseexporter/ @open-telemetry/collector-contrib-approvers @hanjm @dmitryax
exporter/clickhouseexporter/ @open-telemetry/collector-contrib-approvers @hanjm @dmitryax @Frapschen
exporter/coralogixexporter/ @open-telemetry/collector-contrib-approvers @oded-dd @ofirshmuel
exporter/datadogexporter/ @open-telemetry/collector-contrib-approvers @KSerrania @mx-psi @gbbr @knusbaum @amenasria @dineshg13
exporter/dynatraceexporter/ @open-telemetry/collector-contrib-approvers @dyladan @arminru @evan-bradley
Expand Down
234 changes: 226 additions & 8 deletions exporter/clickhouseexporter/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# ClickHouse Exporter

| Status | |
| ------------------------ |--------------|
| Stability | [alpha] |
| Supported pipeline types | traces, logs |
| Distributions | [contrib] |
| Status | |
| ------------------------ |-----------------------|
| Stability | [alpha] |
| Supported pipeline types | traces, logs, metrics |
| Distributions | [contrib] |

This exporter supports sending OpenTelemetry logs and spans to [ClickHouse](https://clickhouse.com/).
This exporter supports sending OpenTelemetry data to [ClickHouse](https://clickhouse.com/).
> ClickHouse is an open-source, high performance columnar OLAP database management system for real-time analytics using
> SQL.
> Throughput can be measured in rows per second or megabytes per second.
Expand Down Expand Up @@ -214,6 +214,40 @@ WHERE ServiceName = 'clickhouse-exporter'
Limit 100;
```

### Metrics

Metrics data is stored in different clickhouse tables depending on their types. The tables will have a suffix to
distinguish which type of metrics data is stored.

| Metrics Type | Metrics Table |
| --------------------- | ---------------------- |
| sum | _sum |
| gauge | _gauge |
| histogram | _histogram |
| exponential histogram | _exponential_histogram |
| summary | _summary |

Before you make a metrics query, you need to know the type of metric you wish to use. If your metrics come from
Prometheus(or someone else uses OpenMetrics protocol), you also need to know the
[compatibility](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#prometheus-and-openmetrics-compatibility)
between Prometheus(OpenMetrics) and OTLP Metrics.

- Find a sum metrics with name
```clickhouse
select TimeUnix,MetricName,Attributes,Value from otel_metrics_sum
where MetricName='calls_total' limit 100
```

- Find a sum metrics with name, attribute.
```clickhouse
select TimeUnix,MetricName,Attributes,Value from otel_metrics_sum
where MetricName='calls_total' and Attributes['service_name']='featureflagservice'
limit 100
```

The OTLP Metrics [define two type value for one datapoint](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto#L358),
clickhouse only use one value of float64 to store them.

## Performance Guide

A single clickhouse instance with 32 CPU cores and 128 GB RAM can handle around 20 TB (20 Billion) logs per day,
Expand All @@ -240,6 +274,7 @@ The following settings can be optionally configured:
- `database` (default = otel): The database name.
- `logs_table_name` (default = otel_logs): The table name for logs.
- `traces_table_name` (default = otel_traces): The table name for traces.
- `metrics_table_name` (default = otel_metrics): The table name for metrics.
- `timeout` (default = 5s): The timeout for every attempt to send data to the backend.
- `sending_queue`
- `queue_size` (default = 5000): Maximum number of batches kept in memory before dropping data.
Expand All @@ -264,8 +299,9 @@ exporters:
clickhouse:
dsn: tcp://127.0.0.1:9000/otel
ttl_days: 3
logs_table_name: otel_logs
traces_table_name: otel_traces
logs_table: otel_logs
traces_table: otel_traces
metrics_table: otel_metrics
timeout: 5s
retry_on_failure:
enabled: true
Expand Down Expand Up @@ -375,6 +411,188 @@ WHERE TraceId != ''
GROUP BY TraceId;
```

### Metrics

#### Gauge

```clickhouse
CREATE TABLE IF NOT EXISTS otel.otel_metrics_gauge (
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeDroppedAttrCount UInt32 CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
MetricName String CODEC(ZSTD(1)),
MetricDescription String CODEC(ZSTD(1)),
MetricUnit String CODEC(ZSTD(1)),
Attributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
StartTimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
TimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
Value Float64 CODEC(ZSTD(1)),
Flags UInt32 CODEC(ZSTD(1)),
Exemplars Nested (
FilteredAttributes Map(LowCardinality(String), String),
TimeUnix DateTime64(9),
Value Float64,
SpanId String,
TraceId String
) CODEC(ZSTD(1))
) ENGINE MergeTree()
TTL toDateTime(TimeUnix) + toIntervalDay(3)
PARTITION BY toDate(TimeUnix)
ORDER BY (MetricName, Attributes, toUnixTimestamp64Nano(TimeUnix))
SETTINGS index_granularity=8192, ttl_only_drop_parts = 1;
```

#### Sum

```clickhouse
CREATE TABLE IF NOT EXISTS otel.otel_metrics_sum (
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeDroppedAttrCount UInt32 CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
MetricName String CODEC(ZSTD(1)),
MetricDescription String CODEC(ZSTD(1)),
MetricUnit String CODEC(ZSTD(1)),
Attributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
StartTimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
TimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
Value Float64 CODEC(ZSTD(1)),
Flags UInt32 CODEC(ZSTD(1)),
Exemplars Nested (
FilteredAttributes Map(LowCardinality(String), String),
TimeUnix DateTime64(9),
Value Float64,
SpanId String,
TraceId String
) CODEC(ZSTD(1)),
AggTemp Int32 CODEC(ZSTD(1)),
IsMonotonic Boolean CODEC(Delta, ZSTD(1))
) ENGINE MergeTree()
TTL toDateTime(TimeUnix) + toIntervalDay(3)
PARTITION BY toDate(TimeUnix)
ORDER BY (MetricName, Attributes, toUnixTimestamp64Nano(TimeUnix))
SETTINGS index_granularity=8192, ttl_only_drop_parts = 1;
```

#### Histogram

```clickhouse
CREATE TABLE IF NOT EXISTS otel.otel_metrics_histogram (
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeDroppedAttrCount UInt32 CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
MetricName String CODEC(ZSTD(1)),
MetricDescription String CODEC(ZSTD(1)),
MetricUnit String CODEC(ZSTD(1)),
Attributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
StartTimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
TimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
Count Int64 CODEC(Delta, ZSTD(1)),
Sum Float64 CODEC(ZSTD(1)),
BucketCounts Array(UInt64) CODEC(ZSTD(1)),
ExplicitBounds Array(Float64) CODEC(ZSTD(1)),
Exemplars Nested (
FilteredAttributes Map(LowCardinality(String), String),
TimeUnix DateTime64(9),
Value Float64,
SpanId String,
TraceId String
) CODEC(ZSTD(1)),
Flags UInt32 CODEC(ZSTD(1)),
Min Float64 CODEC(ZSTD(1)),
Max Float64 CODEC(ZSTD(1))
) ENGINE MergeTree()
TTL toDateTime(TimeUnix) + toIntervalDay(3)
PARTITION BY toDate(TimeUnix)
ORDER BY (MetricName, Attributes, toUnixTimestamp64Nano(TimeUnix))
SETTINGS index_granularity=8192, ttl_only_drop_parts = 1;
```

#### Exponential histogram

```clickhouse
CREATE TABLE IF NOT EXISTS otel.otel_metrics_exponential_histogram (
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeDroppedAttrCount UInt32 CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
MetricName String CODEC(ZSTD(1)),
MetricDescription String CODEC(ZSTD(1)),
MetricUnit String CODEC(ZSTD(1)),
Attributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
StartTimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
TimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
Count Int64 CODEC(Delta, ZSTD(1)),
Sum Float64 CODEC(ZSTD(1)),
Scale Int32 CODEC(ZSTD(1)),
ZeroCount UInt64 CODEC(ZSTD(1)),
PositiveOffset Int32 CODEC(ZSTD(1)),
PositiveBucketCounts Array(UInt64) CODEC(ZSTD(1)),
NegativeOffset Int32 CODEC(ZSTD(1)),
NegativeBucketCounts Array(UInt64) CODEC(ZSTD(1)),
Exemplars Nested (
FilteredAttributes Map(LowCardinality(String), String),
TimeUnix DateTime64(9),
Value Float64,
SpanId String,
TraceId String
) CODEC(ZSTD(1)),
Flags UInt32 CODEC(ZSTD(1)),
Min Float64 CODEC(ZSTD(1)),
Max Float64 CODEC(ZSTD(1))
) ENGINE MergeTree()
TTL toDateTime(TimeUnix) + toIntervalDay(3)
PARTITION BY toDate(TimeUnix)
ORDER BY (MetricName, Attributes, toUnixTimestamp64Nano(TimeUnix))
SETTINGS index_granularity=8192, ttl_only_drop_parts = 1;
```

#### Summary

```clickhouse
CREATE TABLE IF NOT EXISTS otel.otel_metrics_summary (
ResourceAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ResourceSchemaUrl String CODEC(ZSTD(1)),
ScopeName String CODEC(ZSTD(1)),
ScopeVersion String CODEC(ZSTD(1)),
ScopeAttributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
ScopeDroppedAttrCount UInt32 CODEC(ZSTD(1)),
ScopeSchemaUrl String CODEC(ZSTD(1)),
MetricName String CODEC(ZSTD(1)),
MetricDescription String CODEC(ZSTD(1)),
MetricUnit String CODEC(ZSTD(1)),
Attributes Map(LowCardinality(String), String) CODEC(ZSTD(1)),
StartTimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
TimeUnix DateTime64(9) CODEC(Delta, ZSTD(1)),
Count UInt64 CODEC(Delta, ZSTD(1)),
Sum Float64 CODEC(ZSTD(1)),
ValueAtQuantiles Nested(
Quantile Float64,
Value Float64
) CODEC(ZSTD(1)),
Flags UInt32 CODEC(ZSTD(1))
) ENGINE MergeTree()
TTL toDateTime(TimeUnix) + toIntervalDay(3)
PARTITION BY toDate(TimeUnix)
ORDER BY (MetricName, Attributes, toUnixTimestamp64Nano(TimeUnix))
SETTINGS index_granularity=8192, ttl_only_drop_parts = 1;
```


[alpha]:https://github.com/open-telemetry/opentelemetry-collector#alpha

[contrib]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
2 changes: 2 additions & 0 deletions exporter/clickhouseexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Config struct {
LogsTableName string `mapstructure:"logs_table_name"`
// TracesTableName is the table name for logs. default is `otel_traces`.
TracesTableName string `mapstructure:"traces_table_name"`
// MetricsTableName is the table name for metrics. default is `otel_metrics`.
MetricsTableName string `mapstructure:"metrics_table_name"`
// TTLDays is The data time-to-live in days, 0 means no ttl.
TTLDays uint `mapstructure:"ttl_days"`
}
Expand Down
9 changes: 5 additions & 4 deletions exporter/clickhouseexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ func TestLoadConfig(t *testing.T) {
{
id: component.NewIDWithName(typeStr, "full"),
expected: &Config{
DSN: defaultDSN,
TTLDays: 3,
LogsTableName: "otel_logs",
TracesTableName: "otel_traces",
DSN: defaultDSN,
TTLDays: 3,
LogsTableName: "otel_logs",
TracesTableName: "otel_traces",
MetricsTableName: "otel_metrics",
TimeoutSettings: exporterhelper.TimeoutSettings{
Timeout: 5 * time.Second,
},
Expand Down
Loading

0 comments on commit 8821292

Please sign in to comment.