@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,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTEL128: The collector config uses a component the declared Distribution does not build
|
|
3
|
+
*
|
|
4
|
+
* When a project declares a `Distribution` (an ocb builder manifest), every component a collector config declares must be one the distribution builds; a collector built from it fails at start with "unknown type" otherwise. A project without a `Distribution` is not checked.
|
|
5
|
+
*/
|
|
6
|
+
import { distributionIssues, isDistributionEntity } from "../../distribution.js";
|
|
7
|
+
import { collectorConfigs, toDiagnostic } from "./otel-helpers.js";
|
|
8
|
+
export const otel128 = {
|
|
9
|
+
id: "OTEL128",
|
|
10
|
+
description: "The collector config uses a component the declared Distribution does not build",
|
|
11
|
+
check(ctx) {
|
|
12
|
+
const dist = [...(ctx.entities?.values() ?? [])].find(isDistributionEntity);
|
|
13
|
+
if (!dist)
|
|
14
|
+
return [];
|
|
15
|
+
return collectorConfigs(ctx).flatMap(({ config, ...found }) => distributionIssues(config, dist).map((i) => toDiagnostic(i, found)));
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTEL129: A clickhouse exporter writes a table the sql build in the same root does not declare
|
|
3
|
+
*
|
|
4
|
+
* When the build root also declares ClickHouse tables with the sql lexicon, every table a `clickhouse` exporter writes (for the signals whose pipelines use it) must be one of them, in the database the exporter writes to, with every column the exporter's insert statement names. A renamed or dropped table fails here instead of at the exporter's first insert. When `create_schema` is true (the exporter's default) for tables the build declares, it warns: the exporter would run its own `CREATE TABLE IF NOT EXISTS` beside the sql lexicon's plan. A build root with no sql ClickHouse tables is not checked. Sees one build root at a time (#1939); across workspace members the otel lexicon's workspace links check the same tables (#3931).
|
|
5
|
+
*/
|
|
6
|
+
import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
|
|
7
|
+
import type { Declarable } from "@intentius/chant/declarable";
|
|
8
|
+
interface DeclaredTable {
|
|
9
|
+
columns: Set<string>;
|
|
10
|
+
}
|
|
11
|
+
/** Every ClickHouse table the build declares, by `database.name`. */
|
|
12
|
+
export declare function declaredClickHouseTables(entities: Iterable<Declarable>): Map<string, DeclaredTable>;
|
|
13
|
+
export declare const otel129: PostSynthCheck;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=otel129.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel129.d.ts","sourceRoot":"","sources":["../../../src/lint/post-synth/otel129.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kCAAkC,CAAC;AAC9G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAO9D,UAAU,aAAa;IACrB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACtB;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAenG;AASD,eAAO,MAAM,OAAO,EAAE,cAuDrB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTEL129: A clickhouse exporter writes a table the sql build in the same root does not declare
|
|
3
|
+
*
|
|
4
|
+
* When the build root also declares ClickHouse tables with the sql lexicon, every table a `clickhouse` exporter writes (for the signals whose pipelines use it) must be one of them, in the database the exporter writes to, with every column the exporter's insert statement names. A renamed or dropped table fails here instead of at the exporter's first insert. When `create_schema` is true (the exporter's default) for tables the build declares, it warns: the exporter would run its own `CREATE TABLE IF NOT EXISTS` beside the sql lexicon's plan. A build root with no sql ClickHouse tables is not checked. Sees one build root at a time (#1939); across workspace members the otel lexicon's workspace links check the same tables (#3931).
|
|
5
|
+
*/
|
|
6
|
+
import { clickhouseExportersOf } from "../../clickhouse-tables.js";
|
|
7
|
+
import { collectorConfigs } from "./otel-helpers.js";
|
|
8
|
+
/** The sql lexicon's ClickHouse table entity type, matched by name so otel needs no dependency on the sql lexicon. */
|
|
9
|
+
const CLICKHOUSE_TABLE = "ClickHouse::Table";
|
|
10
|
+
/** Every ClickHouse table the build declares, by `database.name`. */
|
|
11
|
+
export function declaredClickHouseTables(entities) {
|
|
12
|
+
const out = new Map();
|
|
13
|
+
for (const e of entities) {
|
|
14
|
+
if (e.entityType !== CLICKHOUSE_TABLE)
|
|
15
|
+
continue;
|
|
16
|
+
const props = e.props;
|
|
17
|
+
if (typeof props?.name !== "string")
|
|
18
|
+
continue;
|
|
19
|
+
const database = typeof props.database === "string" && props.database !== "" ? props.database : "default";
|
|
20
|
+
const columns = new Set();
|
|
21
|
+
for (const c of Array.isArray(props.columns) ? props.columns : []) {
|
|
22
|
+
const name = c?.name;
|
|
23
|
+
if (typeof name === "string")
|
|
24
|
+
columns.add(name);
|
|
25
|
+
}
|
|
26
|
+
out.set(`${database}.${props.name}`, { columns });
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
/** A column the insert names is declared as itself, or as the flattened fields of a Nested column (`Events.Timestamp`). */
|
|
31
|
+
function hasColumn(declared, column) {
|
|
32
|
+
if (declared.has(column))
|
|
33
|
+
return true;
|
|
34
|
+
for (const c of declared)
|
|
35
|
+
if (c.startsWith(`${column}.`))
|
|
36
|
+
return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
export const otel129 = {
|
|
40
|
+
id: "OTEL129",
|
|
41
|
+
description: "A clickhouse exporter writes a table the sql build in the same root does not declare",
|
|
42
|
+
check(ctx) {
|
|
43
|
+
const declared = declaredClickHouseTables(ctx.entities?.values() ?? []);
|
|
44
|
+
if (declared.size === 0)
|
|
45
|
+
return [];
|
|
46
|
+
const known = [...declared.keys()].sort();
|
|
47
|
+
const diagnostics = [];
|
|
48
|
+
for (const { config } of collectorConfigs(ctx)) {
|
|
49
|
+
for (const exp of clickhouseExportersOf(config)) {
|
|
50
|
+
const createsDeclared = [];
|
|
51
|
+
for (const t of exp.tables) {
|
|
52
|
+
const qualified = `${exp.database}.${t.name}`;
|
|
53
|
+
const table = declared.get(qualified);
|
|
54
|
+
if (!table) {
|
|
55
|
+
diagnostics.push({
|
|
56
|
+
checkId: "OTEL129",
|
|
57
|
+
severity: "error",
|
|
58
|
+
message: `exporter ${exp.id} writes ${t.signal} to ${qualified} (${t.key}), which the sql build does not declare. ` +
|
|
59
|
+
`Declare it (OtelTables from @intentius/chant-lexicon-sql/clickhouse declares the exporter's tables) or point ${t.key} at a declared table. ` +
|
|
60
|
+
`Declared ClickHouse tables: ${known.join(", ")}`,
|
|
61
|
+
entity: exp.id,
|
|
62
|
+
lexicon: "otel",
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const missing = t.columns.filter((c) => !hasColumn(table.columns, c));
|
|
67
|
+
if (missing.length > 0) {
|
|
68
|
+
diagnostics.push({
|
|
69
|
+
checkId: "OTEL129",
|
|
70
|
+
severity: "error",
|
|
71
|
+
message: `exporter ${exp.id} inserts ${t.signal} into ${qualified} with column${missing.length === 1 ? "" : "s"} ${missing.join(", ")}, which the declared table does not have; the insert would fail`,
|
|
72
|
+
entity: exp.id,
|
|
73
|
+
lexicon: "otel",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
createsDeclared.push(qualified);
|
|
77
|
+
}
|
|
78
|
+
if (exp.createSchema && createsDeclared.length > 0) {
|
|
79
|
+
diagnostics.push({
|
|
80
|
+
checkId: "OTEL129",
|
|
81
|
+
severity: "warning",
|
|
82
|
+
message: `exporter ${exp.id} has create_schema true (the default), so at start it runs CREATE TABLE IF NOT EXISTS for ${createsDeclared.join(", ")}, which the sql build declares. ` +
|
|
83
|
+
`Set create_schema: false so the sql lexicon alone manages them`,
|
|
84
|
+
entity: exp.id,
|
|
85
|
+
lexicon: "otel",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return diagnostics;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { CompletionContext, CompletionItem } from "@intentius/chant/lsp/types";
|
|
2
|
-
/**
|
|
2
|
+
/** The text of `content` before the cursor. */
|
|
3
|
+
export declare function textBefore(content: string, position: {
|
|
4
|
+
line: number;
|
|
5
|
+
character: number;
|
|
6
|
+
}): string;
|
|
7
|
+
/**
|
|
8
|
+
* Completions for the otel entity classes after `new`, and inside a built-in's
|
|
9
|
+
* constructor, the config properties at the cursor's depth, with upstream's
|
|
10
|
+
* descriptions (#3361).
|
|
11
|
+
*/
|
|
3
12
|
export declare function completions(ctx: CompletionContext): CompletionItem[];
|
|
4
13
|
//# sourceMappingURL=completions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completions.d.ts","sourceRoot":"","sources":["../../src/lsp/completions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"completions.d.ts","sourceRoot":"","sources":["../../src/lsp/completions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAYpF,+CAA+C;AAC/C,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGjG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAoBpE"}
|
package/dist/lsp/completions.js
CHANGED
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
import { LexiconIndex, lexiconCompletions } from "@intentius/chant/lsp/lexicon-providers";
|
|
2
2
|
import { lexiconRegistry } from "../catalog.js";
|
|
3
|
+
import { propertiesAt, propertyMarkdown, propertyPosition } from "./properties.js";
|
|
3
4
|
let cachedIndex = null;
|
|
4
5
|
function getIndex() {
|
|
5
6
|
cachedIndex ?? (cachedIndex = new LexiconIndex(lexiconRegistry()));
|
|
6
7
|
return cachedIndex;
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
+
/** The text of `content` before the cursor. */
|
|
10
|
+
export function textBefore(content, position) {
|
|
11
|
+
const lines = content.split("\n");
|
|
12
|
+
return [...lines.slice(0, position.line), (lines[position.line] ?? "").slice(0, position.character)].join("\n");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Completions for the otel entity classes after `new`, and inside a built-in's
|
|
16
|
+
* constructor, the config properties at the cursor's depth, with upstream's
|
|
17
|
+
* descriptions (#3361).
|
|
18
|
+
*/
|
|
9
19
|
export function completions(ctx) {
|
|
20
|
+
if (ctx?.content && ctx.position && !/\bnew\s+\w*$/.test(ctx.linePrefix ?? "")) {
|
|
21
|
+
const position = propertyPosition(textBefore(ctx.content, ctx.position));
|
|
22
|
+
const props = position && propertiesAt(position);
|
|
23
|
+
if (position && props) {
|
|
24
|
+
const prefix = (ctx.wordAtCursor ?? "").toLowerCase();
|
|
25
|
+
return Object.entries(props)
|
|
26
|
+
.filter(([name]) => name.toLowerCase().startsWith(prefix))
|
|
27
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
28
|
+
.map(([name, doc]) => ({
|
|
29
|
+
label: name,
|
|
30
|
+
insertText: name,
|
|
31
|
+
kind: "property",
|
|
32
|
+
detail: doc.type,
|
|
33
|
+
documentation: propertyMarkdown(name, doc, position.className),
|
|
34
|
+
...(doc.deprecated ? { deprecated: true } : {}),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
10
38
|
return lexiconCompletions(ctx, getIndex(), "OpenTelemetry Collector entity");
|
|
11
39
|
}
|
package/dist/lsp/hover.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Hover for otel entity classes (what the component does and its collector
|
|
4
|
+
* id), and for a config property inside a built-in's constructor (upstream's
|
|
5
|
+
* description, #3361).
|
|
6
|
+
*/
|
|
3
7
|
export declare function hover(ctx: HoverContext): HoverInfo | undefined;
|
|
4
8
|
//# sourceMappingURL=hover.d.ts.map
|
package/dist/lsp/hover.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../src/lsp/hover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"hover.d.ts","sourceRoot":"","sources":["../../src/lsp/hover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAc1E;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,CAO9D"}
|
package/dist/lsp/hover.js
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { LexiconIndex, lexiconHover } from "@intentius/chant/lsp/lexicon-providers";
|
|
2
2
|
import { BUILTIN_CATALOG, lexiconRegistry } from "../catalog.js";
|
|
3
3
|
import { COLLECTOR_PIN } from "../define.js";
|
|
4
|
+
import { propertiesAt, propertyMarkdown, propertyPosition } from "./properties.js";
|
|
5
|
+
import { textBefore } from "./completions.js";
|
|
4
6
|
let cachedIndex = null;
|
|
5
7
|
function getIndex() {
|
|
6
8
|
cachedIndex ?? (cachedIndex = new LexiconIndex(lexiconRegistry()));
|
|
7
9
|
return cachedIndex;
|
|
8
10
|
}
|
|
9
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Hover for otel entity classes (what the component does and its collector
|
|
13
|
+
* id), and for a config property inside a built-in's constructor (upstream's
|
|
14
|
+
* description, #3361).
|
|
15
|
+
*/
|
|
10
16
|
export function hover(ctx) {
|
|
11
|
-
|
|
17
|
+
const entity = lexiconHover(ctx, getIndex(), resourceHover);
|
|
18
|
+
if (entity)
|
|
19
|
+
return entity;
|
|
20
|
+
if (!ctx?.content || !ctx.position || !ctx.word)
|
|
21
|
+
return undefined;
|
|
22
|
+
const position = propertyPosition(textBefore(ctx.content, ctx.position));
|
|
23
|
+
const doc = position && propertiesAt(position)?.[ctx.word];
|
|
24
|
+
return position && doc ? { contents: propertyMarkdown(ctx.word, doc, position.className) } : undefined;
|
|
12
25
|
}
|
|
13
26
|
function resourceHover(className, entry) {
|
|
14
27
|
const cat = BUILTIN_CATALOG.find((c) => c.className === className);
|
|
@@ -17,7 +30,7 @@ function resourceHover(className, entry) {
|
|
|
17
30
|
lines.push("", cat.description);
|
|
18
31
|
if (cat?.type) {
|
|
19
32
|
lines.push("", `Collector id \`${cat.type}\`, or \`${cat.type}/<name>\` with \`name\` set. ` +
|
|
20
|
-
`Config typed
|
|
33
|
+
`Config typed from upstream config.schema.yaml at ${COLLECTOR_PIN.source} ${COLLECTOR_PIN.version}.`);
|
|
21
34
|
}
|
|
22
35
|
return { contents: lines.join("\n") };
|
|
23
36
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-level completion and hover for the built-in components (#3361),
|
|
3
|
+
* from the descriptions in upstream's `config.schema.yaml`.
|
|
4
|
+
*
|
|
5
|
+
* Generation writes each built-in's property tree to
|
|
6
|
+
* `src/generated/properties.json`. Inside `new OtlpReceiver({ … })` the
|
|
7
|
+
* cursor's position is resolved to a path of keys (`protocols.grpc`), and the
|
|
8
|
+
* properties at that path are offered, with upstream's description and a short
|
|
9
|
+
* type. A word under the cursor at such a position hovers with the same text.
|
|
10
|
+
*/
|
|
11
|
+
import type { PropertyDoc } from "../spec/parse.js";
|
|
12
|
+
type PropertyTrees = Record<string, Record<string, PropertyDoc>>;
|
|
13
|
+
/** The generated property trees, or an empty set before `generate` has run. */
|
|
14
|
+
export declare function propertyTrees(): PropertyTrees;
|
|
15
|
+
/** Test seam: replace the loaded trees. */
|
|
16
|
+
export declare function setPropertyTrees(trees: PropertyTrees | undefined): void;
|
|
17
|
+
/** Where the cursor is inside a constructor's config object. */
|
|
18
|
+
export interface PropertyPosition {
|
|
19
|
+
className: string;
|
|
20
|
+
/** The keys of the objects enclosing the cursor, outermost first. */
|
|
21
|
+
path: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the text before the cursor to the built-in whose constructor
|
|
25
|
+
* argument holds it and the keys of the objects around it. Undefined when the
|
|
26
|
+
* cursor is not inside `new X({ … })`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function propertyPosition(before: string): PropertyPosition | undefined;
|
|
29
|
+
/** The properties at a path of a built-in's tree, or undefined when the path leaves it. */
|
|
30
|
+
export declare function propertiesAt(position: PropertyPosition): Record<string, PropertyDoc> | undefined;
|
|
31
|
+
/** Markdown for one property: its type, deprecation and upstream description. */
|
|
32
|
+
export declare function propertyMarkdown(name: string, doc: PropertyDoc, className: string): string;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=properties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../../src/lsp/properties.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAIjE,+EAA+E;AAC/E,wBAAgB,aAAa,IAAI,aAAa,CAK7C;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAEvE;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAsE7E;AASD,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,CAOhG;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-level completion and hover for the built-in components (#3361),
|
|
3
|
+
* from the descriptions in upstream's `config.schema.yaml`.
|
|
4
|
+
*
|
|
5
|
+
* Generation writes each built-in's property tree to
|
|
6
|
+
* `src/generated/properties.json`. Inside `new OtlpReceiver({ … })` the
|
|
7
|
+
* cursor's position is resolved to a path of keys (`protocols.grpc`), and the
|
|
8
|
+
* properties at that path are offered, with upstream's description and a short
|
|
9
|
+
* type. A word under the cursor at such a position hovers with the same text.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from "fs";
|
|
12
|
+
import { dirname, join } from "path";
|
|
13
|
+
import { moduleSourceDir } from "@intentius/chant/module-source";
|
|
14
|
+
let cached;
|
|
15
|
+
/** The generated property trees, or an empty set before `generate` has run. */
|
|
16
|
+
export function propertyTrees() {
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
const file = join(dirname(moduleSourceDir(import.meta.url)), "generated", "properties.json");
|
|
20
|
+
cached = existsSync(file) ? JSON.parse(readFileSync(file, "utf-8")) : {};
|
|
21
|
+
return cached;
|
|
22
|
+
}
|
|
23
|
+
/** Test seam: replace the loaded trees. */
|
|
24
|
+
export function setPropertyTrees(trees) {
|
|
25
|
+
cached = trees;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the text before the cursor to the built-in whose constructor
|
|
29
|
+
* argument holds it and the keys of the objects around it. Undefined when the
|
|
30
|
+
* cursor is not inside `new X({ … })`.
|
|
31
|
+
*/
|
|
32
|
+
export function propertyPosition(before) {
|
|
33
|
+
const re = /\bnew\s+(\w+)\s*\(\s*\{/g;
|
|
34
|
+
let match;
|
|
35
|
+
let last;
|
|
36
|
+
while ((match = re.exec(before)) !== null)
|
|
37
|
+
last = { className: match[1], start: match.index + match[0].length };
|
|
38
|
+
if (!last)
|
|
39
|
+
return undefined;
|
|
40
|
+
// Walk from the constructor's `{`: each `{` opens the object of the key
|
|
41
|
+
// written just before it; `[` opens a list whose objects share that key.
|
|
42
|
+
const stack = [];
|
|
43
|
+
let pendingKey = null;
|
|
44
|
+
let i = last.start;
|
|
45
|
+
const text = before;
|
|
46
|
+
while (i < text.length) {
|
|
47
|
+
const ch = text[i];
|
|
48
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
49
|
+
const end = skipString(text, i);
|
|
50
|
+
const literal = text.slice(i + 1, end - 1);
|
|
51
|
+
// A quoted key: `"k8s.pod.name": …`
|
|
52
|
+
if (/^\s*:/.test(text.slice(end)))
|
|
53
|
+
pendingKey = literal;
|
|
54
|
+
i = end;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (ch === "/" && text[i + 1] === "/") {
|
|
58
|
+
const nl = text.indexOf("\n", i);
|
|
59
|
+
i = nl < 0 ? text.length : nl;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (ch === "/" && text[i + 1] === "*") {
|
|
63
|
+
const close = text.indexOf("*/", i + 2);
|
|
64
|
+
i = close < 0 ? text.length : close + 2;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const ident = /^[A-Za-z_$][\w$]*/.exec(text.slice(i));
|
|
68
|
+
if (ident) {
|
|
69
|
+
if (/^\s*:/.test(text.slice(i + ident[0].length)))
|
|
70
|
+
pendingKey = ident[0];
|
|
71
|
+
i += ident[0].length;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (ch === "{" || ch === "[") {
|
|
75
|
+
// A list keeps its key, so its objects resolve to the list's items.
|
|
76
|
+
stack.push(ch === "[" ? `[${pendingKey ?? ""}` : pendingKey);
|
|
77
|
+
pendingKey = null;
|
|
78
|
+
}
|
|
79
|
+
else if (ch === "}" || ch === "]") {
|
|
80
|
+
if (stack.length === 0)
|
|
81
|
+
return undefined; // the constructor's object closed
|
|
82
|
+
stack.pop();
|
|
83
|
+
}
|
|
84
|
+
else if (ch === "," || ch === "(" || ch === ")") {
|
|
85
|
+
pendingKey = null;
|
|
86
|
+
}
|
|
87
|
+
i++;
|
|
88
|
+
}
|
|
89
|
+
const path = [];
|
|
90
|
+
let inList;
|
|
91
|
+
for (const entry of stack) {
|
|
92
|
+
if (entry === null) {
|
|
93
|
+
if (inList === undefined)
|
|
94
|
+
return undefined; // an object whose key is unknown
|
|
95
|
+
inList = undefined; // an item of the list just entered
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (entry.startsWith("[")) {
|
|
99
|
+
inList = entry.slice(1);
|
|
100
|
+
if (inList)
|
|
101
|
+
path.push(inList);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
path.push(entry);
|
|
105
|
+
inList = undefined;
|
|
106
|
+
}
|
|
107
|
+
if (inList !== undefined)
|
|
108
|
+
return undefined; // directly inside a list, not an item
|
|
109
|
+
return { className: last.className, path };
|
|
110
|
+
}
|
|
111
|
+
function skipString(text, start) {
|
|
112
|
+
const quote = text[start];
|
|
113
|
+
let i = start + 1;
|
|
114
|
+
while (i < text.length && text[i] !== quote)
|
|
115
|
+
i += text[i] === "\\" ? 2 : 1;
|
|
116
|
+
return Math.min(i + 1, text.length);
|
|
117
|
+
}
|
|
118
|
+
/** The properties at a path of a built-in's tree, or undefined when the path leaves it. */
|
|
119
|
+
export function propertiesAt(position) {
|
|
120
|
+
let level = propertyTrees()[position.className];
|
|
121
|
+
for (const key of position.path) {
|
|
122
|
+
level = level?.[key]?.properties;
|
|
123
|
+
if (!level)
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
return level;
|
|
127
|
+
}
|
|
128
|
+
/** Markdown for one property: its type, deprecation and upstream description. */
|
|
129
|
+
export function propertyMarkdown(name, doc, className) {
|
|
130
|
+
const lines = [`**${name}**: \`${doc.type}\`${doc.deprecated ? " (deprecated)" : ""}`];
|
|
131
|
+
if (doc.description)
|
|
132
|
+
lines.push("", doc.description);
|
|
133
|
+
lines.push("", `\`${className}\` config, from upstream config.schema.yaml.`);
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
package/dist/manifest.json
CHANGED
package/dist/meta.json
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"kind": "resource",
|
|
10
10
|
"lexicon": "otel"
|
|
11
11
|
},
|
|
12
|
+
"ClickHouseExporter": {
|
|
13
|
+
"resourceType": "OTel::Exporter::clickhouse",
|
|
14
|
+
"kind": "resource",
|
|
15
|
+
"lexicon": "otel"
|
|
16
|
+
},
|
|
12
17
|
"CountConnector": {
|
|
13
18
|
"resourceType": "OTel::Connector::count",
|
|
14
19
|
"kind": "resource",
|
package/dist/metric-names.d.ts
CHANGED
|
@@ -11,9 +11,16 @@
|
|
|
11
11
|
* with the exporter's defaults: `.` and any other character Prometheus does
|
|
12
12
|
* not allow become `_`; counters take `_total`; a unit becomes a suffix
|
|
13
13
|
* (`ms` is `_milliseconds`, `s` is `_seconds`); the exporter's `namespace`
|
|
14
|
-
* is a prefix joined with `_
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* is a prefix joined with `_`. The exporter's `translation_strategy` decides
|
|
15
|
+
* the escaping and the suffixes: the default, `UnderscoreEscapingWithSuffixes`,
|
|
16
|
+
* is what is described here; `UnderscoreEscapingWithoutSuffixes` drops the
|
|
17
|
+
* suffixes; `NoUTF8EscapingWithSuffixes` keeps the name's characters;
|
|
18
|
+
* `NoTranslation` does neither. From collector-contrib v0.154.0 the
|
|
19
|
+
* `prometheus` exporter ignores the deprecated `add_metric_suffixes`, so a
|
|
20
|
+
* name read from that exporter follows `translation_strategy` alone; the
|
|
21
|
+
* `prometheusremotewrite` exporter still honours it when no strategy is set.
|
|
22
|
+
* Attribute names become label names the same way (`service.name` is
|
|
23
|
+
* `service_name`).
|
|
17
24
|
*
|
|
18
25
|
* This module holds types and string functions only, so a lexicon that
|
|
19
26
|
* builds queries from it does not load the collector components.
|
|
@@ -35,13 +42,34 @@ export declare const SPANMETRICS_DEFAULT_DIMENSIONS: readonly string[];
|
|
|
35
42
|
export declare const SPANMETRICS_DEFAULT_NAMESPACE = "traces.span.metrics";
|
|
36
43
|
/** The `status.code` value of a span that ended in error: the value an error-ratio query selects. */
|
|
37
44
|
export declare const SPAN_STATUS_ERROR = "STATUS_CODE_ERROR";
|
|
45
|
+
/** The `translation_strategy` values the Prometheus exporters take. */
|
|
46
|
+
export type PrometheusTranslationStrategy = "UnderscoreEscapingWithSuffixes" | "UnderscoreEscapingWithoutSuffixes" | "NoUTF8EscapingWithSuffixes" | "NoTranslation";
|
|
38
47
|
/** How the `prometheus` exporter is configured, as far as naming goes. */
|
|
39
48
|
export interface PrometheusNaming {
|
|
40
49
|
/** The exporter's `namespace`, put in front of every name and joined with `_`. */
|
|
41
50
|
namespace?: string;
|
|
42
|
-
/** The exporter's `
|
|
51
|
+
/** The exporter's `translation_strategy`. Default `UnderscoreEscapingWithSuffixes`. */
|
|
52
|
+
translation_strategy?: PrometheusTranslationStrategy | (string & {});
|
|
53
|
+
/**
|
|
54
|
+
* `false` drops the unit and `_total` suffixes when no `translation_strategy`
|
|
55
|
+
* is set, as the `prometheusremotewrite` exporter reads it. The `prometheus`
|
|
56
|
+
* exporter ignores it at the pinned release, and {@link exporterNaming}
|
|
57
|
+
* leaves it out for that exporter.
|
|
58
|
+
*
|
|
59
|
+
* @deprecated Upstream deprecates it for `translation_strategy`.
|
|
60
|
+
*/
|
|
43
61
|
add_metric_suffixes?: boolean;
|
|
44
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* The naming a declared `prometheus` exporter (or its config) applies: its
|
|
65
|
+
* `namespace` and `translation_strategy`. `add_metric_suffixes` is left out,
|
|
66
|
+
* since the exporter ignores it at the pinned release. A plain
|
|
67
|
+
* `PrometheusNaming` is returned as given.
|
|
68
|
+
*/
|
|
69
|
+
export declare function exporterNaming(exporter: PrometheusNaming | {
|
|
70
|
+
props?: PrometheusNaming;
|
|
71
|
+
componentType?: unknown;
|
|
72
|
+
} | undefined): PrometheusNaming;
|
|
45
73
|
/** An attribute name as a Prometheus label: `service.name` is `service_name`. */
|
|
46
74
|
export declare function prometheusLabel(attribute: string): string;
|
|
47
75
|
/**
|
|
@@ -55,23 +83,23 @@ export declare function prometheusMetricName(name: string, type: "sum" | "histog
|
|
|
55
83
|
export interface SpanMetricsNamingConfig {
|
|
56
84
|
namespace?: string;
|
|
57
85
|
dimensions?: Array<{
|
|
58
|
-
name
|
|
86
|
+
name?: string;
|
|
59
87
|
}>;
|
|
60
88
|
calls_dimensions?: Array<{
|
|
61
|
-
name
|
|
89
|
+
name?: string;
|
|
62
90
|
}>;
|
|
63
91
|
exclude_dimensions?: string[];
|
|
64
92
|
histogram?: {
|
|
65
93
|
disable?: boolean;
|
|
66
94
|
unit?: "ms" | "s";
|
|
67
95
|
dimensions?: Array<{
|
|
68
|
-
name
|
|
96
|
+
name?: string;
|
|
69
97
|
}>;
|
|
70
98
|
};
|
|
71
99
|
events?: {
|
|
72
100
|
enabled?: boolean;
|
|
73
101
|
dimensions?: Array<{
|
|
74
|
-
name
|
|
102
|
+
name?: string;
|
|
75
103
|
}>;
|
|
76
104
|
};
|
|
77
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metric-names.d.ts","sourceRoot":"","sources":["../src/metric-names.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"metric-names.d.ts","sourceRoot":"","sources":["../src/metric-names.ts"],"names":[],"mappings":"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"}
|
package/dist/metric-names.js
CHANGED
|
@@ -11,9 +11,16 @@
|
|
|
11
11
|
* with the exporter's defaults: `.` and any other character Prometheus does
|
|
12
12
|
* not allow become `_`; counters take `_total`; a unit becomes a suffix
|
|
13
13
|
* (`ms` is `_milliseconds`, `s` is `_seconds`); the exporter's `namespace`
|
|
14
|
-
* is a prefix joined with `_
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* is a prefix joined with `_`. The exporter's `translation_strategy` decides
|
|
15
|
+
* the escaping and the suffixes: the default, `UnderscoreEscapingWithSuffixes`,
|
|
16
|
+
* is what is described here; `UnderscoreEscapingWithoutSuffixes` drops the
|
|
17
|
+
* suffixes; `NoUTF8EscapingWithSuffixes` keeps the name's characters;
|
|
18
|
+
* `NoTranslation` does neither. From collector-contrib v0.154.0 the
|
|
19
|
+
* `prometheus` exporter ignores the deprecated `add_metric_suffixes`, so a
|
|
20
|
+
* name read from that exporter follows `translation_strategy` alone; the
|
|
21
|
+
* `prometheusremotewrite` exporter still honours it when no strategy is set.
|
|
22
|
+
* Attribute names become label names the same way (`service.name` is
|
|
23
|
+
* `service_name`).
|
|
17
24
|
*
|
|
18
25
|
* This module holds types and string functions only, so a lexicon that
|
|
19
26
|
* builds queries from it does not load the collector components.
|
|
@@ -34,6 +41,29 @@ const UNIT_WORDS = {
|
|
|
34
41
|
By: "bytes",
|
|
35
42
|
"1": "ratio",
|
|
36
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* The naming a declared `prometheus` exporter (or its config) applies: its
|
|
46
|
+
* `namespace` and `translation_strategy`. `add_metric_suffixes` is left out,
|
|
47
|
+
* since the exporter ignores it at the pinned release. A plain
|
|
48
|
+
* `PrometheusNaming` is returned as given.
|
|
49
|
+
*/
|
|
50
|
+
export function exporterNaming(exporter) {
|
|
51
|
+
if (!exporter)
|
|
52
|
+
return {};
|
|
53
|
+
if ("props" in exporter && typeof exporter.props === "object" && exporter.props !== null) {
|
|
54
|
+
const { add_metric_suffixes: _ignored, ...rest } = exporter.props;
|
|
55
|
+
return { ...(rest.namespace !== undefined ? { namespace: rest.namespace } : {}), ...(rest.translation_strategy !== undefined ? { translation_strategy: rest.translation_strategy } : {}) };
|
|
56
|
+
}
|
|
57
|
+
return exporter;
|
|
58
|
+
}
|
|
59
|
+
/** Whether a naming escapes names to `[A-Za-z0-9_:]` and whether it adds suffixes. */
|
|
60
|
+
function strategyOf(naming) {
|
|
61
|
+
const strategy = naming.translation_strategy ?? (naming.add_metric_suffixes === false ? "UnderscoreEscapingWithoutSuffixes" : "UnderscoreEscapingWithSuffixes");
|
|
62
|
+
return {
|
|
63
|
+
escape: strategy.startsWith("UnderscoreEscaping"),
|
|
64
|
+
suffixes: strategy !== "UnderscoreEscapingWithoutSuffixes" && strategy !== "NoTranslation",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
37
67
|
/** An attribute name as a Prometheus label: `service.name` is `service_name`. */
|
|
38
68
|
export function prometheusLabel(attribute) {
|
|
39
69
|
const label = attribute.replace(/[^A-Za-z0-9_]/g, "_");
|
|
@@ -46,10 +76,12 @@ export function prometheusLabel(attribute) {
|
|
|
46
76
|
* @param unit The metric's unit, e.g. `ms`. Units in braces (`{call}`) add nothing.
|
|
47
77
|
*/
|
|
48
78
|
export function prometheusMetricName(name, type, unit, naming = {}) {
|
|
49
|
-
|
|
79
|
+
const { escape, suffixes } = strategyOf(naming);
|
|
80
|
+
const clean = (s) => (escape ? s.replace(/[^A-Za-z0-9_:]/g, "_") : s);
|
|
81
|
+
let out = clean(name);
|
|
50
82
|
if (naming.namespace)
|
|
51
|
-
out = `${naming.namespace
|
|
52
|
-
if (
|
|
83
|
+
out = `${clean(naming.namespace)}_${out}`;
|
|
84
|
+
if (!suffixes)
|
|
53
85
|
return out;
|
|
54
86
|
const word = unit && !unit.startsWith("{") ? (UNIT_WORDS[unit] ?? unit.replace(/[^A-Za-z0-9_:]/g, "_")) : undefined;
|
|
55
87
|
if (word && !out.endsWith(`_${word}`))
|
|
@@ -81,12 +113,13 @@ function configOf(connector) {
|
|
|
81
113
|
*/
|
|
82
114
|
export function spanMetricsNames(connector, exporter) {
|
|
83
115
|
const c = configOf(connector);
|
|
84
|
-
const naming =
|
|
116
|
+
const naming = exporterNaming(exporter);
|
|
85
117
|
const namespace = c.namespace ?? SPANMETRICS_DEFAULT_NAMESPACE;
|
|
86
118
|
const metricName = (n) => (namespace === "" ? n : `${namespace}.${n}`);
|
|
87
119
|
const excluded = new Set(c.exclude_dimensions ?? []);
|
|
88
120
|
const defaults = SPANMETRICS_DEFAULT_DIMENSIONS.filter((d) => !excluded.has(d));
|
|
89
|
-
|
|
121
|
+
// A `glob` dimension names no single attribute, so it adds no fixed label.
|
|
122
|
+
const names = (extra) => (extra ?? []).flatMap((d) => (d.name === undefined ? [] : [d.name]));
|
|
90
123
|
const common = [...defaults, ...names(c.dimensions)];
|
|
91
124
|
const metric = (n, type, dims, unit) => ({
|
|
92
125
|
name: metricName(n),
|
|
@@ -134,7 +167,7 @@ export function serviceGraphNames(connector, exporter) {
|
|
|
134
167
|
throw new Error(`serviceGraphNames: expected a servicegraph connector, got ${d.componentType}`);
|
|
135
168
|
}
|
|
136
169
|
const c = (typeof d.componentType === "string" ? (d.props ?? {}) : connector);
|
|
137
|
-
const naming =
|
|
170
|
+
const naming = exporterNaming(exporter);
|
|
138
171
|
const dimensions = [
|
|
139
172
|
"client",
|
|
140
173
|
"server",
|