@intentius/chant-lexicon-otel 0.97.0 → 0.99.0

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 (54) hide show
  1. package/README.md +5 -0
  2. package/dist/codegen/docs.d.ts.map +1 -1
  3. package/dist/components/common.d.ts +7 -2
  4. package/dist/components/common.d.ts.map +1 -1
  5. package/dist/components/filtering.d.ts +58 -1
  6. package/dist/components/filtering.d.ts.map +1 -1
  7. package/dist/components/processors.d.ts +10 -0
  8. package/dist/components/processors.d.ts.map +1 -1
  9. package/dist/components/receivers.d.ts +87 -7
  10. package/dist/components/receivers.d.ts.map +1 -1
  11. package/dist/import/embedded.d.ts +12 -0
  12. package/dist/import/embedded.d.ts.map +1 -0
  13. package/dist/import/generator.d.ts +39 -0
  14. package/dist/import/generator.d.ts.map +1 -0
  15. package/dist/import/parser.d.ts +61 -0
  16. package/dist/import/parser.d.ts.map +1 -0
  17. package/dist/integrity.json +4 -4
  18. package/dist/lint/rules/literal-credential.d.ts.map +1 -1
  19. package/dist/manifest.json +1 -1
  20. package/dist/plugin.d.ts.map +1 -1
  21. package/dist/rules/literal-credential.ts +46 -17
  22. package/dist/skills/chant-otel.md +11 -0
  23. package/package.json +2 -2
  24. package/src/codegen/docs.ts +2 -1
  25. package/src/components/common.ts +7 -2
  26. package/src/components/filtering.test.ts +27 -0
  27. package/src/components/filtering.ts +65 -2
  28. package/src/components/processors.ts +4 -0
  29. package/src/components/receivers.ts +88 -4
  30. package/src/import/embedded.test.ts +56 -0
  31. package/src/import/embedded.ts +41 -0
  32. package/src/import/generated-types.e2e.test.ts +110 -0
  33. package/src/import/generator.test.ts +165 -0
  34. package/src/import/generator.ts +509 -0
  35. package/src/import/parser.test.ts +174 -0
  36. package/src/import/parser.ts +236 -0
  37. package/src/import/roundtrip.test.ts +365 -0
  38. package/src/import/testdata/agent-observability-agent.yaml +54 -0
  39. package/src/import/testdata/agent-observability-gateway.yaml +128 -0
  40. package/src/import/testdata/fixtures.ts +274 -0
  41. package/src/import/testdata/gateway.yaml +153 -0
  42. package/src/import/testdata/upstream/couchbase.yaml +150 -0
  43. package/src/import/testdata/upstream/fault-tolerant-logs.yaml +27 -0
  44. package/src/import/testdata/upstream/kubernetes-filelog.yaml +86 -0
  45. package/src/import/testdata/upstream/loadbalancing-agent.yaml +38 -0
  46. package/src/import/testdata/upstream/loadbalancing-backend.yaml +27 -0
  47. package/src/import/testdata/upstream/logline-filter-in.yaml +20 -0
  48. package/src/import/testdata/upstream/logline-filter-out.yaml +20 -0
  49. package/src/import/testdata/upstream/secure-tracing.yaml +26 -0
  50. package/src/import/testdata/upstream/servicegraph-nop.yaml +28 -0
  51. package/src/lint/rules/literal-credential.ts +46 -17
  52. package/src/lint/rules/rules.test.ts +16 -0
  53. package/src/plugin.ts +15 -0
  54. package/src/skills/chant-otel.md +11 -0
@@ -0,0 +1,38 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/exporter/loadbalancingexporter/example/otel-agent-config.yaml
3
+
4
+ receivers:
5
+ fluentforward:
6
+ endpoint: 0.0.0.0:24224
7
+
8
+ processors:
9
+ batch:
10
+
11
+ exporters:
12
+ debug:
13
+ verbosity: detailed
14
+ loadbalancing:
15
+ protocol:
16
+ otlp:
17
+ timeout: 1s
18
+ tls:
19
+ insecure: true
20
+ resolver:
21
+ static:
22
+ hostnames:
23
+ - otel-collector-1:4317
24
+ - otel-collector-2:4317
25
+ - otel-collector-3:4317
26
+
27
+ extensions:
28
+ health_check:
29
+ pprof:
30
+ zpages:
31
+
32
+ service:
33
+ extensions: [pprof, zpages, health_check]
34
+ pipelines:
35
+ logs:
36
+ receivers: [fluentforward]
37
+ processors: [batch]
38
+ exporters: [loadbalancing, debug]
@@ -0,0 +1,27 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/exporter/loadbalancingexporter/example/otel-collector-config.yaml
3
+
4
+ receivers:
5
+ otlp:
6
+ protocols:
7
+ grpc:
8
+
9
+ processors:
10
+ batch:
11
+
12
+ exporters:
13
+ debug:
14
+ verbosity: detailed
15
+
16
+ extensions:
17
+ health_check:
18
+ pprof:
19
+ zpages:
20
+
21
+ service:
22
+ extensions: [pprof, zpages, health_check]
23
+ pipelines:
24
+ logs:
25
+ receivers: [otlp]
26
+ processors: [batch]
27
+ exporters: [debug]
@@ -0,0 +1,20 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/examples/logline-filtering/otel-col-config-filter-in-logs.yaml
3
+
4
+ receivers:
5
+ filelog:
6
+ include: [/var/log/busybox/simple.log]
7
+ operators:
8
+ - type: filter
9
+ expr: 'body not matches "^WARN:"'
10
+
11
+ service:
12
+ pipelines:
13
+ logs:
14
+ receivers: [filelog]
15
+ exporters: [otlp/custom]
16
+ processors: []
17
+
18
+ exporters:
19
+ otlp/custom:
20
+ endpoint: http://0.0.0.0:4242
@@ -0,0 +1,20 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/examples/logline-filtering/otel-col-config-filter-out-logs.yaml
3
+
4
+ receivers:
5
+ filelog:
6
+ include: [/var/log/busybox/simple.log]
7
+ operators:
8
+ - type: filter
9
+ expr: 'body matches "^INFO:"'
10
+
11
+ service:
12
+ pipelines:
13
+ logs:
14
+ receivers: [filelog]
15
+ exporters: [otlp/custom]
16
+ processors: []
17
+
18
+ exporters:
19
+ otlp/custom:
20
+ endpoint: http://0.0.0.0:4242
@@ -0,0 +1,26 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/examples/secure-tracing/otel-collector-config.yaml
3
+
4
+ receivers:
5
+ otlp:
6
+ protocols:
7
+ grpc:
8
+ endpoint: 0.0.0.0:55690
9
+ tls:
10
+ cert_file: /etc/otel-collector.crt
11
+ key_file: /etc/otel-collector.key
12
+
13
+ processors:
14
+ batch:
15
+
16
+ exporters:
17
+ debug:
18
+ verbosity: detailed
19
+
20
+ service:
21
+ pipelines:
22
+ traces:
23
+ receivers: [otlp]
24
+ processors: [batch]
25
+ exporters: [debug]
26
+
@@ -0,0 +1,28 @@
1
+ # Vendored from opentelemetry-collector-contrib v0.130.0 (Apache-2.0), unchanged below this header:
2
+ # https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.130.0/connector/servicegraphconnector/testdata/service-graph-connector-config.yaml
3
+
4
+ receivers:
5
+ nop:
6
+
7
+ exporters:
8
+ nop:
9
+
10
+ connectors:
11
+ servicegraph:
12
+ latency_histogram_buckets: [1,2,3,4,5]
13
+ dimensions:
14
+ - dimension-1
15
+ - dimension-2
16
+ store:
17
+ ttl: 1s
18
+ max_items: 10
19
+ database_name_attributes: [db.name]
20
+
21
+ service:
22
+ pipelines:
23
+ traces:
24
+ receivers: [nop]
25
+ exporters: [servicegraph]
26
+ metrics:
27
+ receivers: [servicegraph]
28
+ exporters: [nop]
@@ -25,25 +25,54 @@ export const literalCredentialRule: LintRule = {
25
25
  const diagnostics: LintDiagnostic[] = [];
26
26
  const source = context.sourceFile;
27
27
 
28
+ // `const x = { ... }` (or `[...]`, or a string) anywhere in the file, so a
29
+ // config value lifted out of the constructor into a named const, the way
30
+ // COR001 asks, is scanned where it is used.
31
+ const consts = new Map<string, ts.Expression>();
32
+ const collect = (node: ts.Node) => {
33
+ if (ts.isVariableDeclarationList(node) && node.flags & ts.NodeFlags.Const) {
34
+ for (const d of node.declarations) {
35
+ if (ts.isIdentifier(d.name) && d.initializer) consts.set(d.name.text, d.initializer);
36
+ }
37
+ }
38
+ ts.forEachChild(node, collect);
39
+ };
40
+ collect(source);
41
+
42
+ const flag = (key: string, node: ts.Node) =>
43
+ diagnostics.push({
44
+ ruleId: "OTEL002",
45
+ severity: "error",
46
+ message: `\`${key}\` is a literal credential; write "\${env:NAME}" (or "\${file:/path}") and let the collector read it at start-up`,
47
+ file: context.filePath,
48
+ ...position(source, node),
49
+ });
50
+
51
+ const scanned = new Set<ts.Node>();
52
+ const scanValue = (key: string | undefined, value: ts.Expression) => {
53
+ let init: ts.Expression = value;
54
+ if (ts.isIdentifier(init)) {
55
+ const resolved = consts.get(init.text);
56
+ if (!resolved) return;
57
+ init = resolved;
58
+ }
59
+ if (ts.isObjectLiteralExpression(init) || ts.isArrayLiteralExpression(init)) {
60
+ if (scanned.has(init)) return;
61
+ scanned.add(init);
62
+ if (ts.isObjectLiteralExpression(init)) scan(init);
63
+ else for (const el of init.elements) scanValue(undefined, el as ts.Expression);
64
+ return;
65
+ }
66
+ if (!key || !SECRET_KEY.test(key) || /_file$/i.test(key)) return;
67
+ const text = literalText(init);
68
+ if (text === undefined || text === "" || text.includes("${")) return;
69
+ flag(key, value);
70
+ };
71
+
28
72
  const scan = (obj: ts.ObjectLiteralExpression) => {
29
73
  for (const prop of obj.properties) {
30
- if (!ts.isPropertyAssignment(prop)) continue;
31
- const key = propertyName(prop);
32
- const init = prop.initializer;
33
- if (ts.isObjectLiteralExpression(init)) {
34
- scan(init);
35
- continue;
36
- }
37
- if (!key || !SECRET_KEY.test(key) || /_file$/i.test(key)) continue;
38
- const text = literalText(init);
39
- if (text === undefined || text === "" || text.includes("${")) continue;
40
- diagnostics.push({
41
- ruleId: "OTEL002",
42
- severity: "error",
43
- message: `\`${key}\` is a literal credential; write "\${env:NAME}" (or "\${file:/path}") and let the collector read it at start-up`,
44
- file: context.filePath,
45
- ...position(source, init),
46
- });
74
+ if (ts.isShorthandPropertyAssignment(prop)) scanValue(prop.name.text, prop.name);
75
+ else if (ts.isPropertyAssignment(prop)) scanValue(propertyName(prop), prop.initializer);
47
76
  }
48
77
  };
49
78
 
@@ -67,4 +67,20 @@ describe("OTEL002 literal credential", () => {
67
67
  );
68
68
  expect(diags).toEqual([]);
69
69
  });
70
+
71
+ test("follows config lifted into named consts, and looks inside lists", () => {
72
+ const diags = literalCredentialRule.check(
73
+ ctx(`
74
+ const headers: OtlpExporterConfig["headers"] = { authorization: "Bearer abc123" };
75
+ const safe = { authorization: "Bearer \${env:TOKEN}" };
76
+ const token = "literal";
77
+ const config = { scrape_configs: [{ job_name: "x", basic_auth: { username: "u", password: "p" } }] };
78
+ new OtlpExporter({ endpoint: "x:4317", headers });
79
+ new OtlpExporter({ name: "b", endpoint: "x:4317", headers: safe });
80
+ new SplunkHecExporter({ token, endpoint: "https://hec" });
81
+ new PrometheusReceiver({ config });
82
+ `),
83
+ );
84
+ expect(diags.map((d) => d.message.split("`")[1])).toEqual(["authorization", "token", "password"]);
85
+ });
70
86
  });
package/src/plugin.ts CHANGED
@@ -9,6 +9,9 @@ import { otelAuditCatalog } from "./lint/audit-catalog";
9
9
  import { completions } from "./lsp/completions";
10
10
  import { hover } from "./lsp/hover";
11
11
  import { detectTemplate } from "./detect";
12
+ import { OtelCollectorParser } from "./import/parser";
13
+ import { OtelCollectorGenerator } from "./import/generator";
14
+ import { collectorConfigImporter } from "./import/embedded";
12
15
  import { otelSkills } from "./skill-defs";
13
16
  import { BUILTIN_CATALOG } from "./catalog";
14
17
  import { COLLECTOR_PIN } from "./define";
@@ -96,6 +99,18 @@ export const otelPlugin: LexiconPlugin = {
96
99
  return detectTemplate(data);
97
100
  },
98
101
 
102
+ templateParser() {
103
+ return new OtelCollectorParser();
104
+ },
105
+
106
+ templateGenerator() {
107
+ return new OtelCollectorGenerator();
108
+ },
109
+
110
+ embeddedImporters() {
111
+ return [collectorConfigImporter];
112
+ },
113
+
99
114
  completionProvider(ctx: CompletionContext) {
100
115
  return completions(ctx);
101
116
  },
@@ -78,6 +78,17 @@ It deletes prompt, completion, system-instruction and tool-call content from spa
78
78
  - Every pipeline needs at least one receiver and one exporter (OTEL102). A declared component no pipeline uses is a warning (OTEL103).
79
79
  - Declared extensions are enabled in declaration order unless a `Service` lists `extensions` itself.
80
80
 
81
+ ## Starting from an existing config
82
+
83
+ When the user already has a collector config file, import it rather than retyping it:
84
+
85
+ ```bash
86
+ chant import otel-collector-config.yaml --output src
87
+ chant build src --lexicon otel -o collector.yaml # the same config back
88
+ ```
89
+
90
+ The importer writes `receivers.ts`, `processors.ts`, `exporters.ts`, `connectors.ts`, `extensions.ts`, `pipelines.ts`, and `service.ts` when extensions or telemetry need a `Service`. A component type with no built-in class lands in `custom-components.ts` as a `defineComponent` whose config is untyped data; offer to give it a config interface. Settings outside a built-in's config type still import and build, but `tsc` flags them. Read the warnings `chant import` prints: they name anything the lexicon has no place for.
91
+
81
92
  ## Reading the result
82
93
 
83
94
  `collectorTopologyOf(entities)` returns the pipelines, each component's endpoints and schema pin, for each exporter the signals it carries, the connector `edges` between pipelines, and under `semconv` the semantic-conventions version (`GENAI_SEMCONV_PIN`) the config's `gen_ai.` keys follow, as plain data.