@intentius/chant-lexicon-otel 0.124.46 → 0.124.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/build/capability-plugin.d.ts +10 -0
- package/dist/build/capability-plugin.d.ts.map +1 -0
- package/dist/build/capability-plugin.js +19 -0
- package/dist/build/ocb-build.d.ts +38 -0
- package/dist/build/ocb-build.d.ts.map +1 -0
- package/dist/build/ocb-build.js +49 -0
- package/dist/clickhouse-tables.d.ts +73 -0
- package/dist/clickhouse-tables.d.ts.map +1 -0
- package/dist/clickhouse-tables.js +199 -0
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/docs.js +4 -2
- package/dist/codegen/generate.d.ts +29 -10
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/codegen/generate.js +82 -17
- package/dist/components/common.d.ts +3 -1
- package/dist/components/common.d.ts.map +1 -1
- package/dist/components/common.js +2 -0
- package/dist/components/connectors.d.ts +25 -90
- package/dist/components/connectors.d.ts.map +1 -1
- package/dist/components/connectors.js +3 -0
- package/dist/components/exporters.d.ts +78 -34
- package/dist/components/exporters.d.ts.map +1 -1
- package/dist/components/exporters.js +26 -1
- package/dist/components/extensions.d.ts +16 -33
- package/dist/components/extensions.d.ts.map +1 -1
- package/dist/components/filtering.d.ts +13 -60
- package/dist/components/filtering.d.ts.map +1 -1
- package/dist/components/k8s-receivers.d.ts +5 -53
- package/dist/components/k8s-receivers.d.ts.map +1 -1
- package/dist/components/overlay.d.ts +25 -0
- package/dist/components/overlay.d.ts.map +1 -0
- package/dist/components/overlay.js +19 -0
- package/dist/components/processors.d.ts +18 -79
- package/dist/components/processors.d.ts.map +1 -1
- package/dist/components/receivers.d.ts +17 -71
- package/dist/components/receivers.d.ts.map +1 -1
- package/dist/components/receivers.js +3 -1
- package/dist/components/sampling.d.ts +19 -35
- package/dist/components/sampling.d.ts.map +1 -1
- package/dist/config-hygiene.d.ts +10 -8
- package/dist/config-hygiene.d.ts.map +1 -1
- package/dist/config-hygiene.js +36 -13
- package/dist/coverage.d.ts +50 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +92 -0
- package/dist/define.d.ts +8 -5
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +10 -6
- package/dist/distribution.d.ts +125 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +227 -0
- package/dist/generated/index.d.ts +4234 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +23 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/init-templates.js +2 -2
- package/dist/integrity.json +11 -9
- package/dist/lint/audit-catalog.d.ts +3 -0
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-catalog.js +5 -0
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +4 -0
- package/dist/lint/post-synth/otel-helpers.d.ts +2 -1
- package/dist/lint/post-synth/otel-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/otel-helpers.js +1 -1
- package/dist/lint/post-synth/otel119.d.ts +1 -1
- package/dist/lint/post-synth/otel119.js +1 -1
- package/dist/lint/post-synth/otel125.d.ts +1 -1
- package/dist/lint/post-synth/otel125.js +1 -1
- package/dist/lint/post-synth/otel126.d.ts +1 -1
- package/dist/lint/post-synth/otel126.js +1 -1
- package/dist/lint/post-synth/otel127.d.ts +1 -1
- package/dist/lint/post-synth/otel127.js +1 -1
- package/dist/lint/post-synth/otel128.d.ts +8 -0
- package/dist/lint/post-synth/otel128.d.ts.map +1 -0
- package/dist/lint/post-synth/otel128.js +17 -0
- package/dist/lint/post-synth/otel129.d.ts +15 -0
- package/dist/lint/post-synth/otel129.d.ts.map +1 -0
- package/dist/lint/post-synth/otel129.js +92 -0
- package/dist/lsp/completions.d.ts +10 -1
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +29 -1
- package/dist/lsp/hover.d.ts +5 -1
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +16 -3
- package/dist/lsp/properties.d.ts +34 -0
- package/dist/lsp/properties.d.ts.map +1 -0
- package/dist/lsp/properties.js +135 -0
- package/dist/manifest.json +1 -1
- package/dist/meta.json +5 -0
- package/dist/metric-names.d.ts +36 -8
- package/dist/metric-names.d.ts.map +1 -1
- package/dist/metric-names.js +42 -9
- package/dist/model.d.ts +1 -1
- package/dist/model.js +1 -1
- package/dist/okf/index.md +3 -0
- package/dist/okf/rules/OTEL128.md +11 -0
- package/dist/okf/rules/OTEL129.md +11 -0
- package/dist/okf/types/ClickHouseExporter.md +9 -0
- package/dist/op/activities/collector-audit.d.ts +18 -6
- package/dist/op/activities/collector-audit.d.ts.map +1 -1
- package/dist/op/activities/collector-audit.js +37 -21
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +51 -8
- package/dist/rules/otel-helpers.ts +1 -1
- package/dist/rules/otel119.ts +1 -1
- package/dist/rules/otel125.ts +1 -1
- package/dist/rules/otel126.ts +1 -1
- package/dist/rules/otel127.ts +1 -1
- package/dist/rules/otel128.ts +22 -0
- package/dist/rules/otel129.ts +99 -0
- package/dist/serializer.d.ts +3 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +12 -2
- package/dist/spec/builtins.d.ts +17 -0
- package/dist/spec/builtins.d.ts.map +1 -0
- package/dist/spec/builtins.js +45 -0
- package/dist/spec/fetch.d.ts +120 -0
- package/dist/spec/fetch.d.ts.map +1 -0
- package/dist/spec/fetch.js +282 -0
- package/dist/spec/parse.d.ts +77 -0
- package/dist/spec/parse.d.ts.map +1 -0
- package/dist/spec/parse.js +337 -0
- package/dist/spec/pin.d.ts +82 -0
- package/dist/spec/pin.d.ts.map +1 -0
- package/dist/spec/pin.js +126 -0
- package/dist/spec/snapshot-cli.d.ts +13 -0
- package/dist/spec/snapshot-cli.d.ts.map +1 -0
- package/dist/spec/snapshot-cli.js +31 -0
- package/dist/spec/snapshot.d.ts +9 -0
- package/dist/spec/snapshot.d.ts.map +1 -0
- package/dist/spec/snapshot.js +14 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/validate-config.d.ts +1 -1
- package/dist/validate-config.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +1 -0
- package/dist/workspace-links.d.ts +25 -0
- package/dist/workspace-links.d.ts.map +1 -0
- package/dist/workspace-links.js +49 -0
- package/package.json +3 -2
- package/src/build/capability-plugin.ts +30 -0
- package/src/build/ocb-build.ts +73 -0
- package/src/clickhouse-exporter.e2e.test.ts +208 -0
- package/src/clickhouse-tables.test.ts +216 -0
- package/src/clickhouse-tables.ts +223 -0
- package/src/codegen/docs.ts +4 -2
- package/src/codegen/generate.ts +95 -19
- package/src/components/common.ts +4 -2
- package/src/components/connectors.ts +30 -77
- package/src/components/exporters.ts +128 -61
- package/src/components/extensions.ts +22 -36
- package/src/components/filtering.ts +17 -58
- package/src/components/k8s-receivers.test.ts +1 -1
- package/src/components/k8s-receivers.ts +3 -45
- package/src/components/overlay.ts +24 -0
- package/src/components/processors.ts +18 -63
- package/src/components/receivers.ts +20 -60
- package/src/components/sampling.ts +24 -37
- package/src/config-hygiene.ts +36 -13
- package/src/coverage.test.ts +37 -0
- package/src/coverage.ts +121 -0
- package/src/define.test.ts +2 -0
- package/src/define.ts +10 -6
- package/src/distribution.test.ts +250 -0
- package/src/distribution.ts +305 -0
- package/src/generated/index.ts +4576 -0
- package/src/generated/lexicon-otel.json +5 -0
- package/src/generated/properties.json +1 -0
- package/src/import/roundtrip.test.ts +16 -0
- package/src/import/testdata/clickhouse.yaml +37 -0
- package/src/import/testdata/fixtures.ts +17 -2
- package/src/import/testdata/upstream/clickhouse-exporter.yaml +60 -0
- package/src/index.ts +69 -0
- package/src/init-templates.ts +2 -2
- package/src/lint/audit-catalog.ts +15 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/otel-helpers.ts +1 -1
- package/src/lint/post-synth/otel119.ts +1 -1
- package/src/lint/post-synth/otel125.ts +1 -1
- package/src/lint/post-synth/otel126.ts +1 -1
- package/src/lint/post-synth/otel127.ts +1 -1
- package/src/lint/post-synth/otel128.ts +22 -0
- package/src/lint/post-synth/otel129.ts +99 -0
- package/src/lsp/completions.ts +30 -1
- package/src/lsp/hover.ts +14 -3
- package/src/lsp/properties.test.ts +72 -0
- package/src/lsp/properties.ts +141 -0
- package/src/metric-names.test.ts +11 -0
- package/src/metric-names.ts +64 -16
- package/src/model.ts +1 -1
- package/src/op/activities/collector-audit.test.ts +29 -22
- package/src/op/activities/collector-audit.ts +38 -18
- package/src/plugin.test.ts +2 -0
- package/src/plugin.ts +57 -6
- package/src/serializer.ts +11 -2
- package/src/spec/builtins.ts +56 -0
- package/src/spec/fetch.ts +332 -0
- package/src/spec/otel-schemas.snapshot.json +13932 -0
- package/src/spec/parse.ts +364 -0
- package/src/spec/pin.ts +155 -0
- package/src/spec/snapshot-cli.ts +32 -0
- package/src/spec/snapshot.ts +19 -0
- package/src/spec/spec.test.ts +144 -0
- package/src/validate-config.ts +4 -3
- package/src/validate.ts +1 -0
- package/src/workspace-links.e2e.test.ts +91 -0
- package/src/workspace-links.ts +50 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ClickHouse tables a `clickhouse` exporter writes (#4397), read from its
|
|
3
|
+
* config the way the exporter reads it at `COLLECTOR_PIN` (contrib v0.130.0).
|
|
4
|
+
* OTEL129 and the otel lexicon's `workspaceLinks` hook share this, so the
|
|
5
|
+
* check in one build root and the link across workspace members agree on
|
|
6
|
+
* which tables and columns an exporter needs.
|
|
7
|
+
*
|
|
8
|
+
* Sources in opentelemetry-collector-contrib at v0.130.0,
|
|
9
|
+
* `exporter/clickhouseexporter/`:
|
|
10
|
+
*
|
|
11
|
+
* - Default names: `createDefaultConfig` and `buildMetricTableNames` in
|
|
12
|
+
* `config.go`. The exponential histogram table is
|
|
13
|
+
* `otel_metrics_exponential_histogram` there; the README says
|
|
14
|
+
* `otel_metrics_exp_histogram`, and the code is what runs.
|
|
15
|
+
* - Database: `Config.database()` in `config.go`. `database` wins unless it
|
|
16
|
+
* is `default`, then the endpoint DSN's database, then `default`.
|
|
17
|
+
* - Columns: the column lists of the insert statements in
|
|
18
|
+
* `internal/sqltemplates/*_insert.sql`. A `Nested` field such as
|
|
19
|
+
* `Events.Timestamp` is listed under its column, `Events`.
|
|
20
|
+
* - Which tables a signal touches: each signal's exporter writes only its own
|
|
21
|
+
* tables (`exporter_logs.go`, `exporter_traces.go`, `exporter_metrics.go`),
|
|
22
|
+
* and only when a pipeline of that signal uses the exporter.
|
|
23
|
+
* - `create_schema` defaults to true and makes the exporter run
|
|
24
|
+
* `CREATE TABLE IF NOT EXISTS` for its tables at start.
|
|
25
|
+
*
|
|
26
|
+
* The trace-id lookup table and its materialized view, which the traces
|
|
27
|
+
* exporter creates beside the traces table when `create_schema` is true, are
|
|
28
|
+
* not written by the exporter: the view fills the table from the traces
|
|
29
|
+
* table's inserts. They are not part of what an exporter needs here.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type { CollectorConfig } from "./model";
|
|
33
|
+
import { parseComponentId, pipelineSignal } from "./model";
|
|
34
|
+
|
|
35
|
+
/** One table an exporter writes. */
|
|
36
|
+
export interface ClickHouseExporterTable {
|
|
37
|
+
/** The signal whose pipeline writes it. */
|
|
38
|
+
signal: "logs" | "traces" | "metrics";
|
|
39
|
+
/** The config key that names it: `logs_table_name`, `metrics_tables.gauge.name`. */
|
|
40
|
+
key: string;
|
|
41
|
+
/** The table, as the exporter resolves it. */
|
|
42
|
+
name: string;
|
|
43
|
+
/** The columns its insert statement names. */
|
|
44
|
+
columns: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** What one `clickhouse` exporter writes. */
|
|
48
|
+
export interface ClickHouseExporterTargets {
|
|
49
|
+
/** The exporter's id: `clickhouse` or `clickhouse/<name>`. */
|
|
50
|
+
id: string;
|
|
51
|
+
database: string;
|
|
52
|
+
/** Whether the exporter creates its database and tables at start (`create_schema`, default true). */
|
|
53
|
+
createSchema: boolean;
|
|
54
|
+
tables: ClickHouseExporterTable[];
|
|
55
|
+
/** Values chant can't read without the environment, such as `${env:CH_DB}`: the tables they name are left out. */
|
|
56
|
+
unread: string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const METRIC_HEAD = [
|
|
60
|
+
"ResourceAttributes",
|
|
61
|
+
"ResourceSchemaUrl",
|
|
62
|
+
"ScopeName",
|
|
63
|
+
"ScopeVersion",
|
|
64
|
+
"ScopeAttributes",
|
|
65
|
+
"ScopeDroppedAttrCount",
|
|
66
|
+
"ScopeSchemaUrl",
|
|
67
|
+
"ServiceName",
|
|
68
|
+
"MetricName",
|
|
69
|
+
"MetricDescription",
|
|
70
|
+
"MetricUnit",
|
|
71
|
+
"Attributes",
|
|
72
|
+
"StartTimeUnix",
|
|
73
|
+
"TimeUnix",
|
|
74
|
+
] as const;
|
|
75
|
+
|
|
76
|
+
/** The columns each insert statement names, at v0.130.0. */
|
|
77
|
+
export const CLICKHOUSE_EXPORTER_COLUMNS = {
|
|
78
|
+
logs: [
|
|
79
|
+
"Timestamp",
|
|
80
|
+
"TraceId",
|
|
81
|
+
"SpanId",
|
|
82
|
+
"TraceFlags",
|
|
83
|
+
"SeverityText",
|
|
84
|
+
"SeverityNumber",
|
|
85
|
+
"ServiceName",
|
|
86
|
+
"Body",
|
|
87
|
+
"ResourceSchemaUrl",
|
|
88
|
+
"ResourceAttributes",
|
|
89
|
+
"ScopeSchemaUrl",
|
|
90
|
+
"ScopeName",
|
|
91
|
+
"ScopeVersion",
|
|
92
|
+
"ScopeAttributes",
|
|
93
|
+
"LogAttributes",
|
|
94
|
+
],
|
|
95
|
+
traces: [
|
|
96
|
+
"Timestamp",
|
|
97
|
+
"TraceId",
|
|
98
|
+
"SpanId",
|
|
99
|
+
"ParentSpanId",
|
|
100
|
+
"TraceState",
|
|
101
|
+
"SpanName",
|
|
102
|
+
"SpanKind",
|
|
103
|
+
"ServiceName",
|
|
104
|
+
"ResourceAttributes",
|
|
105
|
+
"ScopeName",
|
|
106
|
+
"ScopeVersion",
|
|
107
|
+
"SpanAttributes",
|
|
108
|
+
"Duration",
|
|
109
|
+
"StatusCode",
|
|
110
|
+
"StatusMessage",
|
|
111
|
+
"Events",
|
|
112
|
+
"Links",
|
|
113
|
+
],
|
|
114
|
+
gauge: [...METRIC_HEAD, "Value", "Flags", "Exemplars"],
|
|
115
|
+
sum: [...METRIC_HEAD, "Value", "Flags", "Exemplars", "AggregationTemporality", "IsMonotonic"],
|
|
116
|
+
summary: [...METRIC_HEAD, "Count", "Sum", "ValueAtQuantiles", "Flags"],
|
|
117
|
+
histogram: [...METRIC_HEAD, "Count", "Sum", "BucketCounts", "ExplicitBounds", "Exemplars", "Flags", "Min", "Max", "AggregationTemporality"],
|
|
118
|
+
exponential_histogram: [
|
|
119
|
+
...METRIC_HEAD,
|
|
120
|
+
"Count",
|
|
121
|
+
"Sum",
|
|
122
|
+
"Scale",
|
|
123
|
+
"ZeroCount",
|
|
124
|
+
"PositiveOffset",
|
|
125
|
+
"PositiveBucketCounts",
|
|
126
|
+
"NegativeOffset",
|
|
127
|
+
"NegativeBucketCounts",
|
|
128
|
+
"Exemplars",
|
|
129
|
+
"Flags",
|
|
130
|
+
"Min",
|
|
131
|
+
"Max",
|
|
132
|
+
"AggregationTemporality",
|
|
133
|
+
],
|
|
134
|
+
} as const satisfies Record<string, readonly string[]>;
|
|
135
|
+
|
|
136
|
+
/** The metric types in `metrics_tables`, with the suffix each default name takes. */
|
|
137
|
+
const METRIC_TYPES = [
|
|
138
|
+
["gauge", "_gauge"],
|
|
139
|
+
["sum", "_sum"],
|
|
140
|
+
["summary", "_summary"],
|
|
141
|
+
["histogram", "_histogram"],
|
|
142
|
+
["exponential_histogram", "_exponential_histogram"],
|
|
143
|
+
] as const;
|
|
144
|
+
|
|
145
|
+
const DEFAULT_DATABASE = "default";
|
|
146
|
+
const DEFAULT_METRICS_PREFIX = "otel_metrics";
|
|
147
|
+
|
|
148
|
+
const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
149
|
+
const str = (v: unknown): string | undefined => (typeof v === "string" && v !== "" ? v : undefined);
|
|
150
|
+
/** A value the collector expands from the environment or another config source. */
|
|
151
|
+
const expanded = (v: string) => v.includes("${");
|
|
152
|
+
|
|
153
|
+
/** The database in the endpoint DSN's path, or undefined when it has none or can't be read. */
|
|
154
|
+
function dsnDatabase(endpoint: string | undefined): string | undefined {
|
|
155
|
+
if (!endpoint || expanded(endpoint)) return undefined;
|
|
156
|
+
try {
|
|
157
|
+
const path = new URL(endpoint).pathname.replace(/^\/+/, "");
|
|
158
|
+
return path === "" ? undefined : decodeURIComponent(path);
|
|
159
|
+
} catch {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** The signals whose pipelines list exporter `id`. */
|
|
165
|
+
export function exporterSignals(config: CollectorConfig, id: string): Set<string> {
|
|
166
|
+
const out = new Set<string>();
|
|
167
|
+
for (const [pid, p] of Object.entries(config.service?.pipelines ?? {})) {
|
|
168
|
+
const exporters = isRecord(p) && Array.isArray(p.exporters) ? p.exporters : [];
|
|
169
|
+
if (exporters.includes(id)) out.add(pipelineSignal(pid));
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The tables one `clickhouse` exporter writes, for the signals whose
|
|
176
|
+
* pipelines use it. `raw` is its config block.
|
|
177
|
+
*/
|
|
178
|
+
export function clickhouseExporterTargets(id: string, raw: unknown, signals: ReadonlySet<string>): ClickHouseExporterTargets {
|
|
179
|
+
const c = isRecord(raw) ? raw : {};
|
|
180
|
+
const unread: string[] = [];
|
|
181
|
+
|
|
182
|
+
let database = DEFAULT_DATABASE;
|
|
183
|
+
const configured = str(c.database);
|
|
184
|
+
if (configured && expanded(configured)) unread.push(`database ${configured}`);
|
|
185
|
+
else if (configured && configured !== DEFAULT_DATABASE) database = configured;
|
|
186
|
+
else {
|
|
187
|
+
const endpoint = str(c.endpoint);
|
|
188
|
+
if (endpoint && expanded(endpoint)) unread.push(`endpoint ${endpoint}, whose path may name the database`);
|
|
189
|
+
database = dsnDatabase(endpoint) ?? DEFAULT_DATABASE;
|
|
190
|
+
}
|
|
191
|
+
if (unread.length > 0) return { id, database, createSchema: c.create_schema !== false, tables: [], unread };
|
|
192
|
+
|
|
193
|
+
const tables: ClickHouseExporterTable[] = [];
|
|
194
|
+
const add = (signal: ClickHouseExporterTable["signal"], key: string, name: string, columns: readonly string[]) => {
|
|
195
|
+
if (expanded(name)) unread.push(`${key} ${name}`);
|
|
196
|
+
else tables.push({ signal, key, name, columns });
|
|
197
|
+
};
|
|
198
|
+
if (signals.has("logs")) add("logs", "logs_table_name", str(c.logs_table_name) ?? "otel_logs", CLICKHOUSE_EXPORTER_COLUMNS.logs);
|
|
199
|
+
if (signals.has("traces")) add("traces", "traces_table_name", str(c.traces_table_name) ?? "otel_traces", CLICKHOUSE_EXPORTER_COLUMNS.traces);
|
|
200
|
+
if (signals.has("metrics")) {
|
|
201
|
+
const mt = isRecord(c.metrics_tables) ? c.metrics_tables : {};
|
|
202
|
+
const nameOf = (type: string) => (isRecord(mt[type]) ? str((mt[type] as Record<string, unknown>).name) : undefined);
|
|
203
|
+
// The deprecated metrics_table_name is a prefix, used only when no metrics_tables name is set.
|
|
204
|
+
const anySet = METRIC_TYPES.some(([type]) => nameOf(type) !== undefined);
|
|
205
|
+
const prefix = !anySet ? (str(c.metrics_table_name) ?? DEFAULT_METRICS_PREFIX) : DEFAULT_METRICS_PREFIX;
|
|
206
|
+
for (const [type, suffix] of METRIC_TYPES) {
|
|
207
|
+
add("metrics", `metrics_tables.${type}.name`, nameOf(type) ?? `${prefix}${suffix}`, CLICKHOUSE_EXPORTER_COLUMNS[type]);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return { id, database, createSchema: c.create_schema !== false, tables, unread };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Every `clickhouse` exporter a pipeline uses in `config`, with what it writes. */
|
|
214
|
+
export function clickhouseExportersOf(config: CollectorConfig): ClickHouseExporterTargets[] {
|
|
215
|
+
const out: ClickHouseExporterTargets[] = [];
|
|
216
|
+
for (const [id, raw] of Object.entries(config.exporters ?? {})) {
|
|
217
|
+
if (parseComponentId(id)?.type !== "clickhouse") continue;
|
|
218
|
+
const signals = exporterSignals(config, id);
|
|
219
|
+
if (signals.size === 0) continue;
|
|
220
|
+
out.push(clickhouseExporterTargets(id, raw, signals));
|
|
221
|
+
}
|
|
222
|
+
return out;
|
|
223
|
+
}
|
package/src/codegen/docs.ts
CHANGED
|
@@ -59,8 +59,10 @@ on the same address (OTEL117), and a literal credential in source (OTEL002)
|
|
|
59
59
|
or in the config (OTEL120). Others report deprecated fields (OTEL119),
|
|
60
60
|
credentials sent in plaintext (OTEL121), zpages or pprof off loopback
|
|
61
61
|
(OTEL122), detailed debug output beside a backend (OTEL123), delivery and
|
|
62
|
-
batching settings (OTEL124, OTEL125),
|
|
63
|
-
resourcedetection detectors the collector doesn't know (OTEL126, OTEL127)
|
|
62
|
+
batching settings (OTEL124, OTEL125), k8sattributes fields or
|
|
63
|
+
resourcedetection detectors the collector doesn't know (OTEL126, OTEL127),
|
|
64
|
+
and, when the project declares a \`Distribution\`, a component the config uses
|
|
65
|
+
that the distribution doesn't build (OTEL128). In
|
|
64
66
|
a build that stamps telemetry attribution, OTEL118 reports a processor that can
|
|
65
67
|
drop or overwrite one of the attribution's resource attributes.
|
|
66
68
|
`;
|
package/src/codegen/generate.ts
CHANGED
|
@@ -1,50 +1,126 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The otel lexicon's
|
|
2
|
+
* The otel lexicon's generation step (#3361).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* The built-in components' config types are generated from upstream
|
|
5
|
+
* `config.schema.yaml`, the documents `schemagen` writes next to each
|
|
6
|
+
* component's `config.go`, at the collector-contrib release `COLLECTOR_PIN`
|
|
7
|
+
* names and scoped by the `otelcol-contrib` distribution manifest. Generation
|
|
8
|
+
* reads the committed snapshot (`src/spec/otel-schemas.snapshot.json`, refreshed
|
|
9
|
+
* by `just snapshot`), refuses one that does not match `OTEL_SPEC_PIN`, and
|
|
10
|
+
* writes, into the gitignored `src/generated/`:
|
|
11
|
+
*
|
|
12
|
+
* - `index.ts`: a type alias per schema definition the built-ins reach, and
|
|
13
|
+
* `<ClassName>SchemaConfig` for each built-in that has a schema. The
|
|
14
|
+
* hand-written `defineBuiltin` files build their config types on these,
|
|
15
|
+
* overlaying only what a schema lacks (see `src/components/overlay.ts`);
|
|
16
|
+
* - `properties.json`: each built-in's property tree with upstream's
|
|
17
|
+
* descriptions, for LSP completion and hover;
|
|
18
|
+
* - `lexicon-otel.json`: the registry, derived from the exported classes.
|
|
19
|
+
*
|
|
20
|
+
* A built-in with no upstream schema (`forward`, which has no config) keeps its
|
|
21
|
+
* hand-written type.
|
|
10
22
|
*/
|
|
11
23
|
|
|
12
24
|
import { dirname, join } from "path";
|
|
13
25
|
import { fileURLToPath } from "url";
|
|
14
26
|
import { mkdirSync, writeFileSync } from "fs";
|
|
15
27
|
import type { GenerateResult } from "@intentius/chant/codegen/generate";
|
|
16
|
-
import {
|
|
28
|
+
import { loadSnapshot } from "../spec/snapshot";
|
|
29
|
+
import { assertPinnedSnapshot, assertSnapshotVersions } from "../spec/pin";
|
|
30
|
+
import { generateTypes, propertyDocs, type PropertyDoc } from "../spec/parse";
|
|
31
|
+
import { BUILTIN_SPECS } from "../spec/builtins";
|
|
32
|
+
import type { OtelSpecSnapshot } from "../spec/fetch";
|
|
17
33
|
|
|
18
34
|
export type { GenerateResult };
|
|
19
35
|
|
|
20
36
|
/** The packaged types entry re-exports the compiled declarations, which carry every config type. */
|
|
21
|
-
const TYPES_DTS = `// The otel lexicon's entity classes and config types are
|
|
22
|
-
//
|
|
37
|
+
const TYPES_DTS = `// The otel lexicon's entity classes and config types are compiled to
|
|
38
|
+
// dist/index.d.ts (config types generated from upstream config.schema.yaml);
|
|
39
|
+
// this entry re-exports them.
|
|
23
40
|
export * from "../index";
|
|
24
41
|
`;
|
|
25
42
|
|
|
26
|
-
|
|
43
|
+
/** The upstream schema document behind each built-in, by class name, from the contrib index. */
|
|
44
|
+
export function builtinSchemaDocs(snapshot: OtelSpecSnapshot): Map<string, string> {
|
|
45
|
+
const out = new Map<string, string>();
|
|
46
|
+
const index = snapshot.distributions["otelcol-contrib"];
|
|
47
|
+
for (const b of BUILTIN_SPECS) {
|
|
48
|
+
const hit = index.find((c) => c.kind === b.kind && (c.type === b.type || c.deprecatedType === b.type));
|
|
49
|
+
if (hit?.schema && snapshot.schemas[hit.schema]) out.set(b.className, hit.schema);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface OtelGenerated extends GenerateResult {
|
|
55
|
+
/** Built-in class name → its property tree. */
|
|
56
|
+
propertiesJSON: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function generate(opts?: { verbose?: boolean; force?: boolean }): Promise<OtelGenerated> {
|
|
60
|
+
// The registry is derived from the classes, which import the generated
|
|
61
|
+
// types; types are erased at runtime, so this import does not need them.
|
|
62
|
+
const { BUILTIN_CATALOG, lexiconRegistry } = await import("../catalog");
|
|
63
|
+
const snapshot = loadSnapshot();
|
|
64
|
+
assertSnapshotVersions(snapshot.versions);
|
|
65
|
+
assertPinnedSnapshot(snapshot);
|
|
66
|
+
|
|
67
|
+
const roots = builtinSchemaDocs(snapshot);
|
|
68
|
+
const generated = generateTypes(snapshot.schemas, [...new Set(roots.values())]);
|
|
69
|
+
const aliases = [...roots]
|
|
70
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
71
|
+
.map(([className, doc]) => `/** \`${className}\`'s config, from \`${doc}\`. */\nexport type ${className}SchemaConfig = ${generated.roots.get(doc)};\n`)
|
|
72
|
+
.join("\n");
|
|
73
|
+
|
|
74
|
+
const unresolved = [...generated.unresolved.keys()].sort();
|
|
75
|
+
const indexTS = [
|
|
76
|
+
"// Generated by `npm run generate` from src/spec/otel-schemas.snapshot.json. Do not edit.",
|
|
77
|
+
`// Versions: ${Object.entries(snapshot.versions).map(([k, v]) => `${k} ${v}`).join(", ")}.`,
|
|
78
|
+
...(unresolved.length > 0
|
|
79
|
+
? ["// Upstream publishes no schema for these $refs, so they are typed `unknown`:", ...unresolved.map((u) => `// ${u}`)]
|
|
80
|
+
: []),
|
|
81
|
+
"",
|
|
82
|
+
'import type { Duration } from "../components/common";',
|
|
83
|
+
"",
|
|
84
|
+
generated.declarations,
|
|
85
|
+
"// ── Built-in config types ──────────────────────────────────────────",
|
|
86
|
+
"",
|
|
87
|
+
aliases,
|
|
88
|
+
].join("\n");
|
|
89
|
+
|
|
90
|
+
const properties: Record<string, Record<string, PropertyDoc>> = {};
|
|
91
|
+
let propertyCount = 0;
|
|
92
|
+
for (const [className, doc] of [...roots].sort(([a], [b]) => a.localeCompare(b))) {
|
|
93
|
+
properties[className] = propertyDocs(snapshot.schemas, doc);
|
|
94
|
+
propertyCount += Object.keys(properties[className]).length;
|
|
95
|
+
}
|
|
96
|
+
|
|
27
97
|
const registry = lexiconRegistry();
|
|
28
|
-
const lexiconJSON = `${JSON.stringify(registry, null, 2)}\n`;
|
|
29
|
-
const components = BUILTIN_CATALOG.filter((c) => c.type !== undefined).length;
|
|
30
98
|
if (opts?.verbose) {
|
|
31
|
-
|
|
99
|
+
const components = BUILTIN_CATALOG.filter((c) => c.type !== undefined).length;
|
|
100
|
+
console.error(
|
|
101
|
+
`otel: ${components} built-in components, ${roots.size} typed from upstream config.schema.yaml ` +
|
|
102
|
+
`(${snapshot.versions["otelcol-contrib"]}), plus Pipeline and Service (${BUILTIN_CATALOG.length} entities)`,
|
|
103
|
+
);
|
|
104
|
+
if (unresolved.length > 0) console.error(`otel: ${unresolved.length} upstream $refs have no schema and are typed unknown`);
|
|
32
105
|
}
|
|
33
106
|
return {
|
|
34
|
-
lexiconJSON,
|
|
107
|
+
lexiconJSON: `${JSON.stringify(registry, null, 2)}\n`,
|
|
35
108
|
typesDTS: TYPES_DTS,
|
|
36
|
-
indexTS
|
|
109
|
+
indexTS,
|
|
110
|
+
propertiesJSON: `${JSON.stringify(properties)}\n`,
|
|
37
111
|
resources: BUILTIN_CATALOG.length,
|
|
38
|
-
properties:
|
|
112
|
+
properties: propertyCount,
|
|
39
113
|
enums: 0,
|
|
40
114
|
warnings: [],
|
|
41
115
|
};
|
|
42
116
|
}
|
|
43
117
|
|
|
44
|
-
/** Write the
|
|
45
|
-
export function writeGeneratedFiles(result:
|
|
118
|
+
/** Write the generated files to src/generated/. */
|
|
119
|
+
export function writeGeneratedFiles(result: OtelGenerated): void {
|
|
46
120
|
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
47
121
|
const dir = join(pkgDir, "src", "generated");
|
|
48
122
|
mkdirSync(dir, { recursive: true });
|
|
49
123
|
writeFileSync(join(dir, "lexicon-otel.json"), result.lexiconJSON);
|
|
124
|
+
writeFileSync(join(dir, "index.ts"), result.indexTS);
|
|
125
|
+
writeFileSync(join(dir, "properties.json"), result.propertiesJSON);
|
|
50
126
|
}
|
package/src/components/common.ts
CHANGED
|
@@ -176,8 +176,10 @@ export interface QueueSettings {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/** Problems in the `sending_queue` of an exporter's `exporterhelper` settings. */
|
|
179
|
-
export function queueIssues(c:
|
|
180
|
-
|
|
179
|
+
export function queueIssues(c: { sending_queue?: unknown }): string[] {
|
|
180
|
+
// `blocking` is not an upstream field; reading it through the hand-written
|
|
181
|
+
// shape is how a config that sets it anyway gets told so.
|
|
182
|
+
const q = c.sending_queue as QueueSettings | null | undefined;
|
|
181
183
|
if (!q) return [];
|
|
182
184
|
const issues: string[] = [];
|
|
183
185
|
if (q.blocking !== undefined) {
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { defineBuiltin } from "../define";
|
|
12
|
+
import type { Overlay, Require } from "./overlay";
|
|
13
|
+
import type { CountConnectorSchemaConfig, RoutingConnectorSchemaConfig, ServiceGraphConnectorSchemaConfig, SignalToMetricsConnectorSchemaConfig, SpanMetricsConnectorSchemaConfig, SumConnectorSchemaConfig } from "../generated/index";
|
|
12
14
|
import type { ConnectorSignalPair } from "../model";
|
|
13
|
-
import type { Duration } from "./common";
|
|
14
15
|
|
|
15
16
|
const SAME_SIGNAL: ConnectorSignalPair[] = [
|
|
16
17
|
{ from: "traces", to: "traces" },
|
|
@@ -27,39 +28,7 @@ export interface SpanMetricsDimension {
|
|
|
27
28
|
default?: string;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
export
|
|
31
|
-
/** Extra dimensions on every metric, beyond service.name, span.name, span.kind and status.code. */
|
|
32
|
-
dimensions?: SpanMetricsDimension[];
|
|
33
|
-
/** Extra dimensions on the calls metric only. */
|
|
34
|
-
calls_dimensions?: SpanMetricsDimension[];
|
|
35
|
-
/** Default dimensions to leave out. */
|
|
36
|
-
exclude_dimensions?: string[];
|
|
37
|
-
resource_metrics_cache_size?: number;
|
|
38
|
-
/** Resource attributes that key the metrics' resource, so a restart doesn't start a new series. */
|
|
39
|
-
resource_metrics_key_attributes?: string[];
|
|
40
|
-
aggregation_temporality?: "AGGREGATION_TEMPORALITY_CUMULATIVE" | "AGGREGATION_TEMPORALITY_DELTA";
|
|
41
|
-
histogram?: {
|
|
42
|
-
disable?: boolean;
|
|
43
|
-
unit?: "ms" | "s";
|
|
44
|
-
/** Explicit bucket boundaries. Set this or `exponential`, not both. */
|
|
45
|
-
explicit?: { buckets?: Duration[] };
|
|
46
|
-
exponential?: { max_size?: number };
|
|
47
|
-
/** Extra dimensions on the duration histogram only. */
|
|
48
|
-
dimensions?: SpanMetricsDimension[];
|
|
49
|
-
};
|
|
50
|
-
/** How often metrics are emitted (default 60s). */
|
|
51
|
-
metrics_flush_interval?: Duration;
|
|
52
|
-
/** Drop a series not updated for this long. */
|
|
53
|
-
metrics_expiration?: Duration;
|
|
54
|
-
metric_timestamp_cache_size?: number;
|
|
55
|
-
/** Prefix for the emitted metric names (default `traces.span.metrics`). */
|
|
56
|
-
namespace?: string;
|
|
57
|
-
exemplars?: { enabled?: boolean; max_per_data_point?: number };
|
|
58
|
-
/** Also count span events. Needs `dimensions` when enabled. */
|
|
59
|
-
events?: { enabled?: boolean; dimensions?: SpanMetricsDimension[] };
|
|
60
|
-
include_instrumentation_scope?: string[];
|
|
61
|
-
aggregation_cardinality_limit?: number;
|
|
62
|
-
}
|
|
31
|
+
export type SpanMetricsConnectorConfig = SpanMetricsConnectorSchemaConfig;
|
|
63
32
|
|
|
64
33
|
/** Turns spans into request, error and duration (RED) metrics. */
|
|
65
34
|
export const SpanMetricsConnector = defineBuiltin<SpanMetricsConnectorConfig, "connector", "spanmetrics">({
|
|
@@ -77,6 +46,8 @@ export const SpanMetricsConnector = defineBuiltin<SpanMetricsConnectorConfig, "c
|
|
|
77
46
|
}
|
|
78
47
|
const reserved = new Set(["service.name", "span.name", "span.kind", "status.code"]);
|
|
79
48
|
for (const d of c.dimensions ?? []) {
|
|
49
|
+
// A dimension names one attribute or matches several by `glob`.
|
|
50
|
+
if (d.name === undefined) continue;
|
|
80
51
|
if (reserved.has(d.name)) problems.push(`dimensions: "${d.name}" is already a default dimension`);
|
|
81
52
|
reserved.add(d.name);
|
|
82
53
|
}
|
|
@@ -86,21 +57,7 @@ export const SpanMetricsConnector = defineBuiltin<SpanMetricsConnectorConfig, "c
|
|
|
86
57
|
|
|
87
58
|
// ── servicegraph ─────────────────────────────────────────────────────
|
|
88
59
|
|
|
89
|
-
export
|
|
90
|
-
latency_histogram_buckets?: Duration[];
|
|
91
|
-
/** Span attributes added as dimensions on the edge metrics. */
|
|
92
|
-
dimensions?: string[];
|
|
93
|
-
/** How long an unpaired client or server span waits for its other half. */
|
|
94
|
-
store?: { ttl?: Duration; max_items?: number };
|
|
95
|
-
cache_loop?: Duration;
|
|
96
|
-
store_expiration_loop?: Duration;
|
|
97
|
-
/** Attributes that name the peer when only one side of a call is instrumented. */
|
|
98
|
-
virtual_node_peer_attributes?: string[];
|
|
99
|
-
virtual_node_extra_label?: boolean;
|
|
100
|
-
metrics_flush_interval?: Duration;
|
|
101
|
-
/** Attributes that name the database for a database call edge. */
|
|
102
|
-
database_name_attributes?: string[];
|
|
103
|
-
}
|
|
60
|
+
export type ServiceGraphConnectorConfig = ServiceGraphConnectorSchemaConfig;
|
|
104
61
|
|
|
105
62
|
/** Builds service-to-service edge metrics from paired client and server spans. */
|
|
106
63
|
export const ServiceGraphConnector = defineBuiltin<ServiceGraphConnectorConfig, "connector", "servicegraph">({
|
|
@@ -113,7 +70,12 @@ export const ServiceGraphConnector = defineBuiltin<ServiceGraphConnectorConfig,
|
|
|
113
70
|
// ── routing ──────────────────────────────────────────────────────────
|
|
114
71
|
|
|
115
72
|
export interface RoutingTableItem {
|
|
116
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* The OTTL context the condition runs in. `request` routes on request
|
|
75
|
+
* metadata such as headers; it is deprecated since collector-contrib
|
|
76
|
+
* v0.156.0 for `otelcol.client.metadata[...]` and `otelcol.grpc.metadata[...]`
|
|
77
|
+
* paths, which work in every context.
|
|
78
|
+
*/
|
|
117
79
|
context?: "resource" | "span" | "metric" | "datapoint" | "log" | "request";
|
|
118
80
|
/** An OTTL `route() where ...` statement. Set this or `condition`, not both. */
|
|
119
81
|
statement?: string;
|
|
@@ -123,12 +85,8 @@ export interface RoutingTableItem {
|
|
|
123
85
|
pipelines: string[];
|
|
124
86
|
}
|
|
125
87
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
/** Pipelines for data no route matches. */
|
|
129
|
-
default_pipelines?: string[];
|
|
130
|
-
error_mode?: "ignore" | "silent" | "propagate";
|
|
131
|
-
}
|
|
88
|
+
/** The connector refuses to start with no routing table. */
|
|
89
|
+
export type RoutingConnectorConfig = Require<RoutingConnectorSchemaConfig, "table">;
|
|
132
90
|
|
|
133
91
|
/** Sends each item to the pipelines whose route matches it. */
|
|
134
92
|
export const RoutingConnector = defineBuiltin<RoutingConnectorConfig, "connector", "routing">({
|
|
@@ -172,14 +130,7 @@ export interface CountMetricInfo {
|
|
|
172
130
|
}
|
|
173
131
|
|
|
174
132
|
/** Each key is the name of a metric to emit. */
|
|
175
|
-
export
|
|
176
|
-
spans?: Record<string, CountMetricInfo>;
|
|
177
|
-
spanevents?: Record<string, CountMetricInfo>;
|
|
178
|
-
metrics?: Record<string, CountMetricInfo>;
|
|
179
|
-
datapoints?: Record<string, CountMetricInfo>;
|
|
180
|
-
logs?: Record<string, CountMetricInfo>;
|
|
181
|
-
profiles?: Record<string, CountMetricInfo>;
|
|
182
|
-
}
|
|
133
|
+
export type CountConnectorConfig = CountConnectorSchemaConfig;
|
|
183
134
|
|
|
184
135
|
/** Counts spans, span events, metrics, data points or log records, as metrics. */
|
|
185
136
|
export const CountConnector = defineBuiltin<CountConnectorConfig, "connector", "count">({
|
|
@@ -229,13 +180,7 @@ export interface SumMetricInfo {
|
|
|
229
180
|
* while an exporter that needs cumulative input wants a `deltatocumulative`
|
|
230
181
|
* processor in front of it.
|
|
231
182
|
*/
|
|
232
|
-
export
|
|
233
|
-
spans?: Record<string, SumMetricInfo>;
|
|
234
|
-
spanevents?: Record<string, SumMetricInfo>;
|
|
235
|
-
metrics?: Record<string, SumMetricInfo>;
|
|
236
|
-
datapoints?: Record<string, SumMetricInfo>;
|
|
237
|
-
logs?: Record<string, SumMetricInfo>;
|
|
238
|
-
}
|
|
183
|
+
export type SumConnectorConfig = SumConnectorSchemaConfig;
|
|
239
184
|
|
|
240
185
|
/** Sums a numeric attribute of spans, span events, data points or log records, as metrics. */
|
|
241
186
|
export const SumConnector = defineBuiltin<SumConnectorConfig, "connector", "sum">({
|
|
@@ -383,12 +328,20 @@ export type SignalToMetricsMetric = SignalToMetricsMetricBase &
|
|
|
383
328
|
* exporter that needs cumulative input (Prometheus remote write) wants a
|
|
384
329
|
* `deltatocumulative` processor in front of it.
|
|
385
330
|
*/
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
331
|
+
/**
|
|
332
|
+
* Upstream writes a metric as one struct with `sum`, `gauge`, `histogram` and
|
|
333
|
+
* `exponential_histogram` all optional; the connector takes exactly one, so
|
|
334
|
+
* here each entry is a union with one metric type set.
|
|
335
|
+
*/
|
|
336
|
+
export type SignalToMetricsConnectorConfig = Overlay<
|
|
337
|
+
SignalToMetricsConnectorSchemaConfig,
|
|
338
|
+
{
|
|
339
|
+
spans?: SignalToMetricsMetric[];
|
|
340
|
+
datapoints?: SignalToMetricsMetric[];
|
|
341
|
+
logs?: SignalToMetricsMetric[];
|
|
342
|
+
profiles?: SignalToMetricsMetric[];
|
|
343
|
+
}
|
|
344
|
+
>;
|
|
392
345
|
|
|
393
346
|
/** One entry of a `signaltometrics` config, with where it sits. */
|
|
394
347
|
export interface SignalToMetricsEntry {
|