@intentius/chant-lexicon-otel 0.124.45 → 0.124.48
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,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in components, as the schema snapshot and the generator see them:
|
|
3
|
+
* class name, kind and collector type. Kept apart from `../components` so the
|
|
4
|
+
* snapshot refresh and generation load no component code (the components
|
|
5
|
+
* import the types generation writes). `builtins.test.ts` holds this list to
|
|
6
|
+
* the exported classes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ComponentKind } from "../model";
|
|
10
|
+
|
|
11
|
+
export interface BuiltinSpec {
|
|
12
|
+
/** The exported class, e.g. `OtlpReceiver`. The generated config type is `<className>SchemaConfig`. */
|
|
13
|
+
className: string;
|
|
14
|
+
kind: ComponentKind;
|
|
15
|
+
/** The type the class writes, which may be the older name of a renamed component. */
|
|
16
|
+
type: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const BUILTIN_SPECS: readonly BuiltinSpec[] = [
|
|
20
|
+
{ className: "OtlpReceiver", kind: "receiver", type: "otlp" },
|
|
21
|
+
{ className: "PrometheusReceiver", kind: "receiver", type: "prometheus" },
|
|
22
|
+
{ className: "HostMetricsReceiver", kind: "receiver", type: "hostmetrics" },
|
|
23
|
+
{ className: "FileLogReceiver", kind: "receiver", type: "filelog" },
|
|
24
|
+
{ className: "K8sClusterReceiver", kind: "receiver", type: "k8s_cluster" },
|
|
25
|
+
{ className: "KubeletStatsReceiver", kind: "receiver", type: "kubeletstats" },
|
|
26
|
+
{ className: "BatchProcessor", kind: "processor", type: "batch" },
|
|
27
|
+
{ className: "MemoryLimiterProcessor", kind: "processor", type: "memory_limiter" },
|
|
28
|
+
{ className: "ResourceProcessor", kind: "processor", type: "resource" },
|
|
29
|
+
{ className: "AttributesProcessor", kind: "processor", type: "attributes" },
|
|
30
|
+
{ className: "K8sAttributesProcessor", kind: "processor", type: "k8sattributes" },
|
|
31
|
+
{ className: "ResourceDetectionProcessor", kind: "processor", type: "resourcedetection" },
|
|
32
|
+
{ className: "DeltaToCumulativeProcessor", kind: "processor", type: "deltatocumulative" },
|
|
33
|
+
{ className: "FilterProcessor", kind: "processor", type: "filter" },
|
|
34
|
+
{ className: "TransformProcessor", kind: "processor", type: "transform" },
|
|
35
|
+
{ className: "RedactionProcessor", kind: "processor", type: "redaction" },
|
|
36
|
+
{ className: "TailSamplingProcessor", kind: "processor", type: "tail_sampling" },
|
|
37
|
+
{ className: "ProbabilisticSamplerProcessor", kind: "processor", type: "probabilistic_sampler" },
|
|
38
|
+
{ className: "OtlpExporter", kind: "exporter", type: "otlp" },
|
|
39
|
+
{ className: "OtlpHttpExporter", kind: "exporter", type: "otlphttp" },
|
|
40
|
+
{ className: "DebugExporter", kind: "exporter", type: "debug" },
|
|
41
|
+
{ className: "PrometheusExporter", kind: "exporter", type: "prometheus" },
|
|
42
|
+
{ className: "GoogleCloudExporter", kind: "exporter", type: "googlecloud" },
|
|
43
|
+
{ className: "ClickHouseExporter", kind: "exporter", type: "clickhouse" },
|
|
44
|
+
{ className: "LoadBalancingExporter", kind: "exporter", type: "loadbalancing" },
|
|
45
|
+
{ className: "SpanMetricsConnector", kind: "connector", type: "spanmetrics" },
|
|
46
|
+
{ className: "ServiceGraphConnector", kind: "connector", type: "servicegraph" },
|
|
47
|
+
{ className: "RoutingConnector", kind: "connector", type: "routing" },
|
|
48
|
+
{ className: "ForwardConnector", kind: "connector", type: "forward" },
|
|
49
|
+
{ className: "CountConnector", kind: "connector", type: "count" },
|
|
50
|
+
{ className: "SumConnector", kind: "connector", type: "sum" },
|
|
51
|
+
{ className: "SignalToMetricsConnector", kind: "connector", type: "signaltometrics" },
|
|
52
|
+
{ className: "HealthCheckExtension", kind: "extension", type: "health_check" },
|
|
53
|
+
{ className: "PprofExtension", kind: "extension", type: "pprof" },
|
|
54
|
+
{ className: "ZPagesExtension", kind: "extension", type: "zpages" },
|
|
55
|
+
{ className: "K8sLeaderElectorExtension", kind: "extension", type: "k8s_leader_elector" },
|
|
56
|
+
];
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The upstream collector schemas, read at the pinned tags (#3361).
|
|
3
|
+
*
|
|
4
|
+
* Three repositories, all read at git tags:
|
|
5
|
+
*
|
|
6
|
+
* - opentelemetry-collector-releases, for each distribution's builder manifest
|
|
7
|
+
* (`distributions/<name>/manifest.yaml`): which component modules a given
|
|
8
|
+
* `otelcol` binary is built from, and at which version;
|
|
9
|
+
* - opentelemetry-collector (`go.opentelemetry.io/collector/...`) and
|
|
10
|
+
* opentelemetry-collector-contrib, for each component's `metadata.yaml` (its
|
|
11
|
+
* collector type, and the deprecated type it still answers to) and its
|
|
12
|
+
* `config.schema.yaml`, plus every schema document those reach through
|
|
13
|
+
* `$ref` (the shared `config/*` packages, `exporterhelper`, contrib's
|
|
14
|
+
* `internal/*` and `pkg/*`).
|
|
15
|
+
*
|
|
16
|
+
* Downloads go through core's `fetchWithCache` under `~/.chant/otel-spec/<tag>`,
|
|
17
|
+
* with a long TTL, because a tag's content never moves. This module only runs
|
|
18
|
+
* when the snapshot is refreshed (`just snapshot`); generation reads the
|
|
19
|
+
* committed snapshot and never touches the network.
|
|
20
|
+
*
|
|
21
|
+
* ## `$ref` forms
|
|
22
|
+
*
|
|
23
|
+
* `schemagen` writes four:
|
|
24
|
+
*
|
|
25
|
+
* - `name`, a definition in the same document's `$defs`;
|
|
26
|
+
* - `./internal/metadata.name`, a package below the referring document's;
|
|
27
|
+
* - `/config/configgrpc.client_config`, a package path from the root of the
|
|
28
|
+
* referring document's repository;
|
|
29
|
+
* - `go.opentelemetry.io/collector/config/configopaque.string`, a full Go
|
|
30
|
+
* import path.
|
|
31
|
+
*
|
|
32
|
+
* Every form ends in `.<definition>`; {@link resolveRef} turns each into a
|
|
33
|
+
* document key (the Go import path of the package) and a definition name.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { homedir } from "os";
|
|
37
|
+
import { join } from "path";
|
|
38
|
+
import yaml from "js-yaml";
|
|
39
|
+
import { fetchWithCache } from "@intentius/chant/codegen/fetch";
|
|
40
|
+
import type { ComponentKind } from "../model";
|
|
41
|
+
|
|
42
|
+
export const CORE_MODULE = "go.opentelemetry.io/collector";
|
|
43
|
+
export const CONTRIB_MODULE = "github.com/open-telemetry/opentelemetry-collector-contrib";
|
|
44
|
+
|
|
45
|
+
const REPOS: ReadonlyArray<{ module: string; repo: string }> = [
|
|
46
|
+
{ module: CONTRIB_MODULE, repo: "open-telemetry/opentelemetry-collector-contrib" },
|
|
47
|
+
{ module: CORE_MODULE, repo: "open-telemetry/opentelemetry-collector" },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
/** The distributions whose manifests scope the lexicon. */
|
|
51
|
+
export const DISTRIBUTIONS = ["otelcol-contrib", "otelcol-k8s"] as const;
|
|
52
|
+
export type DistributionName = (typeof DISTRIBUTIONS)[number];
|
|
53
|
+
|
|
54
|
+
/** A tag's content never moves, so a cached copy stays good for a year. */
|
|
55
|
+
const TAG_TTL_MS = 365 * 24 * 60 * 60 * 1000;
|
|
56
|
+
|
|
57
|
+
function cacheFile(repo: string, tag: string, path: string): string {
|
|
58
|
+
return join(homedir(), ".chant", "otel-spec", repo.split("/")[1], tag, ...path.split("/"));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function rawUrl(repo: string, tag: string, path: string): string {
|
|
62
|
+
return `https://raw.githubusercontent.com/${repo}/${tag}/${path}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── Manifests ───────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/** One component module a distribution is built from. */
|
|
68
|
+
export interface ManifestModule {
|
|
69
|
+
kind: ComponentKind;
|
|
70
|
+
/** The Go module path, e.g. `go.opentelemetry.io/collector/receiver/otlpreceiver`. */
|
|
71
|
+
module: string;
|
|
72
|
+
/** The module version the manifest names, e.g. `v0.162.0`. */
|
|
73
|
+
version: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const SECTION_KIND: Record<string, ComponentKind> = {
|
|
77
|
+
receivers: "receiver",
|
|
78
|
+
processors: "processor",
|
|
79
|
+
exporters: "exporter",
|
|
80
|
+
connectors: "connector",
|
|
81
|
+
extensions: "extension",
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The component modules a builder manifest lists. `providers` (confmap URI
|
|
86
|
+
* schemes) are not components and are left out.
|
|
87
|
+
*/
|
|
88
|
+
export function parseManifest(text: string): ManifestModule[] {
|
|
89
|
+
const doc = yaml.load(text) as Record<string, unknown>;
|
|
90
|
+
const out: ManifestModule[] = [];
|
|
91
|
+
for (const [section, kind] of Object.entries(SECTION_KIND)) {
|
|
92
|
+
const entries = doc[section];
|
|
93
|
+
if (!Array.isArray(entries)) continue;
|
|
94
|
+
for (const entry of entries as Array<{ gomod?: string }>) {
|
|
95
|
+
const [module, version] = (entry.gomod ?? "").trim().split(/\s+/);
|
|
96
|
+
if (module && version) out.push({ kind, module, version });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── Where a Go package lives ────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/** The repository and tag a module's files are read from, or undefined for a module outside the two collector repos. */
|
|
105
|
+
export function locate(
|
|
106
|
+
pkg: string,
|
|
107
|
+
tags: { core: string; contrib: string },
|
|
108
|
+
): { repo: string; tag: string; path: string; root: string } | undefined {
|
|
109
|
+
for (const { module, repo } of REPOS) {
|
|
110
|
+
if (pkg === module || pkg.startsWith(`${module}/`)) {
|
|
111
|
+
return { repo, tag: module === CORE_MODULE ? tags.core : tags.contrib, path: pkg.slice(module.length + 1), root: module };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The repository root module a package belongs to, for resolving `/path` refs. */
|
|
118
|
+
export function repoRoot(pkg: string): string | undefined {
|
|
119
|
+
return REPOS.find(({ module }) => pkg === module || pkg.startsWith(`${module}/`))?.module;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Resolve a `$ref` written in document `from` (a Go package path) to the
|
|
124
|
+
* document it names and the definition inside it. A local ref returns `from`
|
|
125
|
+
* itself.
|
|
126
|
+
*/
|
|
127
|
+
export function resolveRef(from: string, ref: string): { doc: string; def: string } {
|
|
128
|
+
const dot = ref.lastIndexOf(".");
|
|
129
|
+
const slash = ref.lastIndexOf("/");
|
|
130
|
+
// `name`: no package part.
|
|
131
|
+
if (slash < 0 && !ref.startsWith(".")) return { doc: from, def: ref };
|
|
132
|
+
const pkgPart = dot > slash ? ref.slice(0, dot) : ref;
|
|
133
|
+
const def = dot > slash ? ref.slice(dot + 1) : "";
|
|
134
|
+
let doc: string;
|
|
135
|
+
if (pkgPart.startsWith("./")) doc = `${from}/${pkgPart.slice(2)}`;
|
|
136
|
+
else if (pkgPart.startsWith("/")) doc = `${repoRoot(from) ?? ""}${pkgPart}`;
|
|
137
|
+
else doc = pkgPart;
|
|
138
|
+
return { doc, def };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Every `$ref` string inside a schema document, in order. */
|
|
142
|
+
export function refsIn(node: unknown, out: string[] = []): string[] {
|
|
143
|
+
if (Array.isArray(node)) {
|
|
144
|
+
for (const n of node) refsIn(n, out);
|
|
145
|
+
} else if (node !== null && typeof node === "object") {
|
|
146
|
+
for (const [k, v] of Object.entries(node)) {
|
|
147
|
+
if (k === "$ref" && typeof v === "string") out.push(v);
|
|
148
|
+
else refsIn(v, out);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Fetching ────────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
async function fetchText(repo: string, tag: string, path: string, force?: boolean): Promise<string | undefined> {
|
|
157
|
+
try {
|
|
158
|
+
const buf = await fetchWithCache(
|
|
159
|
+
{ url: rawUrl(repo, tag, path), cacheFile: cacheFile(repo, tag, path), cacheTtlMs: TAG_TTL_MS },
|
|
160
|
+
force,
|
|
161
|
+
);
|
|
162
|
+
return buf.toString("utf-8");
|
|
163
|
+
} catch (err) {
|
|
164
|
+
// A missing file is an answer (this component ships no schema); anything
|
|
165
|
+
// else is not, and must not be read as one.
|
|
166
|
+
if (err instanceof Error && /returned 404\b/.test(err.message)) return undefined;
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** One component in a distribution's index. */
|
|
172
|
+
export interface IndexedComponent {
|
|
173
|
+
kind: ComponentKind;
|
|
174
|
+
/** The collector type its factory registers, from `metadata.yaml`. Absent for a module outside the collector repos. */
|
|
175
|
+
type?: string;
|
|
176
|
+
/** The older type the factory still accepts, when it was renamed. */
|
|
177
|
+
deprecatedType?: string;
|
|
178
|
+
module: string;
|
|
179
|
+
version: string;
|
|
180
|
+
/** The document key of its config schema, when upstream ships one. */
|
|
181
|
+
schema?: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** What `fetchUpstreamSpec` returns, and what the committed snapshot holds. */
|
|
185
|
+
export interface OtelSpecSnapshot {
|
|
186
|
+
versions: { "otelcol-contrib": string; "otelcol-k8s": string; core: string; contrib: string };
|
|
187
|
+
distributions: Record<DistributionName, IndexedComponent[]>;
|
|
188
|
+
/** Schema documents keyed by Go package path. */
|
|
189
|
+
schemas: Record<string, unknown>;
|
|
190
|
+
/** `$ref`ed documents that could not be read, and who asked for them. */
|
|
191
|
+
unresolved: Record<string, string[]>;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function pool<T, R>(items: T[], size: number, fn: (item: T) => Promise<R>): Promise<R[]> {
|
|
195
|
+
const out: R[] = new Array(items.length);
|
|
196
|
+
let next = 0;
|
|
197
|
+
await Promise.all(
|
|
198
|
+
Array.from({ length: Math.min(size, items.length) }, async () => {
|
|
199
|
+
while (next < items.length) {
|
|
200
|
+
const i = next++;
|
|
201
|
+
out[i] = await fn(items[i]);
|
|
202
|
+
}
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** The version a manifest uses for the modules of one repository, the most common one listed. */
|
|
209
|
+
function repoTag(modules: ManifestModule[], root: string): string {
|
|
210
|
+
const counts = new Map<string, number>();
|
|
211
|
+
for (const m of modules) if (m.module.startsWith(`${root}/`)) counts.set(m.version, (counts.get(m.version) ?? 0) + 1);
|
|
212
|
+
const best = [...counts].sort((a, b) => b[1] - a[1])[0];
|
|
213
|
+
if (!best) throw new Error(`no ${root} module in the manifest`);
|
|
214
|
+
return best[0];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Fetch both manifests at their tags, index every component they list, and
|
|
219
|
+
* collect the schema documents reachable from the components in `keep` (by
|
|
220
|
+
* collector type and kind). Other components are indexed (type, schema or
|
|
221
|
+
* not) but their schemas are not carried, so the snapshot stays the size of
|
|
222
|
+
* what the lexicon generates from.
|
|
223
|
+
*/
|
|
224
|
+
export async function fetchUpstreamSpec(options: {
|
|
225
|
+
contribVersion: string;
|
|
226
|
+
k8sVersion: string;
|
|
227
|
+
keep: ReadonlyArray<{ kind: ComponentKind; type: string }>;
|
|
228
|
+
force?: boolean;
|
|
229
|
+
log?: (message: string) => void;
|
|
230
|
+
}): Promise<OtelSpecSnapshot> {
|
|
231
|
+
const log = options.log ?? (() => {});
|
|
232
|
+
const releases = "open-telemetry/opentelemetry-collector-releases";
|
|
233
|
+
const manifests = {} as Record<DistributionName, ManifestModule[]>;
|
|
234
|
+
const distTags: Record<DistributionName, string> = { "otelcol-contrib": options.contribVersion, "otelcol-k8s": options.k8sVersion };
|
|
235
|
+
for (const dist of DISTRIBUTIONS) {
|
|
236
|
+
const text = await fetchText(releases, distTags[dist], `distributions/${dist}/manifest.yaml`, options.force);
|
|
237
|
+
if (text === undefined) throw new Error(`no manifest for ${dist} at ${distTags[dist]}`);
|
|
238
|
+
manifests[dist] = parseManifest(text);
|
|
239
|
+
log(`${dist} ${distTags[dist]}: ${manifests[dist].length} components`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const contribManifest = manifests["otelcol-contrib"];
|
|
243
|
+
const tags = { core: repoTag(contribManifest, CORE_MODULE), contrib: repoTag(contribManifest, CONTRIB_MODULE) };
|
|
244
|
+
|
|
245
|
+
// Index each distinct module once: its type, and where its schema is.
|
|
246
|
+
const modules = new Map<string, ManifestModule>();
|
|
247
|
+
for (const dist of DISTRIBUTIONS) for (const m of manifests[dist]) modules.set(m.module, m);
|
|
248
|
+
const docs = new Map<string, unknown>();
|
|
249
|
+
const info = new Map<string, { type?: string; deprecatedType?: string; schemaDoc?: string; schema?: unknown }>();
|
|
250
|
+
await pool([...modules.values()], 16, async (m) => {
|
|
251
|
+
const where = locate(m.module, tags);
|
|
252
|
+
if (!where) {
|
|
253
|
+
info.set(m.module, {});
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const meta = await fetchText(where.repo, where.tag, `${where.path}/metadata.yaml`, options.force);
|
|
257
|
+
const parsed = meta ? (yaml.load(meta) as { type?: string; deprecated_type?: string }) : {};
|
|
258
|
+
// Most components keep their config in the module root; a few
|
|
259
|
+
// (signaltometrics) in a `config` package below it.
|
|
260
|
+
let schemaDoc: string | undefined;
|
|
261
|
+
let schema: unknown;
|
|
262
|
+
for (const sub of ["", "/config"]) {
|
|
263
|
+
const text = await fetchText(where.repo, where.tag, `${where.path}${sub}/config.schema.yaml`, options.force);
|
|
264
|
+
if (text !== undefined) {
|
|
265
|
+
schemaDoc = `${m.module}${sub}`;
|
|
266
|
+
schema = yaml.load(text);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
info.set(m.module, { type: parsed.type, deprecatedType: parsed.deprecated_type, schemaDoc, schema });
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const distributions = {} as Record<DistributionName, IndexedComponent[]>;
|
|
274
|
+
for (const dist of DISTRIBUTIONS) {
|
|
275
|
+
distributions[dist] = manifests[dist]
|
|
276
|
+
.map((m) => {
|
|
277
|
+
const i = info.get(m.module)!;
|
|
278
|
+
const entry: IndexedComponent = { kind: m.kind, module: m.module, version: m.version };
|
|
279
|
+
if (i.type) entry.type = i.type;
|
|
280
|
+
if (i.deprecatedType) entry.deprecatedType = i.deprecatedType;
|
|
281
|
+
if (i.schemaDoc) entry.schema = i.schemaDoc;
|
|
282
|
+
return entry;
|
|
283
|
+
})
|
|
284
|
+
.sort((a, b) => a.kind.localeCompare(b.kind) || (a.type ?? a.module).localeCompare(b.type ?? b.module));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// The documents the kept components reach, transitively.
|
|
288
|
+
const unresolved: Record<string, string[]> = {};
|
|
289
|
+
const queue: string[] = [];
|
|
290
|
+
for (const want of options.keep) {
|
|
291
|
+
const hit = distributions["otelcol-contrib"].find(
|
|
292
|
+
(c) => c.kind === want.kind && (c.type === want.type || c.deprecatedType === want.type),
|
|
293
|
+
);
|
|
294
|
+
if (!hit?.schema) continue;
|
|
295
|
+
docs.set(hit.schema, info.get(hit.module)!.schema);
|
|
296
|
+
queue.push(hit.schema);
|
|
297
|
+
}
|
|
298
|
+
const seen = new Set<string>();
|
|
299
|
+
while (queue.length > 0) {
|
|
300
|
+
const batch = queue.splice(0).filter((d) => !seen.has(d));
|
|
301
|
+
for (const d of batch) seen.add(d);
|
|
302
|
+
const wanted = new Map<string, string[]>();
|
|
303
|
+
for (const d of batch) {
|
|
304
|
+
for (const ref of refsIn(docs.get(d))) {
|
|
305
|
+
const { doc } = resolveRef(d, ref);
|
|
306
|
+
if (doc === d || docs.has(doc) || seen.has(doc)) continue;
|
|
307
|
+
wanted.set(doc, [...(wanted.get(doc) ?? []), d]);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
await pool([...wanted.keys()], 16, async (doc) => {
|
|
311
|
+
const where = locate(doc, tags);
|
|
312
|
+
const text = where ? await fetchText(where.repo, where.tag, `${where.path}/config.schema.yaml`, options.force) : undefined;
|
|
313
|
+
if (text === undefined) {
|
|
314
|
+
unresolved[doc] = [...new Set(wanted.get(doc))].sort();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
docs.set(doc, yaml.load(text));
|
|
318
|
+
queue.push(doc);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const schemas: Record<string, unknown> = {};
|
|
323
|
+
for (const key of [...docs.keys()].sort()) schemas[key] = docs.get(key);
|
|
324
|
+
const sortedUnresolved: Record<string, string[]> = {};
|
|
325
|
+
for (const key of Object.keys(unresolved).sort()) sortedUnresolved[key] = unresolved[key];
|
|
326
|
+
return {
|
|
327
|
+
versions: { "otelcol-contrib": options.contribVersion, "otelcol-k8s": options.k8sVersion, ...tags },
|
|
328
|
+
distributions,
|
|
329
|
+
schemas,
|
|
330
|
+
unresolved: sortedUnresolved,
|
|
331
|
+
};
|
|
332
|
+
}
|