Skip to content

Commit 4b1e300

Browse files
authored
[exporter/clickhouse]: Add the ability to override default table names for all metric types (#34251)
**Description:** <Describe what has changed.> - add the ability to override default table names for all metric types **Link to tracking Issue:** #34225 **Testing:** - unit tests **Documentation:** <Describe the documentation added.> --------- Signed-off-by: odubajDT <[email protected]>
1 parent 6928f2b commit 4b1e300

14 files changed

+337
-44
lines changed
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: exporter/clickhouse
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add the ability to override default table names for all metric types.
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34225]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: |
19+
'metrics_table_name' of the clickhouse exporter config is deprecated and newly introduced parameter 'metrics_tables' should be used instead.
20+
21+
# If your change doesn't affect end users or the exported elements of any package,
22+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
23+
# Optional: The change log or logs in which this entry should be included.
24+
# e.g. '[user]' or '[user, api]'
25+
# Include 'user' if the change is relevant to end users.
26+
# Include 'api' if there is a change to a library API.
27+
# Default: '[user]'
28+
change_logs: []

exporter/clickhouseexporter/README.md

+22-2
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,17 @@ ClickHouse tables:
294294

295295
- `logs_table_name` (default = otel_logs): The table name for logs.
296296
- `traces_table_name` (default = otel_traces): The table name for traces.
297-
- `metrics_table_name` (default = otel_metrics): The table name for metrics.
297+
- `metrics_tables`
298+
- `gauge`
299+
- `name` (default = "otel_metrics_gauge")
300+
- `sum`
301+
- `name` (default = "otel_metrics_sum")
302+
- `summary`
303+
- `name` (default = "otel_metrics_summary")
304+
- `histogram`
305+
- `name` (default = "otel_metrics_histogram")
306+
- `exponential_histogram`
307+
- `name` (default = "otel_metrics_exp_histogram")
298308

299309
Cluster definition:
300310

@@ -365,8 +375,18 @@ exporters:
365375
create_schema: true
366376
logs_table_name: otel_logs
367377
traces_table_name: otel_traces
368-
metrics_table_name: otel_metrics
369378
timeout: 5s
379+
metrics_tables:
380+
gauge:
381+
name: "otel_metrics_gauge"
382+
sum:
383+
name: "otel_metrics_sum"
384+
summary:
385+
name: "otel_metrics_summary"
386+
histogram:
387+
name: "otel_metrics_histogram"
388+
exponential_histogram:
389+
name: "otel_metrics_exp_histogram"
370390
retry_on_failure:
371391
enabled: true
372392
initial_interval: 5s

exporter/clickhouseexporter/config.go

+61
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"go.opentelemetry.io/collector/config/configopaque"
1515
"go.opentelemetry.io/collector/config/configretry"
1616
"go.opentelemetry.io/collector/exporter/exporterhelper"
17+
18+
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/clickhouseexporter/internal"
1719
)
1820

1921
// Config defines configuration for Elastic exporter.
@@ -37,6 +39,10 @@ type Config struct {
3739
// TracesTableName is the table name for traces. default is `otel_traces`.
3840
TracesTableName string `mapstructure:"traces_table_name"`
3941
// MetricsTableName is the table name for metrics. default is `otel_metrics`.
42+
//
43+
// Deprecated: MetricsTableName exists for historical compatibility
44+
// and should not be used. To set the metrics tables name,
45+
// use the MetricsTables parameter instead.
4046
MetricsTableName string `mapstructure:"metrics_table_name"`
4147
// TTL is The data time-to-live example 30m, 48h. 0 means no ttl.
4248
TTL time.Duration `mapstructure:"ttl"`
@@ -52,6 +58,21 @@ type Config struct {
5258
// Ignored if async inserts are configured in the `endpoint` or `connection_params`.
5359
// Async inserts may still be overridden server-side.
5460
AsyncInsert bool `mapstructure:"async_insert"`
61+
// MetricsTables defines the table names for metric types.
62+
MetricsTables MetricTablesConfig `mapstructure:"metrics_tables"`
63+
}
64+
65+
type MetricTablesConfig struct {
66+
// Gauge is the table name for gauge metric type. default is `otel_metrics_gauge`.
67+
Gauge internal.MetricTypeConfig `mapstructure:"gauge"`
68+
// Sum is the table name for sum metric type. default is `otel_metrics_sum`.
69+
Sum internal.MetricTypeConfig `mapstructure:"sum"`
70+
// Summary is the table name for summary metric type. default is `otel_metrics_summary`.
71+
Summary internal.MetricTypeConfig `mapstructure:"summary"`
72+
// Histogram is the table name for histogram metric type. default is `otel_metrics_histogram`.
73+
Histogram internal.MetricTypeConfig `mapstructure:"histogram"`
74+
// ExponentialHistogram is the table name for exponential histogram metric type. default is `otel_metrics_exponential_histogram`.
75+
ExponentialHistogram internal.MetricTypeConfig `mapstructure:"exponential_histogram"`
5576
}
5677

5778
// TableEngine defines the ENGINE string value when creating the table.
@@ -62,6 +83,12 @@ type TableEngine struct {
6283

6384
const defaultDatabase = "default"
6485
const defaultTableEngineName = "MergeTree"
86+
const defaultMetricTableName = "otel_metrics"
87+
const defaultGaugeSuffix = "_gauge"
88+
const defaultSumSuffix = "_sum"
89+
const defaultSummarySuffix = "_summary"
90+
const defaultHistogramSuffix = "_histogram"
91+
const defaultExpHistogramSuffix = "_exponential_histogram"
6592

6693
var (
6794
errConfigNoEndpoint = errors.New("endpoint must be specified")
@@ -78,6 +105,8 @@ func (cfg *Config) Validate() (err error) {
78105
err = errors.Join(err, e)
79106
}
80107

108+
cfg.buildMetricTableNames()
109+
81110
// Validate DSN with clickhouse driver.
82111
// Last chance to catch invalid config.
83112
if _, e := clickhouse.ParseDSN(dsn); e != nil {
@@ -153,6 +182,38 @@ func (cfg *Config) shouldCreateSchema() bool {
153182
return cfg.CreateSchema
154183
}
155184

185+
func (cfg *Config) buildMetricTableNames() {
186+
tableName := defaultMetricTableName
187+
188+
if len(cfg.MetricsTableName) != 0 && !cfg.areMetricTableNamesSet() {
189+
tableName = cfg.MetricsTableName
190+
}
191+
192+
if len(cfg.MetricsTables.Gauge.Name) == 0 {
193+
cfg.MetricsTables.Gauge.Name = tableName + defaultGaugeSuffix
194+
}
195+
if len(cfg.MetricsTables.Sum.Name) == 0 {
196+
cfg.MetricsTables.Sum.Name = tableName + defaultSumSuffix
197+
}
198+
if len(cfg.MetricsTables.Summary.Name) == 0 {
199+
cfg.MetricsTables.Summary.Name = tableName + defaultSummarySuffix
200+
}
201+
if len(cfg.MetricsTables.Histogram.Name) == 0 {
202+
cfg.MetricsTables.Histogram.Name = tableName + defaultHistogramSuffix
203+
}
204+
if len(cfg.MetricsTables.ExponentialHistogram.Name) == 0 {
205+
cfg.MetricsTables.ExponentialHistogram.Name = tableName + defaultExpHistogramSuffix
206+
}
207+
}
208+
209+
func (cfg *Config) areMetricTableNamesSet() bool {
210+
return len(cfg.MetricsTables.Gauge.Name) != 0 ||
211+
len(cfg.MetricsTables.Sum.Name) != 0 ||
212+
len(cfg.MetricsTables.Summary.Name) != 0 ||
213+
len(cfg.MetricsTables.Histogram.Name) != 0 ||
214+
len(cfg.MetricsTables.ExponentialHistogram.Name) != 0
215+
}
216+
156217
// tableEngineString generates the ENGINE string.
157218
func (cfg *Config) tableEngineString() string {
158219
engine := cfg.TableEngine.Name

exporter/clickhouseexporter/config_test.go

+133-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"go.opentelemetry.io/collector/confmap/confmaptest"
2020
"go.opentelemetry.io/collector/exporter/exporterhelper"
2121

22+
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/clickhouseexporter/internal"
2223
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/clickhouseexporter/internal/metadata"
2324
)
2425

@@ -47,15 +48,14 @@ func TestLoadConfig(t *testing.T) {
4748
{
4849
id: component.NewIDWithName(metadata.Type, "full"),
4950
expected: &Config{
50-
Endpoint: defaultEndpoint,
51-
Database: "otel",
52-
Username: "foo",
53-
Password: "bar",
54-
TTL: 72 * time.Hour,
55-
LogsTableName: "otel_logs",
56-
TracesTableName: "otel_traces",
57-
MetricsTableName: "otel_metrics",
58-
CreateSchema: true,
51+
Endpoint: defaultEndpoint,
52+
Database: "otel",
53+
Username: "foo",
54+
Password: "bar",
55+
TTL: 72 * time.Hour,
56+
LogsTableName: "otel_logs",
57+
TracesTableName: "otel_traces",
58+
CreateSchema: true,
5959
TimeoutSettings: exporterhelper.TimeoutConfig{
6060
Timeout: 5 * time.Second,
6161
},
@@ -67,6 +67,13 @@ func TestLoadConfig(t *testing.T) {
6767
RandomizationFactor: backoff.DefaultRandomizationFactor,
6868
Multiplier: backoff.DefaultMultiplier,
6969
},
70+
MetricsTables: MetricTablesConfig{
71+
Gauge: internal.MetricTypeConfig{Name: "otel_metrics_custom_gauge"},
72+
Sum: internal.MetricTypeConfig{Name: "otel_metrics_custom_sum"},
73+
Summary: internal.MetricTypeConfig{Name: "otel_metrics_custom_summary"},
74+
Histogram: internal.MetricTypeConfig{Name: "otel_metrics_custom_histogram"},
75+
ExponentialHistogram: internal.MetricTypeConfig{Name: "otel_metrics_custom_exp_histogram"},
76+
},
7077
ConnectionParams: map[string]string{},
7178
QueueSettings: exporterhelper.QueueConfig{
7279
Enabled: true,
@@ -102,6 +109,123 @@ func withDefaultConfig(fns ...func(*Config)) *Config {
102109
return cfg
103110
}
104111

112+
func TestBuildMetricMetricTableNames(t *testing.T) {
113+
tests := []struct {
114+
name string
115+
cfg Config
116+
want Config
117+
}{
118+
{
119+
name: "nothing set",
120+
cfg: Config{},
121+
want: Config{
122+
MetricsTables: MetricTablesConfig{
123+
Gauge: internal.MetricTypeConfig{Name: "otel_metrics_gauge"},
124+
Sum: internal.MetricTypeConfig{Name: "otel_metrics_sum"},
125+
Summary: internal.MetricTypeConfig{Name: "otel_metrics_summary"},
126+
Histogram: internal.MetricTypeConfig{Name: "otel_metrics_histogram"},
127+
ExponentialHistogram: internal.MetricTypeConfig{Name: "otel_metrics_exponential_histogram"},
128+
},
129+
},
130+
},
131+
{
132+
name: "only metric_table_name set",
133+
cfg: Config{
134+
MetricsTableName: "table_name",
135+
},
136+
want: Config{
137+
MetricsTableName: "table_name",
138+
MetricsTables: MetricTablesConfig{
139+
Gauge: internal.MetricTypeConfig{Name: "table_name_gauge"},
140+
Sum: internal.MetricTypeConfig{Name: "table_name_sum"},
141+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
142+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
143+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exponential_histogram"},
144+
},
145+
},
146+
},
147+
{
148+
name: "only metric_tables set fully",
149+
cfg: Config{
150+
MetricsTables: MetricTablesConfig{
151+
Gauge: internal.MetricTypeConfig{Name: "table_name_gauge"},
152+
Sum: internal.MetricTypeConfig{Name: "table_name_sum"},
153+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
154+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
155+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exponential_histogram"},
156+
},
157+
},
158+
want: Config{
159+
MetricsTables: MetricTablesConfig{
160+
Gauge: internal.MetricTypeConfig{Name: "table_name_gauge"},
161+
Sum: internal.MetricTypeConfig{Name: "table_name_sum"},
162+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
163+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
164+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exponential_histogram"},
165+
},
166+
},
167+
},
168+
{
169+
name: "only metric_tables set partially",
170+
cfg: Config{
171+
MetricsTables: MetricTablesConfig{
172+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
173+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
174+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exp_histogram"},
175+
},
176+
},
177+
want: Config{
178+
MetricsTables: MetricTablesConfig{
179+
Gauge: internal.MetricTypeConfig{Name: "otel_metrics_gauge"},
180+
Sum: internal.MetricTypeConfig{Name: "otel_metrics_sum"},
181+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
182+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
183+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exp_histogram"},
184+
},
185+
},
186+
},
187+
{
188+
name: "only metric_tables set partially with metric_table_name",
189+
cfg: Config{
190+
MetricsTableName: "custom_name",
191+
MetricsTables: MetricTablesConfig{
192+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
193+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
194+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exp_histogram"},
195+
},
196+
},
197+
want: Config{
198+
MetricsTableName: "custom_name",
199+
MetricsTables: MetricTablesConfig{
200+
Gauge: internal.MetricTypeConfig{Name: "otel_metrics_gauge"},
201+
Sum: internal.MetricTypeConfig{Name: "otel_metrics_sum"},
202+
Summary: internal.MetricTypeConfig{Name: "table_name_summary"},
203+
Histogram: internal.MetricTypeConfig{Name: "table_name_histogram"},
204+
ExponentialHistogram: internal.MetricTypeConfig{Name: "table_name_exp_histogram"},
205+
},
206+
},
207+
},
208+
}
209+
for _, tt := range tests {
210+
t.Run(tt.name, func(t *testing.T) {
211+
tt.cfg.buildMetricTableNames()
212+
require.Equal(t, tt.want, tt.cfg)
213+
})
214+
}
215+
}
216+
217+
func TestAreMetricTableNamesSet(t *testing.T) {
218+
cfg := Config{}
219+
require.False(t, cfg.areMetricTableNamesSet())
220+
221+
cfg = Config{
222+
MetricsTables: MetricTablesConfig{
223+
Gauge: internal.MetricTypeConfig{Name: "gauge"},
224+
},
225+
}
226+
require.True(t, cfg.areMetricTableNamesSet())
227+
}
228+
105229
func TestConfig_buildDSN(t *testing.T) {
106230
type fields struct {
107231
Endpoint string

exporter/clickhouseexporter/exporter_metrics.go

+21-7
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ import (
1919
type metricsExporter struct {
2020
client *sql.DB
2121

22-
logger *zap.Logger
23-
cfg *Config
22+
logger *zap.Logger
23+
cfg *Config
24+
tablesConfig internal.MetricTablesConfigMapper
2425
}
2526

2627
func newMetricsExporter(logger *zap.Logger, cfg *Config) (*metricsExporter, error) {
@@ -29,10 +30,13 @@ func newMetricsExporter(logger *zap.Logger, cfg *Config) (*metricsExporter, erro
2930
return nil, err
3031
}
3132

33+
tablesConfig := generateMetricTablesConfigMapper(cfg)
34+
3235
return &metricsExporter{
33-
client: client,
34-
logger: logger,
35-
cfg: cfg,
36+
client: client,
37+
logger: logger,
38+
cfg: cfg,
39+
tablesConfig: tablesConfig,
3640
}, nil
3741
}
3842

@@ -48,7 +52,17 @@ func (e *metricsExporter) start(ctx context.Context, _ component.Host) error {
4852
}
4953

5054
ttlExpr := generateTTLExpr(e.cfg.TTL, "toDateTime(TimeUnix)")
51-
return internal.NewMetricsTable(ctx, e.cfg.MetricsTableName, e.cfg.clusterString(), e.cfg.tableEngineString(), ttlExpr, e.client)
55+
return internal.NewMetricsTable(ctx, e.tablesConfig, e.cfg.clusterString(), e.cfg.tableEngineString(), ttlExpr, e.client)
56+
}
57+
58+
func generateMetricTablesConfigMapper(cfg *Config) internal.MetricTablesConfigMapper {
59+
return internal.MetricTablesConfigMapper{
60+
pmetric.MetricTypeGauge: cfg.MetricsTables.Gauge,
61+
pmetric.MetricTypeSum: cfg.MetricsTables.Sum,
62+
pmetric.MetricTypeSummary: cfg.MetricsTables.Summary,
63+
pmetric.MetricTypeHistogram: cfg.MetricsTables.Histogram,
64+
pmetric.MetricTypeExponentialHistogram: cfg.MetricsTables.ExponentialHistogram,
65+
}
5266
}
5367

5468
// shutdown will shut down the exporter.
@@ -60,7 +74,7 @@ func (e *metricsExporter) shutdown(_ context.Context) error {
6074
}
6175

6276
func (e *metricsExporter) pushMetricsData(ctx context.Context, md pmetric.Metrics) error {
63-
metricsMap := internal.NewMetricsModel(e.cfg.MetricsTableName)
77+
metricsMap := internal.NewMetricsModel(e.tablesConfig)
6478
for i := 0; i < md.ResourceMetrics().Len(); i++ {
6579
metrics := md.ResourceMetrics().At(i)
6680
resAttr := attributesToMap(metrics.Resource().Attributes())

0 commit comments

Comments
 (0)