@intentius/chant-lexicon-otel 0.124.30 → 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.
Files changed (96) hide show
  1. package/dist/attribution.js +391 -0
  2. package/dist/catalog.js +42 -0
  3. package/dist/codegen/docs-cli.js +3 -0
  4. package/dist/codegen/docs.js +101 -0
  5. package/dist/codegen/generate-cli.js +7 -0
  6. package/dist/codegen/generate.js +43 -0
  7. package/dist/codegen/package.js +28 -0
  8. package/dist/collector.js +150 -0
  9. package/dist/components/common.js +50 -0
  10. package/dist/components/connectors.js +242 -0
  11. package/dist/components/exporters.js +57 -0
  12. package/dist/components/extensions.js +58 -0
  13. package/dist/components/filtering.js +106 -0
  14. package/dist/components/index.js +9 -0
  15. package/dist/components/k8s-receivers.js +36 -0
  16. package/dist/components/processors.js +103 -0
  17. package/dist/components/receivers.js +61 -0
  18. package/dist/components/sampling.js +257 -0
  19. package/dist/composites/catalog.js +368 -0
  20. package/dist/composites/genai-pipeline.js +28 -0
  21. package/dist/composites/index.js +8 -0
  22. package/dist/composites/node-agent.js +156 -0
  23. package/dist/composites/otlp-collector.js +57 -0
  24. package/dist/composites/red-metrics.js +95 -0
  25. package/dist/composites/tail-sampling-tier.js +132 -0
  26. package/dist/config-hygiene.js +464 -0
  27. package/dist/configmap.js +86 -0
  28. package/dist/define.js +204 -0
  29. package/dist/detect.js +22 -0
  30. package/dist/genai.js +569 -0
  31. package/dist/import/embedded.js +57 -0
  32. package/dist/import/generator.js +459 -0
  33. package/dist/import/parser.js +199 -0
  34. package/dist/index.js +34 -0
  35. package/dist/init-templates.js +119 -0
  36. package/dist/integrity.json +2 -2
  37. package/dist/lint/audit-catalog.js +49 -0
  38. package/dist/lint/post-synth/index.js +52 -0
  39. package/dist/lint/post-synth/otel-helpers.js +103 -0
  40. package/dist/lint/post-synth/otel101.js +13 -0
  41. package/dist/lint/post-synth/otel102.js +13 -0
  42. package/dist/lint/post-synth/otel103.js +13 -0
  43. package/dist/lint/post-synth/otel104.js +13 -0
  44. package/dist/lint/post-synth/otel105.js +13 -0
  45. package/dist/lint/post-synth/otel106.js +13 -0
  46. package/dist/lint/post-synth/otel107.js +13 -0
  47. package/dist/lint/post-synth/otel108.js +13 -0
  48. package/dist/lint/post-synth/otel109.js +13 -0
  49. package/dist/lint/post-synth/otel112.js +13 -0
  50. package/dist/lint/post-synth/otel113.js +13 -0
  51. package/dist/lint/post-synth/otel114.js +13 -0
  52. package/dist/lint/post-synth/otel115.js +13 -0
  53. package/dist/lint/post-synth/otel116.js +13 -0
  54. package/dist/lint/post-synth/otel117.js +13 -0
  55. package/dist/lint/post-synth/otel118.js +13 -0
  56. package/dist/lint/post-synth/otel119.js +13 -0
  57. package/dist/lint/post-synth/otel120.js +13 -0
  58. package/dist/lint/post-synth/otel121.js +13 -0
  59. package/dist/lint/post-synth/otel122.js +13 -0
  60. package/dist/lint/post-synth/otel123.js +13 -0
  61. package/dist/lint/post-synth/otel124.js +13 -0
  62. package/dist/lint/post-synth/otel125.js +13 -0
  63. package/dist/lint/post-synth/otel126.js +13 -0
  64. package/dist/lint/post-synth/otel127.js +13 -0
  65. package/dist/lint/rules/component-id-syntax.js +66 -0
  66. package/dist/lint/rules/index.js +6 -0
  67. package/dist/lint/rules/literal-credential.js +91 -0
  68. package/dist/lint/rules/otel-ast.js +30 -0
  69. package/dist/lsp/completions.js +11 -0
  70. package/dist/lsp/hover.js +23 -0
  71. package/dist/manifest.json +1 -1
  72. package/dist/metric-names.js +244 -0
  73. package/dist/model.js +90 -0
  74. package/dist/op/activities/collector-audit.js +213 -0
  75. package/dist/op/activities/collector-health.js +176 -0
  76. package/dist/op/activities/exec.js +16 -0
  77. package/dist/op/activities/github.js +110 -0
  78. package/dist/op/activities/index.js +16 -0
  79. package/dist/op/activities/otelcol.js +173 -0
  80. package/dist/op/activity-contracts.js +64 -0
  81. package/dist/op/audit-op.js +33 -0
  82. package/dist/op/builders.js +38 -0
  83. package/dist/package-cli.js +14 -0
  84. package/dist/pipeline.js +31 -0
  85. package/dist/platform.js +144 -0
  86. package/dist/plugin.js +126 -0
  87. package/dist/semconv.js +50 -0
  88. package/dist/serializer.js +26 -0
  89. package/dist/skill-defs.js +34 -0
  90. package/dist/topology.js +104 -0
  91. package/dist/validate-cli.js +7 -0
  92. package/dist/validate-config.js +706 -0
  93. package/dist/validate.js +85 -0
  94. package/dist/yaml.js +157 -0
  95. package/package.json +8 -8
  96. package/src/codegen/package.ts +2 -2
@@ -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
+ ]);
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env tsx
2
+ import { printValidationResult } from "@intentius/chant/codegen/validate";
3
+ import { validate } from "./validate.js";
4
+ const result = await validate();
5
+ printValidationResult(result);
6
+ if (!result.success)
7
+ process.exit(1);