@intentius/chant-lexicon-otel 0.124.31 → 0.124.32
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/dist/attribution.js +391 -0
- package/dist/catalog.js +42 -0
- package/dist/codegen/docs-cli.js +3 -0
- package/dist/codegen/docs.js +101 -0
- package/dist/codegen/generate-cli.js +7 -0
- package/dist/codegen/generate.js +43 -0
- package/dist/codegen/package.js +28 -0
- package/dist/collector.js +150 -0
- package/dist/components/common.js +50 -0
- package/dist/components/connectors.js +242 -0
- package/dist/components/exporters.js +57 -0
- package/dist/components/extensions.js +58 -0
- package/dist/components/filtering.js +106 -0
- package/dist/components/index.js +9 -0
- package/dist/components/k8s-receivers.js +36 -0
- package/dist/components/processors.js +103 -0
- package/dist/components/receivers.js +61 -0
- package/dist/components/sampling.js +257 -0
- package/dist/composites/catalog.js +368 -0
- package/dist/composites/genai-pipeline.js +28 -0
- package/dist/composites/index.js +8 -0
- package/dist/composites/node-agent.js +156 -0
- package/dist/composites/otlp-collector.js +57 -0
- package/dist/composites/red-metrics.js +95 -0
- package/dist/composites/tail-sampling-tier.js +132 -0
- package/dist/config-hygiene.js +464 -0
- package/dist/configmap.js +86 -0
- package/dist/define.js +204 -0
- package/dist/detect.js +22 -0
- package/dist/genai.js +569 -0
- package/dist/import/embedded.js +57 -0
- package/dist/import/generator.js +459 -0
- package/dist/import/parser.js +199 -0
- package/dist/index.js +34 -0
- package/dist/init-templates.js +119 -0
- package/dist/integrity.json +2 -2
- package/dist/lint/audit-catalog.js +49 -0
- package/dist/lint/post-synth/index.js +52 -0
- package/dist/lint/post-synth/otel-helpers.js +103 -0
- package/dist/lint/post-synth/otel101.js +13 -0
- package/dist/lint/post-synth/otel102.js +13 -0
- package/dist/lint/post-synth/otel103.js +13 -0
- package/dist/lint/post-synth/otel104.js +13 -0
- package/dist/lint/post-synth/otel105.js +13 -0
- package/dist/lint/post-synth/otel106.js +13 -0
- package/dist/lint/post-synth/otel107.js +13 -0
- package/dist/lint/post-synth/otel108.js +13 -0
- package/dist/lint/post-synth/otel109.js +13 -0
- package/dist/lint/post-synth/otel112.js +13 -0
- package/dist/lint/post-synth/otel113.js +13 -0
- package/dist/lint/post-synth/otel114.js +13 -0
- package/dist/lint/post-synth/otel115.js +13 -0
- package/dist/lint/post-synth/otel116.js +13 -0
- package/dist/lint/post-synth/otel117.js +13 -0
- package/dist/lint/post-synth/otel118.js +13 -0
- package/dist/lint/post-synth/otel119.js +13 -0
- package/dist/lint/post-synth/otel120.js +13 -0
- package/dist/lint/post-synth/otel121.js +13 -0
- package/dist/lint/post-synth/otel122.js +13 -0
- package/dist/lint/post-synth/otel123.js +13 -0
- package/dist/lint/post-synth/otel124.js +13 -0
- package/dist/lint/post-synth/otel125.js +13 -0
- package/dist/lint/post-synth/otel126.js +13 -0
- package/dist/lint/post-synth/otel127.js +13 -0
- package/dist/lint/rules/component-id-syntax.js +66 -0
- package/dist/lint/rules/index.js +6 -0
- package/dist/lint/rules/literal-credential.js +91 -0
- package/dist/lint/rules/otel-ast.js +30 -0
- package/dist/lsp/completions.js +11 -0
- package/dist/lsp/hover.js +23 -0
- package/dist/manifest.json +1 -1
- package/dist/metric-names.js +244 -0
- package/dist/model.js +90 -0
- package/dist/op/activities/collector-audit.js +213 -0
- package/dist/op/activities/collector-health.js +176 -0
- package/dist/op/activities/exec.js +16 -0
- package/dist/op/activities/github.js +110 -0
- package/dist/op/activities/index.js +16 -0
- package/dist/op/activities/otelcol.js +173 -0
- package/dist/op/activity-contracts.js +64 -0
- package/dist/op/audit-op.js +33 -0
- package/dist/op/builders.js +38 -0
- package/dist/package-cli.js +14 -0
- package/dist/pipeline.js +31 -0
- package/dist/platform.js +144 -0
- package/dist/plugin.js +126 -0
- package/dist/semconv.js +50 -0
- package/dist/serializer.js +26 -0
- package/dist/skill-defs.js +34 -0
- package/dist/topology.js +104 -0
- package/dist/validate-cli.js +7 -0
- package/dist/validate-config.js +706 -0
- package/dist/validate.js +85 -0
- package/dist/yaml.js +157 -0
- package/package.json +8 -8
- package/src/codegen/package.ts +2 -2
package/dist/semconv.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic-convention vocabularies a collector config can depend on, and how
|
|
3
|
+
* to tell that it does.
|
|
4
|
+
*
|
|
5
|
+
* A collector config has no metadata channel, so a config cannot say which
|
|
6
|
+
* semconv version its attribute keys follow. What it can show is that it uses
|
|
7
|
+
* a vocabulary: a `spanmetrics` dimension named `gen_ai.request.model`, an
|
|
8
|
+
* OTTL statement deleting `gen_ai.input.messages`, a `k8sattributes`
|
|
9
|
+
* processor extracting `k8s.pod.name`. `semconvUsage()` finds
|
|
10
|
+
* those and pairs each vocabulary with the pin this package's keys follow, the
|
|
11
|
+
* same way `collectorTopology()` pairs a component type with the pin of the
|
|
12
|
+
* definition this process has. Reading a parsed YAML file and reading the
|
|
13
|
+
* declaration give the same answer.
|
|
14
|
+
*/
|
|
15
|
+
import { GENAI_SEMCONV_PIN, SEMCONV_PIN } from "./define.js";
|
|
16
|
+
import { SECTION_OF } from "./model.js";
|
|
17
|
+
// `gen_ai.` as a key, in OTTL (`attributes["gen_ai.x"]`) or in an RE2 pattern (`gen_ai\.`).
|
|
18
|
+
const GEN_AI_REF = /(^|[^A-Za-z0-9_])gen_ai(\\\\|\\)?\./;
|
|
19
|
+
// `k8s.` with the dot, so the component types `k8s_cluster` and `k8sattributes` don't count.
|
|
20
|
+
const K8S_REF = /(^|[^A-Za-z0-9_])k8s(\\\\|\\)?\./;
|
|
21
|
+
export const SEMCONV_VOCABULARIES = Object.freeze([
|
|
22
|
+
{ namespace: "gen_ai", pin: GENAI_SEMCONV_PIN, matches: (text) => GEN_AI_REF.test(text) },
|
|
23
|
+
{ namespace: "k8s", pin: SEMCONV_PIN, matches: (text) => K8S_REF.test(text) },
|
|
24
|
+
]);
|
|
25
|
+
function mentions(value, test) {
|
|
26
|
+
if (typeof value === "string")
|
|
27
|
+
return test(value);
|
|
28
|
+
if (Array.isArray(value))
|
|
29
|
+
return value.some((v) => mentions(v, test));
|
|
30
|
+
if (value && typeof value === "object") {
|
|
31
|
+
return Object.entries(value).some(([k, v]) => test(k) || mentions(v, test));
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
/** The semconv vocabularies a collector config uses, each with its pin and the components that use it. */
|
|
36
|
+
export function semconvUsage(config) {
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const vocab of SEMCONV_VOCABULARIES) {
|
|
39
|
+
const components = [];
|
|
40
|
+
for (const kind of Object.keys(SECTION_OF)) {
|
|
41
|
+
for (const [id, cfg] of Object.entries(config[SECTION_OF[kind]] ?? {})) {
|
|
42
|
+
if (mentions(cfg, vocab.matches))
|
|
43
|
+
components.push(id);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (components.length > 0)
|
|
47
|
+
out.push({ namespace: vocab.namespace, ...vocab.pin, components });
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry Collector serializer.
|
|
3
|
+
*
|
|
4
|
+
* Emits one collector config file from every otel entity in the build: the
|
|
5
|
+
* YAML `otelcol --config` reads as it is. Section order is fixed (receivers,
|
|
6
|
+
* processors, exporters, connectors, extensions, service); components and pipelines keep
|
|
7
|
+
* the order they are declared in, and each component's config keeps the key
|
|
8
|
+
* order it was written in, since collector docs and diffs read that way.
|
|
9
|
+
*
|
|
10
|
+
* A collector config has no metadata channel, so there is no ownership marker
|
|
11
|
+
* to stamp. A custom component's schema pin is written as a `# chant:` comment
|
|
12
|
+
* line above the config (see `define.ts`).
|
|
13
|
+
*/
|
|
14
|
+
import { buildCollectorConfig } from "./collector.js";
|
|
15
|
+
import { emitCollectorYaml } from "./yaml.js";
|
|
16
|
+
export const otelSerializer = {
|
|
17
|
+
name: "otel",
|
|
18
|
+
rulePrefix: "OTEL",
|
|
19
|
+
serialize(entities, _outputs) {
|
|
20
|
+
const built = buildCollectorConfig(entities);
|
|
21
|
+
const yaml = emitCollectorYaml(built.config, { header: built.header });
|
|
22
|
+
if (built.warnings.length === 0)
|
|
23
|
+
return yaml;
|
|
24
|
+
return { primary: yaml, warnings: built.warnings };
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createSkillsLoader } from "@intentius/chant/lexicon-plugin-helpers";
|
|
2
|
+
/** The otel lexicon's AI skills, read from src/skills/. */
|
|
3
|
+
export const otelSkills = createSkillsLoader(import.meta.url, [
|
|
4
|
+
{
|
|
5
|
+
file: "chant-otel.md",
|
|
6
|
+
name: "chant-otel",
|
|
7
|
+
description: "Declare OpenTelemetry Collector config (receivers, processors, exporters, pipelines) as typed chant entities and build collector YAML",
|
|
8
|
+
triggers: [
|
|
9
|
+
{ type: "context", value: "opentelemetry" },
|
|
10
|
+
{ type: "context", value: "otel collector" },
|
|
11
|
+
{ type: "file-pattern", value: "*.otel.ts" },
|
|
12
|
+
],
|
|
13
|
+
examples: [
|
|
14
|
+
{
|
|
15
|
+
title: "An OTLP-in, OTLP-out traces pipeline",
|
|
16
|
+
output: 'const otlp = new OtlpReceiver({ protocols: { grpc: { endpoint: "0.0.0.0:4317" } } });\n' +
|
|
17
|
+
'const backend = new OtlpExporter({ name: "backend", endpoint: "tempo:4317" });\n' +
|
|
18
|
+
"export const traces = new Pipeline({ signal: \"traces\", receivers: [otlp], exporters: [backend] });",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
file: "chant-otel-custom-components.md",
|
|
24
|
+
name: "chant-otel-custom-components",
|
|
25
|
+
description: "Add a collector component chant doesn't ship (a vendor exporter, an in-house processor) with defineComponent, and pin its schema",
|
|
26
|
+
triggers: [{ type: "context", value: "otel custom component" }],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
file: "chant-otel-platforms.md",
|
|
30
|
+
name: "chant-otel-platforms",
|
|
31
|
+
description: "Run a declared collector config on Kubernetes, GKE, Docker or Fly by rendering it into the platform's own config file",
|
|
32
|
+
triggers: [{ type: "context", value: "deploy otel collector" }],
|
|
33
|
+
},
|
|
34
|
+
]);
|
package/dist/topology.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where telemetry goes, as plain data.
|
|
3
|
+
*
|
|
4
|
+
* `collectorTopology()` reads a collector config (declared, or parsed from a
|
|
5
|
+
* YAML file) and returns its pipelines, its components with their endpoints
|
|
6
|
+
* and schema pins, for each exporter the pipelines and signals it carries,
|
|
7
|
+
* the edges connectors make from one pipeline to another, and the
|
|
8
|
+
* semantic-convention versions its attribute keys follow. It is the
|
|
9
|
+
* surface a reader such as `chant workspace graph` uses to say where a
|
|
10
|
+
* member's telemetry is sent, and what a declared telemetry endpoint link can
|
|
11
|
+
* point at.
|
|
12
|
+
*/
|
|
13
|
+
import { buildCollectorConfig } from "./collector.js";
|
|
14
|
+
import { definitionOf } from "./define.js";
|
|
15
|
+
import { parseComponentId, pipelineSignal, SECTION_OF } from "./model.js";
|
|
16
|
+
import { semconvUsage } from "./semconv.js";
|
|
17
|
+
function protocolsOf(kind, type, config) {
|
|
18
|
+
const def = definitionOf(kind, type);
|
|
19
|
+
if (!def?.protocols)
|
|
20
|
+
return [];
|
|
21
|
+
try {
|
|
22
|
+
return def.protocols((config ?? {}));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function endpointsOf(kind, type, config) {
|
|
29
|
+
const def = definitionOf(kind, type);
|
|
30
|
+
const cfg = config ?? {};
|
|
31
|
+
if (def?.endpoints) {
|
|
32
|
+
try {
|
|
33
|
+
return def.endpoints(cfg);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return typeof cfg.endpoint === "string" && cfg.endpoint !== "" ? [cfg.endpoint] : [];
|
|
40
|
+
}
|
|
41
|
+
/** The topology of a collector config. */
|
|
42
|
+
export function collectorTopology(config) {
|
|
43
|
+
const pipelines = Object.entries(config.service?.pipelines ?? {}).map(([id, p]) => ({
|
|
44
|
+
id,
|
|
45
|
+
signal: pipelineSignal(id),
|
|
46
|
+
receivers: (p?.receivers ?? []).map(String),
|
|
47
|
+
processors: (p?.processors ?? []).map(String),
|
|
48
|
+
exporters: (p?.exporters ?? []).map(String),
|
|
49
|
+
}));
|
|
50
|
+
const components = [];
|
|
51
|
+
for (const kind of Object.keys(SECTION_OF)) {
|
|
52
|
+
const section = SECTION_OF[kind];
|
|
53
|
+
for (const [id, cfg] of Object.entries(config[section] ?? {})) {
|
|
54
|
+
const parsed = parseComponentId(id);
|
|
55
|
+
const type = parsed?.type ?? id;
|
|
56
|
+
const def = definitionOf(kind, type);
|
|
57
|
+
const inPipelines = section === "extensions"
|
|
58
|
+
? []
|
|
59
|
+
: section === "connectors"
|
|
60
|
+
? pipelines.filter((p) => p.receivers.includes(id) || p.exporters.includes(id)).map((p) => p.id)
|
|
61
|
+
: pipelines.filter((p) => p[section].includes(id)).map((p) => p.id);
|
|
62
|
+
components.push({
|
|
63
|
+
id,
|
|
64
|
+
kind,
|
|
65
|
+
type,
|
|
66
|
+
...(parsed?.name !== undefined ? { name: parsed.name } : {}),
|
|
67
|
+
builtin: def?.builtin ?? false,
|
|
68
|
+
...(def ? { schema: { ...def.pin } } : {}),
|
|
69
|
+
endpoints: endpointsOf(kind, type, cfg),
|
|
70
|
+
protocols: protocolsOf(kind, type, cfg),
|
|
71
|
+
pipelines: inPipelines,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const exporters = components
|
|
76
|
+
.filter((c) => c.kind === "exporter")
|
|
77
|
+
.map((c) => {
|
|
78
|
+
const signals = [];
|
|
79
|
+
for (const pid of c.pipelines) {
|
|
80
|
+
const s = pipelineSignal(pid);
|
|
81
|
+
if (!signals.includes(s))
|
|
82
|
+
signals.push(s);
|
|
83
|
+
}
|
|
84
|
+
return { id: c.id, type: c.type, endpoints: c.endpoints, pipelines: c.pipelines, signals };
|
|
85
|
+
});
|
|
86
|
+
const edges = [];
|
|
87
|
+
for (const c of components) {
|
|
88
|
+
if (c.kind !== "connector")
|
|
89
|
+
continue;
|
|
90
|
+
const pairs = definitionOf("connector", c.type)?.connects;
|
|
91
|
+
for (const from of pipelines.filter((p) => p.exporters.includes(c.id))) {
|
|
92
|
+
for (const to of pipelines.filter((p) => p.receivers.includes(c.id))) {
|
|
93
|
+
if (pairs && pairs.length > 0 && !pairs.some((pair) => pair.from === from.signal && pair.to === to.signal))
|
|
94
|
+
continue;
|
|
95
|
+
edges.push({ connector: c.id, from: from.id, fromSignal: from.signal, to: to.id, toSignal: to.signal });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { pipelines, components, exporters, edges, semconv: semconvUsage(config) };
|
|
100
|
+
}
|
|
101
|
+
/** The topology of declared entities, i.e. of the config the serializer would emit for them. */
|
|
102
|
+
export function collectorTopologyOf(entities) {
|
|
103
|
+
return collectorTopology(buildCollectorConfig(entities).config);
|
|
104
|
+
}
|