mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
[HDX-3994] Deprecate clickhouse.json feature gate in favor of per-exporter json config (#2119)
## Summary
Deprecate the upstream-deprecated `--feature-gates=clickhouse.json` CLI flag in favor of the per-exporter `json: true` config option, as recommended by the OpenTelemetry ClickHouse exporter v0.149.0.
This introduces a new env var `HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE` that controls JSON mode at the exporter config level. The old `OTEL_AGENT_FEATURE_GATE_ARG` env var remains backward-compatible — when it contains `clickhouse.json`, the entrypoint strips that gate, maps it to the new env var, and prints a deprecation warning. Other feature gates are preserved and passed through to the collector.
**Key changes:**
- **`docker/otel-collector/entrypoint.sh`** — Detects `clickhouse.json` in `OTEL_AGENT_FEATURE_GATE_ARG`, strips it, sets `HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE=true`, and prints a deprecation warning. Remaining feature gates are still passed through to the collector in both standalone and supervisor modes.
- **`docker/otel-collector/config.standalone.yaml`** — Added `json: ${env:HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE:-false}` to both ClickHouse exporter configs
- **`packages/api/src/opamp/controllers/opampController.ts`** — Added `json` field to the `CollectorConfig` type and both ClickHouse exporter configs for OpAMP-managed collectors
- **`docker/otel-collector/supervisor_docker.yaml.tmpl`** — Feature gate pass-through preserved for non-`clickhouse.json` gates (entrypoint strips the deprecated gate before supervisor template renders)
- **`smoke-tests/otel-collector/`** — Added a JSON-enabled otel-collector service and smoke tests verifying:
- `ResourceAttributes` and `LogAttributes` columns in `otel_logs` are `JSON` type (not `Map`)
- Log data with various attribute types (string, int, boolean) is inserted and queryable via JSON path access
### How to test locally or on Vercel
1. Run `yarn dev` to start the dev stack
2. Verify the `otel-collector-json` container starts without errors (the `clickhouse.json` feature gate is stripped, not passed to the collector)
3. Check container logs for the deprecation warning when `OTEL_AGENT_FEATURE_GATE_ARG` contains `clickhouse.json`
4. Verify the non-JSON `otel-collector` service continues to work normally (json defaults to false)
5. Run smoke tests: `cd smoke-tests/otel-collector && bats json-exporter.bats`
### References
- Linear Issue: https://linear.app/hyperdx/issue/HDX-3994
- Upstream deprecation: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/clickhouseexporter#experimental-json-support
This commit is contained in:
parent
4ca1d472e3
commit
cb841457f2
14 changed files with 187 additions and 6 deletions
11
.changeset/deprecate-clickhouse-json-feature-gate.md
Normal file
11
.changeset/deprecate-clickhouse-json-feature-gate.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
'@hyperdx/otel-collector': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
refactor: Deprecate clickhouse.json feature gate in favor of per-exporter json config
|
||||||
|
|
||||||
|
Replace the upstream-deprecated `--feature-gates=clickhouse.json` CLI flag with
|
||||||
|
the per-exporter `json: true` config option controlled by
|
||||||
|
`HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE`. The old
|
||||||
|
`OTEL_AGENT_FEATURE_GATE_ARG` is still supported for backward compatibility but
|
||||||
|
prints a deprecation warning when `clickhouse.json` is detected.
|
||||||
|
|
@ -80,9 +80,9 @@ services:
|
||||||
CUSTOM_OTELCOL_CONFIG_FILE: '/etc/otelcol-contrib/custom.config.yaml'
|
CUSTOM_OTELCOL_CONFIG_FILE: '/etc/otelcol-contrib/custom.config.yaml'
|
||||||
# Uncomment to enable stdout logging for the OTel collector
|
# Uncomment to enable stdout logging for the OTel collector
|
||||||
OTEL_SUPERVISOR_LOGS: 'true'
|
OTEL_SUPERVISOR_LOGS: 'true'
|
||||||
# Uncomment to enable JSON schema in ClickHouse
|
# Enable JSON schema in the ClickHouse exporter (per-exporter config)
|
||||||
# Be sure to also set BETA_CH_OTEL_JSON_SCHEMA_ENABLED to 'true' in ch-server
|
# Be sure to also set BETA_CH_OTEL_JSON_SCHEMA_ENABLED to 'true' in ch-server
|
||||||
OTEL_AGENT_FEATURE_GATE_ARG: '--feature-gates=clickhouse.json'
|
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE: 'true'
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/otel-collector/config.yaml:/etc/otelcol-contrib/config.yaml
|
- ./docker/otel-collector/config.yaml:/etc/otelcol-contrib/config.yaml
|
||||||
- ./docker/otel-collector/supervisor_docker.yaml.tmpl:/etc/otel/supervisor.yaml.tmpl
|
- ./docker/otel-collector/supervisor_docker.yaml.tmpl:/etc/otel/supervisor.yaml.tmpl
|
||||||
|
|
@ -109,7 +109,7 @@ services:
|
||||||
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
|
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
|
||||||
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE: ${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE}
|
HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE: ${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE}
|
||||||
# Set to 'true' to allow for proper OTel JSON Schema creation
|
# Set to 'true' to allow for proper OTel JSON Schema creation
|
||||||
# Be sure to also set the OTEL_AGENT_FEATURE_GATE_ARG env in otel-collector
|
# Be sure to also set HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE in otel-collector
|
||||||
# BETA_CH_OTEL_JSON_SCHEMA_ENABLED: 'true'
|
# BETA_CH_OTEL_JSON_SCHEMA_ENABLED: 'true'
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/clickhouse/local/config.xml:/etc/clickhouse-server/config.xml
|
- ./docker/clickhouse/local/config.xml:/etc/clickhouse-server/config.xml
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ exporters:
|
||||||
logs_table_name: hyperdx_sessions
|
logs_table_name: hyperdx_sessions
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
create_schema: ${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}
|
create_schema: ${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}
|
||||||
|
json: ${env:HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE:-false}
|
||||||
retry_on_failure:
|
retry_on_failure:
|
||||||
enabled: true
|
enabled: true
|
||||||
initial_interval: 5s
|
initial_interval: 5s
|
||||||
|
|
@ -46,6 +47,7 @@ exporters:
|
||||||
ttl: 720h
|
ttl: 720h
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
create_schema: ${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}
|
create_schema: ${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}
|
||||||
|
json: ${env:HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE:-false}
|
||||||
retry_on_failure:
|
retry_on_failure:
|
||||||
enabled: true
|
enabled: true
|
||||||
initial_interval: 5s
|
initial_interval: 5s
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Fall back to legacy schema when the ClickHouse JSON feature gate is enabled
|
# DEPRECATED: The clickhouse.json feature gate has been removed upstream.
|
||||||
|
# When OTEL_AGENT_FEATURE_GATE_ARG contains clickhouse.json, strip it and
|
||||||
|
# map it to HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE instead. Other feature gates
|
||||||
|
# are preserved and passed through to the collector.
|
||||||
if echo "$OTEL_AGENT_FEATURE_GATE_ARG" | grep -q "clickhouse.json"; then
|
if echo "$OTEL_AGENT_FEATURE_GATE_ARG" | grep -q "clickhouse.json"; then
|
||||||
|
echo "WARNING: '--feature-gates=clickhouse.json' is deprecated and no longer supported by the collector."
|
||||||
|
echo "WARNING: Use HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE=true instead. This flag will be removed in a future release."
|
||||||
|
export HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE=true
|
||||||
|
|
||||||
|
# Strip clickhouse.json from the feature gates, keeping any other gates
|
||||||
|
REMAINING_GATES=$(echo "$OTEL_AGENT_FEATURE_GATE_ARG" | sed 's/--feature-gates=//' | tr ',' '\n' | grep -v 'clickhouse.json' | tr '\n' ',' | sed 's/,$//')
|
||||||
|
if [ -n "$REMAINING_GATES" ]; then
|
||||||
|
export OTEL_AGENT_FEATURE_GATE_ARG="--feature-gates=$REMAINING_GATES"
|
||||||
|
else
|
||||||
|
unset OTEL_AGENT_FEATURE_GATE_ARG
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fall back to legacy schema when ClickHouse JSON exporter mode is enabled
|
||||||
|
if [ "$HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE" = "true" ]; then
|
||||||
export HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA=true
|
export HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -39,7 +57,7 @@ if [ -z "$OPAMP_SERVER_URL" ]; then
|
||||||
COLLECTOR_ARGS="$COLLECTOR_ARGS --config $CUSTOM_OTELCOL_CONFIG_FILE"
|
COLLECTOR_ARGS="$COLLECTOR_ARGS --config $CUSTOM_OTELCOL_CONFIG_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pass feature gates to the collector in standalone mode
|
# Pass remaining feature gates to the collector in standalone mode
|
||||||
if [ -n "$OTEL_AGENT_FEATURE_GATE_ARG" ]; then
|
if [ -n "$OTEL_AGENT_FEATURE_GATE_ARG" ]; then
|
||||||
COLLECTOR_ARGS="$COLLECTOR_ARGS $OTEL_AGENT_FEATURE_GATE_ARG"
|
COLLECTOR_ARGS="$COLLECTOR_ARGS $OTEL_AGENT_FEATURE_GATE_ARG"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ agent:
|
||||||
{{- if getenv "CUSTOM_OTELCOL_CONFIG_FILE" }}
|
{{- if getenv "CUSTOM_OTELCOL_CONFIG_FILE" }}
|
||||||
- {{ getenv "CUSTOM_OTELCOL_CONFIG_FILE" }}
|
- {{ getenv "CUSTOM_OTELCOL_CONFIG_FILE" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
args:
|
|
||||||
{{- if getenv "OTEL_AGENT_FEATURE_GATE_ARG" }}
|
{{- if getenv "OTEL_AGENT_FEATURE_GATE_ARG" }}
|
||||||
|
args:
|
||||||
- {{ getenv "OTEL_AGENT_FEATURE_GATE_ARG" }}
|
- {{ getenv "OTEL_AGENT_FEATURE_GATE_ARG" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ type CollectorConfig = {
|
||||||
logs_table_name: string;
|
logs_table_name: string;
|
||||||
timeout: string;
|
timeout: string;
|
||||||
create_schema: string;
|
create_schema: string;
|
||||||
|
json: string;
|
||||||
retry_on_failure: {
|
retry_on_failure: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
initial_interval: string;
|
initial_interval: string;
|
||||||
|
|
@ -97,6 +98,7 @@ type CollectorConfig = {
|
||||||
ttl: string;
|
ttl: string;
|
||||||
timeout: string;
|
timeout: string;
|
||||||
create_schema: string;
|
create_schema: string;
|
||||||
|
json: string;
|
||||||
retry_on_failure: {
|
retry_on_failure: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
initial_interval: string;
|
initial_interval: string;
|
||||||
|
|
@ -205,6 +207,7 @@ export const buildOtelCollectorConfig = (
|
||||||
timeout: '5s',
|
timeout: '5s',
|
||||||
create_schema:
|
create_schema:
|
||||||
'${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}',
|
'${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}',
|
||||||
|
json: '${env:HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE:-false}',
|
||||||
retry_on_failure: {
|
retry_on_failure: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
initial_interval: '5s',
|
initial_interval: '5s',
|
||||||
|
|
@ -221,6 +224,7 @@ export const buildOtelCollectorConfig = (
|
||||||
timeout: '5s',
|
timeout: '5s',
|
||||||
create_schema:
|
create_schema:
|
||||||
'${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}',
|
'${env:HYPERDX_OTEL_EXPORTER_CREATE_LEGACY_SCHEMA:-false}',
|
||||||
|
json: '${env:HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE:-false}',
|
||||||
retry_on_failure: {
|
retry_on_failure: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
initial_interval: '5s',
|
initial_interval: '5s',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
SELECT
|
||||||
|
Body,
|
||||||
|
toString(LogAttributes.`user.id`),
|
||||||
|
toString(LogAttributes.`request.method`),
|
||||||
|
toString(LogAttributes.`http.status_code`),
|
||||||
|
toString(LogAttributes.error)
|
||||||
|
FROM otel_json.otel_logs
|
||||||
|
WHERE toString(ResourceAttributes.`suite-id`) = 'json-exporter'
|
||||||
|
AND toString(ResourceAttributes.`test-id`) = 'basic-insert'
|
||||||
|
ORDER BY Timestamp
|
||||||
|
FORMAT CSV
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
"JSON exporter log with string attributes","user-123","GET","",""
|
||||||
|
"JSON exporter log with integer attribute","","","200",""
|
||||||
|
"JSON exporter log with boolean attribute","","","","false"
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
{
|
||||||
|
"resourceLogs": [
|
||||||
|
{
|
||||||
|
"resource": {
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "suite-id",
|
||||||
|
"value": {
|
||||||
|
"stringValue": "json-exporter"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "test-id",
|
||||||
|
"value": {
|
||||||
|
"stringValue": "basic-insert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "service.name",
|
||||||
|
"value": {
|
||||||
|
"stringValue": "test-service"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scopeLogs": [
|
||||||
|
{
|
||||||
|
"scope": {},
|
||||||
|
"logRecords": [
|
||||||
|
{
|
||||||
|
"timeUnixNano": "1901999590000000000",
|
||||||
|
"body": {
|
||||||
|
"stringValue": "JSON exporter log with string attributes"
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "user.id",
|
||||||
|
"value": {
|
||||||
|
"stringValue": "user-123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "request.method",
|
||||||
|
"value": {
|
||||||
|
"stringValue": "GET"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timeUnixNano": "1901999590000000001",
|
||||||
|
"body": {
|
||||||
|
"stringValue": "JSON exporter log with integer attribute"
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "http.status_code",
|
||||||
|
"value": {
|
||||||
|
"intValue": "200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timeUnixNano": "1901999590000000002",
|
||||||
|
"body": {
|
||||||
|
"stringValue": "JSON exporter log with boolean attribute"
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"key": "error",
|
||||||
|
"value": {
|
||||||
|
"boolValue": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
SELECT name, type
|
||||||
|
FROM system.columns
|
||||||
|
WHERE database = 'otel_json'
|
||||||
|
AND table = 'otel_logs'
|
||||||
|
AND name IN ('ResourceAttributes', 'LogAttributes')
|
||||||
|
ORDER BY name
|
||||||
|
FORMAT CSV
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
"LogAttributes","JSON"
|
||||||
|
"ResourceAttributes","JSON"
|
||||||
|
|
@ -43,6 +43,31 @@ services:
|
||||||
ch-server:
|
ch-server:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
|
otel-collector-json:
|
||||||
|
build:
|
||||||
|
context: ../..
|
||||||
|
dockerfile: docker/otel-collector/Dockerfile
|
||||||
|
target: dev
|
||||||
|
args:
|
||||||
|
OTEL_COLLECTOR_VERSION: ${OTEL_COLLECTOR_VERSION:-0.149.0}
|
||||||
|
OTEL_COLLECTOR_CORE_VERSION: ${OTEL_COLLECTOR_CORE_VERSION:-1.55.0}
|
||||||
|
environment:
|
||||||
|
- CLICKHOUSE_ENDPOINT=tcp://ch-server:9000?dial_timeout=10s
|
||||||
|
- CLICKHOUSE_PROMETHEUS_METRICS_ENDPOINT=ch-server:9363
|
||||||
|
- CLICKHOUSE_USER=default
|
||||||
|
- CLICKHOUSE_PASSWORD=
|
||||||
|
- HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=otel_json
|
||||||
|
- HYPERDX_OTEL_EXPORTER_CLICKHOUSE_JSON_ENABLE=true
|
||||||
|
- HYPERDX_LOG_LEVEL=info
|
||||||
|
# OPAMP_SERVER_URL is intentionally not set to run in standalone mode
|
||||||
|
ports:
|
||||||
|
- 14318:4318 # OTLP http receiver
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
depends_on:
|
||||||
|
ch-server:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
internal:
|
internal:
|
||||||
name: 'smoke-test-internal-network'
|
name: 'smoke-test-internal-network'
|
||||||
|
|
|
||||||
14
smoke-tests/otel-collector/json-exporter.bats
Normal file
14
smoke-tests/otel-collector/json-exporter.bats
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load 'test_helpers/utilities.bash'
|
||||||
|
load 'test_helpers/assertions.bash'
|
||||||
|
|
||||||
|
@test "HDX-3994: JSON exporter creates otel_logs table with JSON column types for ResourceAttributes and LogAttributes" {
|
||||||
|
assert_test_data "data/json-exporter/column-types"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "HDX-3994: JSON exporter inserts log data with attributes accessible via JSON path" {
|
||||||
|
emit_otel_data "http://localhost:14318" "data/json-exporter/basic-insert"
|
||||||
|
sleep 2
|
||||||
|
assert_test_data "data/json-exporter/basic-insert"
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ setup_suite() {
|
||||||
validate_env
|
validate_env
|
||||||
docker compose up --build --detach
|
docker compose up --build --detach
|
||||||
wait_for_ready "otel-collector"
|
wait_for_ready "otel-collector"
|
||||||
|
wait_for_ready "otel-collector-json"
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown_suite() {
|
teardown_suite() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue