@intentius/chant-lexicon-otel 0.97.0 → 0.98.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 (37) hide show
  1. package/README.md +5 -0
  2. package/dist/codegen/docs.d.ts.map +1 -1
  3. package/dist/import/generator.d.ts +39 -0
  4. package/dist/import/generator.d.ts.map +1 -0
  5. package/dist/import/parser.d.ts +61 -0
  6. package/dist/import/parser.d.ts.map +1 -0
  7. package/dist/integrity.json +4 -4
  8. package/dist/lint/rules/literal-credential.d.ts.map +1 -1
  9. package/dist/manifest.json +1 -1
  10. package/dist/plugin.d.ts.map +1 -1
  11. package/dist/rules/literal-credential.ts +46 -17
  12. package/dist/skills/chant-otel.md +11 -0
  13. package/package.json +2 -2
  14. package/src/codegen/docs.ts +2 -1
  15. package/src/import/generated-types.e2e.test.ts +75 -0
  16. package/src/import/generator.test.ts +165 -0
  17. package/src/import/generator.ts +509 -0
  18. package/src/import/parser.test.ts +174 -0
  19. package/src/import/parser.ts +236 -0
  20. package/src/import/roundtrip.test.ts +365 -0
  21. package/src/import/testdata/agent-observability-agent.yaml +54 -0
  22. package/src/import/testdata/agent-observability-gateway.yaml +128 -0
  23. package/src/import/testdata/fixtures.ts +274 -0
  24. package/src/import/testdata/gateway.yaml +153 -0
  25. package/src/import/testdata/upstream/couchbase.yaml +150 -0
  26. package/src/import/testdata/upstream/fault-tolerant-logs.yaml +27 -0
  27. package/src/import/testdata/upstream/kubernetes-filelog.yaml +86 -0
  28. package/src/import/testdata/upstream/loadbalancing-agent.yaml +38 -0
  29. package/src/import/testdata/upstream/loadbalancing-backend.yaml +27 -0
  30. package/src/import/testdata/upstream/logline-filter-in.yaml +20 -0
  31. package/src/import/testdata/upstream/logline-filter-out.yaml +20 -0
  32. package/src/import/testdata/upstream/secure-tracing.yaml +26 -0
  33. package/src/import/testdata/upstream/servicegraph-nop.yaml +28 -0
  34. package/src/lint/rules/literal-credential.ts +46 -17
  35. package/src/lint/rules/rules.test.ts +16 -0
  36. package/src/plugin.ts +10 -0
  37. package/src/skills/chant-otel.md +11 -0
@@ -0,0 +1,128 @@
1
+ # The otel-gateway-config ConfigMap's config.yaml from examples/agent-observability,
2
+ # as that example builds it. Regenerate from examples/agent-observability/test/built.ts (gatewayConfigYaml).
3
+
4
+ # chant: semconv gen_ai github.com/open-telemetry/semantic-conventions@v1.41.1 (transform/genai_content, redaction/genai_content, filter/genai_spans, spanmetrics/genai, sum/genai_tokens)
5
+
6
+ receivers:
7
+ otlp:
8
+ protocols:
9
+ grpc:
10
+ endpoint: 0.0.0.0:4317
11
+
12
+ processors:
13
+ memory_limiter:
14
+ check_interval: 1s
15
+ limit_percentage: 80
16
+ spike_limit_percentage: 20
17
+ transform/genai_content:
18
+ error_mode: ignore
19
+ trace_statements:
20
+ - context: span
21
+ statements: ["delete_key(span.attributes, \"gen_ai.system_instructions\")", "delete_key(span.attributes, \"gen_ai.input.messages\")", "delete_key(span.attributes, \"gen_ai.output.messages\")", "delete_key(span.attributes, \"gen_ai.tool.call.arguments\")", "delete_key(span.attributes, \"gen_ai.tool.call.result\")", "delete_key(span.attributes, \"gen_ai.retrieval.query.text\")", "delete_key(span.attributes, \"gen_ai.retrieval.documents\")", "delete_key(span.attributes, \"gen_ai.prompt\")", "delete_key(span.attributes, \"gen_ai.completion\")", "delete_matching_keys(span.attributes, \"^gen_ai\\\\.(prompt|completion)\\\\.[0-9]+\\\\..+$\")"]
22
+ - context: spanevent
23
+ statements: ["delete_key(spanevent.attributes, \"gen_ai.system_instructions\")", "delete_key(spanevent.attributes, \"gen_ai.input.messages\")", "delete_key(spanevent.attributes, \"gen_ai.output.messages\")", "delete_key(spanevent.attributes, \"gen_ai.tool.call.arguments\")", "delete_key(spanevent.attributes, \"gen_ai.tool.call.result\")", "delete_key(spanevent.attributes, \"gen_ai.retrieval.query.text\")", "delete_key(spanevent.attributes, \"gen_ai.retrieval.documents\")", "delete_key(spanevent.attributes, \"gen_ai.prompt\")", "delete_key(spanevent.attributes, \"gen_ai.completion\")", "delete_matching_keys(spanevent.attributes, \"^gen_ai\\\\.(prompt|completion)\\\\.[0-9]+\\\\..+$\")"]
24
+ log_statements:
25
+ - context: log
26
+ statements: ["delete_key(log.attributes, \"gen_ai.system_instructions\")", "delete_key(log.attributes, \"gen_ai.input.messages\")", "delete_key(log.attributes, \"gen_ai.output.messages\")", "delete_key(log.attributes, \"gen_ai.tool.call.arguments\")", "delete_key(log.attributes, \"gen_ai.tool.call.result\")", "delete_key(log.attributes, \"gen_ai.retrieval.query.text\")", "delete_key(log.attributes, \"gen_ai.retrieval.documents\")", "delete_key(log.attributes, \"gen_ai.prompt\")", "delete_key(log.attributes, \"gen_ai.completion\")", "delete_matching_keys(log.attributes, \"^gen_ai\\\\.(prompt|completion)\\\\.[0-9]+\\\\..+$\")", "delete_matching_keys(log.body, \"^(content|message|tool_calls)$\") where IsMap(log.body) and (IsMatch(log.event_name, \"^(gen_ai\\\\.system\\\\.message|gen_ai\\\\.user\\\\.message|gen_ai\\\\.assistant\\\\.message|gen_ai\\\\.tool\\\\.message|gen_ai\\\\.choice)$\") or IsMatch(log.attributes[\"event.name\"], \"^(gen_ai\\\\.system\\\\.message|gen_ai\\\\.user\\\\.message|gen_ai\\\\.assistant\\\\.message|gen_ai\\\\.tool\\\\.message|gen_ai\\\\.choice)$\"))", "set(log.body, \"\") where IsString(log.body) and (IsMatch(log.event_name, \"^(gen_ai\\\\.system\\\\.message|gen_ai\\\\.user\\\\.message|gen_ai\\\\.assistant\\\\.message|gen_ai\\\\.tool\\\\.message|gen_ai\\\\.choice)$\") or IsMatch(log.attributes[\"event.name\"], \"^(gen_ai\\\\.system\\\\.message|gen_ai\\\\.user\\\\.message|gen_ai\\\\.assistant\\\\.message|gen_ai\\\\.tool\\\\.message|gen_ai\\\\.choice)$\"))"]
27
+ redaction/genai_content:
28
+ allow_all_keys: true
29
+ blocked_key_patterns: [^(gen_ai\.system_instructions|gen_ai\.input\.messages|gen_ai\.output\.messages|gen_ai\.tool\.call\.arguments|gen_ai\.tool\.call\.result|gen_ai\.retrieval\.query\.text|gen_ai\.retrieval\.documents|gen_ai\.prompt|gen_ai\.completion)$, "^gen_ai\\.(prompt|completion)\\.[0-9]+\\..+$"]
30
+ tail_sampling:
31
+ decision_wait: 5s
32
+ num_traces: 50000
33
+ policies:
34
+ - name: errors
35
+ type: status_code
36
+ status_code:
37
+ status_codes: [ERROR]
38
+ - name: slow
39
+ type: latency
40
+ latency:
41
+ threshold_ms: 2000
42
+ - name: baseline
43
+ type: probabilistic
44
+ probabilistic:
45
+ sampling_percentage: 10
46
+ batch:
47
+ timeout: 5s
48
+ filter/genai_spans:
49
+ error_mode: ignore
50
+ traces:
51
+ span: ["attributes[\"gen_ai.operation.name\"] == nil"]
52
+
53
+ exporters:
54
+ otlp/tempo:
55
+ endpoint: tempo:4317
56
+ tls:
57
+ insecure: true
58
+ prometheus:
59
+ endpoint: 0.0.0.0:8889
60
+ metric_expiration: 10m
61
+ otlphttp/loki:
62
+ endpoint: http://loki:3100/otlp
63
+
64
+ connectors:
65
+ spanmetrics:
66
+ histogram:
67
+ unit: ms
68
+ explicit:
69
+ buckets: [50ms, 100ms, 250ms, 500ms, 1s, 2s, 5s, 10s]
70
+ metrics_flush_interval: 15s
71
+ forward/genai: {}
72
+ forward/sampled: {}
73
+ spanmetrics/genai:
74
+ namespace: genai
75
+ dimensions:
76
+ - name: gen_ai.operation.name
77
+ - name: gen_ai.request.model
78
+ - name: gen_ai.tool.name
79
+ - name: error.type
80
+ histogram:
81
+ unit: s
82
+ explicit:
83
+ buckets: [100ms, 250ms, 500ms, 1s, 2s, 5s, 10s, 20s, 40s, 80s]
84
+ metrics_flush_interval: 15s
85
+ sum/genai_tokens:
86
+ spans:
87
+ genai.tokens.input:
88
+ source_attribute: gen_ai.usage.input_tokens
89
+ description: Input tokens used by GenAI operations
90
+ conditions: ["attributes[\"gen_ai.usage.input_tokens\"] != nil and not (kind == SPAN_KIND_INTERNAL and (attributes[\"gen_ai.operation.name\"] == \"invoke_agent\" or attributes[\"gen_ai.operation.name\"] == \"invoke_workflow\"))"]
91
+ attributes:
92
+ - key: gen_ai.request.model
93
+ default_value: unknown
94
+ genai.tokens.output:
95
+ source_attribute: gen_ai.usage.output_tokens
96
+ description: Output tokens used by GenAI operations
97
+ conditions: ["attributes[\"gen_ai.usage.output_tokens\"] != nil and not (kind == SPAN_KIND_INTERNAL and (attributes[\"gen_ai.operation.name\"] == \"invoke_agent\" or attributes[\"gen_ai.operation.name\"] == \"invoke_workflow\"))"]
98
+ attributes:
99
+ - key: gen_ai.request.model
100
+ default_value: unknown
101
+
102
+ extensions:
103
+ health_check:
104
+ endpoint: 0.0.0.0:13133
105
+
106
+ service:
107
+ extensions: [health_check]
108
+ pipelines:
109
+ traces:
110
+ receivers: [otlp]
111
+ processors: [memory_limiter, transform/genai_content, redaction/genai_content]
112
+ exporters: [spanmetrics, forward/genai, forward/sampled]
113
+ traces/sampled:
114
+ receivers: [forward/sampled]
115
+ processors: [tail_sampling, batch]
116
+ exporters: [otlp/tempo]
117
+ traces/genai:
118
+ receivers: [forward/genai]
119
+ processors: [filter/genai_spans]
120
+ exporters: [spanmetrics/genai, sum/genai_tokens]
121
+ metrics:
122
+ receivers: [otlp, spanmetrics, spanmetrics/genai, sum/genai_tokens]
123
+ processors: [memory_limiter, batch]
124
+ exporters: [prometheus]
125
+ logs:
126
+ receivers: [otlp]
127
+ processors: [memory_limiter, transform/genai_content, redaction/genai_content, batch]
128
+ exporters: [otlphttp/loki]
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Fixtures shared by the import round-trip tests (roundtrip.test.ts) and the
3
+ * type-check of the generated source (generated-types.e2e.test.ts).
4
+ */
5
+ import { readdirSync, readFileSync, statSync } from "fs";
6
+ import { join, resolve } from "path";
7
+ import { build } from "@intentius/chant/build";
8
+ import type { SerializerResult } from "@intentius/chant/serializer";
9
+ import type { Declarable } from "@intentius/chant/declarable";
10
+ import { otelSerializer } from "../../serializer";
11
+ import { Pipeline, Service } from "../../pipeline";
12
+ import * as c from "../../components";
13
+
14
+ export const pkgDir = resolve(import.meta.dirname, "../../..");
15
+ export const repoRoot = resolve(pkgDir, "../..");
16
+ export const read = (...p: string[]) => readFileSync(join(import.meta.dirname, ...p), "utf-8");
17
+
18
+ export function primary(out: string | SerializerResult | undefined): string {
19
+ if (out === undefined) return "";
20
+ return typeof out === "string" ? out : out.primary;
21
+ }
22
+
23
+ /** Each otel example's `chant build` output. */
24
+ export async function exampleOutputs(): Promise<Array<[string, string]>> {
25
+ const examplesDir = join(pkgDir, "examples");
26
+ const out: Array<[string, string]> = [];
27
+ for (const name of readdirSync(examplesDir).sort()) {
28
+ const srcDir = join(examplesDir, name, "src");
29
+ try {
30
+ if (!statSync(srcDir).isDirectory()) continue;
31
+ } catch {
32
+ continue;
33
+ }
34
+ const result = await build(srcDir, [otelSerializer]);
35
+ if (result.errors.length > 0) throw new Error(`${name}: ${result.errors.map(String).join("; ")}`);
36
+ out.push([name, primary(result.outputs.get("otel"))]);
37
+ }
38
+ return out;
39
+ }
40
+
41
+ export const UPSTREAM_BUILTIN_ONLY = [
42
+ "kubernetes-filelog.yaml",
43
+ "logline-filter-in.yaml",
44
+ "logline-filter-out.yaml",
45
+ "secure-tracing.yaml",
46
+ "loadbalancing-backend.yaml",
47
+ ];
48
+
49
+ /** One instance of every built-in, each using its typed fields, wired into pipelines the connectors accept. */
50
+ export function everyBuiltin(): Declarable[] {
51
+ const otlp = new c.OtlpReceiver({
52
+ protocols: {
53
+ grpc: { endpoint: "0.0.0.0:4317", max_recv_msg_size_mib: 16, keepalive: { server_parameters: { time: "30s" } } },
54
+ http: { endpoint: "0.0.0.0:4318", cors: { allowed_origins: ["https://*.example.com"] }, traces_url_path: "/v1/traces" },
55
+ },
56
+ });
57
+ const prometheusIn = new c.PrometheusReceiver({
58
+ name: "self",
59
+ config: {
60
+ global: { scrape_interval: "30s" },
61
+ scrape_configs: [{ job_name: "collector", scrape_interval: "10s", static_configs: [{ targets: ["localhost:8888"], labels: { tier: "gw" } }] }],
62
+ },
63
+ trim_metric_suffixes: true,
64
+ });
65
+ const hostmetrics = new c.HostMetricsReceiver({
66
+ collection_interval: "30s",
67
+ root_path: "/hostfs",
68
+ scrapers: { cpu: {}, memory: {}, filesystem: { exclude_mount_points: { match_type: "regexp", mount_points: ["/dev/.*"] } } },
69
+ });
70
+ const filelog = new c.FileLogReceiver({
71
+ include: ["/var/log/pods/*/*/*.log"],
72
+ exclude: ["/var/log/pods/*/otel-collector/*.log"],
73
+ start_at: "end",
74
+ include_file_path: true,
75
+ storage: "file_storage",
76
+ operators: [{ type: "container", id: "container-parser" }],
77
+ retry_on_failure: { enabled: true, initial_interval: "1s" },
78
+ });
79
+ const cluster = new c.K8sClusterReceiver({
80
+ auth_type: "serviceAccount",
81
+ collection_interval: "30s",
82
+ node_conditions_to_report: ["Ready", "MemoryPressure"],
83
+ allocatable_types_to_report: ["cpu", "memory"],
84
+ metrics: { "k8s.pod.phase": { enabled: false } },
85
+ });
86
+ const kubelet = new c.KubeletStatsReceiver({
87
+ auth_type: "serviceAccount",
88
+ endpoint: "https://${env:K8S_NODE_NAME}:10250",
89
+ insecure_skip_verify: true,
90
+ metric_groups: ["node", "pod", "container"],
91
+ extra_metadata_labels: ["container.id"],
92
+ });
93
+
94
+ const batch = new c.BatchProcessor({ timeout: "5s", send_batch_size: 1024, send_batch_max_size: 2048, metadata_keys: ["tenant"] });
95
+ const memoryLimiter = new c.MemoryLimiterProcessor({ check_interval: "1s", limit_mib: 1024, spike_limit_mib: 256 });
96
+ const resource = new c.ResourceProcessor({
97
+ attributes: [
98
+ { key: "deployment.environment", value: "${env:DEPLOY_ENV}", action: "upsert" },
99
+ { key: "host.id", action: "delete" },
100
+ ],
101
+ });
102
+ const attributes = new c.AttributesProcessor({
103
+ name: "scrub",
104
+ actions: [
105
+ { key: "user.email", action: "hash" },
106
+ { key: "http.status_code", action: "convert", converted_type: "int" },
107
+ ],
108
+ include: { match_type: "strict", services: ["checkout"] },
109
+ });
110
+ const k8sattributes = new c.K8sAttributesProcessor({
111
+ auth_type: "serviceAccount",
112
+ passthrough: false,
113
+ filter: { node_from_env_var: "K8S_NODE_NAME" },
114
+ extract: { metadata: ["k8s.pod.name", "k8s.namespace.name"], labels: [{ tag_name: "app", key: "app.kubernetes.io/name", from: "pod" }] },
115
+ pod_association: [{ sources: [{ from: "resource_attribute", name: "k8s.pod.ip" }] }, { sources: [{ from: "connection" }] }],
116
+ });
117
+ const resourcedetection = new c.ResourceDetectionProcessor({
118
+ detectors: ["env", "system", "gcp"],
119
+ timeout: "2s",
120
+ override: false,
121
+ system: { hostname_sources: ["os"] },
122
+ });
123
+ const filter = new c.FilterProcessor({
124
+ name: "health",
125
+ error_mode: "ignore",
126
+ traces: { span: ['attributes["http.route"] == "/healthz"'] },
127
+ metrics: { datapoint: ['metric.name == "up" and value_int == 1'] },
128
+ logs: { log_record: ["severity_number < SEVERITY_NUMBER_INFO"] },
129
+ });
130
+ const transform = new c.TransformProcessor({
131
+ error_mode: "ignore",
132
+ trace_statements: [{ context: "span", conditions: ["kind == SPAN_KIND_SERVER"], statements: ['set(attributes["tier"], "edge")'] }],
133
+ metric_statements: ['delete_key(datapoint.attributes, "pod_ip")'],
134
+ log_statements: [{ context: "log", statements: ['set(severity_text, "WARN") where severity_number == 13'] }],
135
+ });
136
+ const redaction = new c.RedactionProcessor({
137
+ allow_all_keys: true,
138
+ blocked_key_patterns: ["^gen_ai\\.(prompt|completion)"],
139
+ blocked_values: ["4[0-9]{12}(?:[0-9]{3})?"],
140
+ hash_function: "sha3",
141
+ summary: "silent",
142
+ });
143
+ const tailSampling = new c.TailSamplingProcessor({
144
+ decision_wait: "10s",
145
+ num_traces: 50000,
146
+ sample_on_first_match: true,
147
+ policies: [
148
+ { name: "errors", type: "status_code", status_code: { status_codes: ["ERROR"] } },
149
+ { name: "slow", type: "latency", latency: { threshold_ms: 1000, upper_threshold_ms: 60000 } },
150
+ { name: "vip", type: "boolean_attribute", boolean_attribute: { key: "vip", value: true } },
151
+ { name: "sized", type: "span_count", span_count: { min_spans: 2, max_spans: 500 } },
152
+ { name: "both", type: "and", and: { and_sub_policy: [{ name: "a", type: "rate_limiting", rate_limiting: { spans_per_second: 100 } }, { name: "b", type: "always_sample" }] } },
153
+ { name: "rest", type: "probabilistic", probabilistic: { sampling_percentage: 5, hash_salt: "s" } },
154
+ ],
155
+ });
156
+ const probabilistic = new c.ProbabilisticSamplerProcessor({ sampling_percentage: 12.5, mode: "proportional", sampling_precision: 4 });
157
+
158
+ const otlpOut = new c.OtlpExporter({
159
+ name: "backend",
160
+ endpoint: "backend:4317",
161
+ compression: "zstd",
162
+ headers: { "x-api-key": "${env:BACKEND_KEY}" },
163
+ tls: { insecure: false, ca_file: "/etc/ca.pem", min_version: "1.3" },
164
+ balancer_name: "round_robin",
165
+ timeout: "10s",
166
+ retry_on_failure: { enabled: true, max_elapsed_time: "2m" },
167
+ sending_queue: { enabled: true, num_consumers: 4, queue_size: 2000, sizer: "requests" },
168
+ });
169
+ const otlphttp = new c.OtlpHttpExporter({ endpoint: "https://otlp.example.com", encoding: "json", logs_endpoint: "https://logs.example.com/v1/logs" });
170
+ const debug = new c.DebugExporter({ verbosity: "detailed", sampling_initial: 5, sampling_thereafter: 200 });
171
+ const prometheusOut = new c.PrometheusExporter({
172
+ endpoint: "0.0.0.0:8889",
173
+ namespace: "otel",
174
+ const_labels: { cluster: "prod" },
175
+ metric_expiration: "5m",
176
+ resource_to_telemetry_conversion: { enabled: true },
177
+ });
178
+ const googlecloud = new c.GoogleCloudExporter({
179
+ project: "my-project",
180
+ metric: { prefix: "custom.googleapis.com", resource_filters: [{ prefix: "k8s." }] },
181
+ trace: { attribute_mappings: [{ key: "http.route", replacement: "/http/route" }] },
182
+ log: { default_log_name: "otel" },
183
+ });
184
+ const loadbalancing = new c.LoadBalancingExporter({
185
+ routing_key: "service",
186
+ protocol: { otlp: { timeout: "1s", tls: { insecure: true } } },
187
+ resolver: { k8s: { service: "sampling.observability", ports: [4317], return_hostnames: true } },
188
+ });
189
+
190
+ const spanmetrics = new c.SpanMetricsConnector({
191
+ namespace: "span.metrics",
192
+ dimensions: [{ name: "http.route" }, { name: "env", default: "dev" }],
193
+ histogram: { unit: "s", exponential: { max_size: 160 } },
194
+ exemplars: { enabled: true, max_per_data_point: 5 },
195
+ metrics_flush_interval: "15s",
196
+ aggregation_temporality: "AGGREGATION_TEMPORALITY_DELTA",
197
+ });
198
+ const servicegraph = new c.ServiceGraphConnector({
199
+ latency_histogram_buckets: ["10ms", "100ms", "1s"],
200
+ dimensions: ["k8s.cluster.name"],
201
+ store: { ttl: "2s", max_items: 1000 },
202
+ virtual_node_peer_attributes: ["db.name"],
203
+ });
204
+ const routing = new c.RoutingConnector({
205
+ table: [{ context: "resource", condition: 'attributes["tenant"] == "acme"', pipelines: ["traces/acme"] }],
206
+ default_pipelines: ["traces/rest"],
207
+ error_mode: "ignore",
208
+ });
209
+ const forward = new c.ForwardConnector({});
210
+ const count = new c.CountConnector({
211
+ spans: { "span.count": { description: "Spans by service", attributes: [{ key: "service.name", default_value: "unknown" }] } },
212
+ });
213
+ const sum = new c.SumConnector({
214
+ spans: { "span.bytes": { source_attribute: "bytes", description: "Bytes by route", conditions: ['attributes["bytes"] != nil'] } },
215
+ });
216
+
217
+ const health = new c.HealthCheckExtension({ endpoint: "0.0.0.0:13133", path: "/health", response_body: { healthy: "ok" } });
218
+ const pprof = new c.PprofExtension({ endpoint: "localhost:1777", block_profile_fraction: 3 });
219
+ const zpages = new c.ZPagesExtension({ endpoint: "localhost:55679" });
220
+
221
+ return [
222
+ otlp,
223
+ prometheusIn,
224
+ hostmetrics,
225
+ filelog,
226
+ cluster,
227
+ kubelet,
228
+ batch,
229
+ memoryLimiter,
230
+ resource,
231
+ attributes,
232
+ k8sattributes,
233
+ resourcedetection,
234
+ filter,
235
+ transform,
236
+ redaction,
237
+ tailSampling,
238
+ probabilistic,
239
+ otlpOut,
240
+ otlphttp,
241
+ debug,
242
+ prometheusOut,
243
+ googlecloud,
244
+ loadbalancing,
245
+ spanmetrics,
246
+ servicegraph,
247
+ routing,
248
+ forward,
249
+ count,
250
+ sum,
251
+ health,
252
+ pprof,
253
+ zpages,
254
+ new Pipeline({
255
+ signal: "traces",
256
+ receivers: [otlp],
257
+ processors: [memoryLimiter, k8sattributes, resourcedetection, resource, attributes, filter, transform, redaction, probabilistic],
258
+ exporters: [spanmetrics, servicegraph, count, sum, forward, routing, loadbalancing],
259
+ }),
260
+ new Pipeline({ signal: "traces", name: "acme", receivers: [routing], processors: [tailSampling, batch], exporters: [otlpOut] }),
261
+ new Pipeline({ signal: "traces", name: "rest", receivers: [routing, forward], processors: [batch], exporters: [googlecloud, debug] }),
262
+ new Pipeline({
263
+ signal: "metrics",
264
+ receivers: [otlp, prometheusIn, hostmetrics, cluster, kubelet, spanmetrics, servicegraph, count, sum],
265
+ processors: [memoryLimiter, filter, batch],
266
+ exporters: [prometheusOut, otlphttp],
267
+ }),
268
+ new Pipeline({ signal: "logs", receivers: [otlp, filelog], processors: [memoryLimiter, redaction, batch], exporters: [otlphttp, debug] }),
269
+ new Service({
270
+ extensions: [health, zpages, pprof],
271
+ telemetry: { logs: { level: "warn", encoding: "json" }, metrics: { level: "normal" }, resource: { "service.name": "gw" } },
272
+ }),
273
+ ];
274
+ }
@@ -0,0 +1,153 @@
1
+ # A two-tier trace gateway in one file. The front tier spreads spans across
2
+ # the sampling tier by trace id with the loadbalancing exporter; the sampling
3
+ # tier keeps whole traces with tail_sampling and derives RED metrics from
4
+ # every span with spanmetrics before sampling drops any.
5
+
6
+ receivers:
7
+ otlp:
8
+ protocols:
9
+ grpc:
10
+ endpoint: 0.0.0.0:4317
11
+ http:
12
+ endpoint: 0.0.0.0:4318
13
+ otlp/sampling:
14
+ protocols:
15
+ grpc:
16
+ endpoint: 0.0.0.0:14317
17
+
18
+ processors:
19
+ memory_limiter:
20
+ check_interval: 1s
21
+ limit_percentage: 75
22
+ spike_limit_percentage: 15
23
+ batch:
24
+ timeout: 5s
25
+ send_batch_size: 8192
26
+ tail_sampling:
27
+ decision_wait: 10s
28
+ num_traces: 100000
29
+ expected_new_traces_per_sec: 2000
30
+ decision_cache:
31
+ sampled_cache_size: 100000
32
+ policies:
33
+ - name: errors
34
+ type: status_code
35
+ status_code:
36
+ status_codes: [ERROR]
37
+ - name: slow
38
+ type: latency
39
+ latency:
40
+ threshold_ms: 1500
41
+ - name: checkout
42
+ type: string_attribute
43
+ string_attribute:
44
+ key: service.name
45
+ values: [checkout, payments]
46
+ - name: noisy-health
47
+ type: drop
48
+ drop:
49
+ drop_sub_policy:
50
+ - name: health-route
51
+ type: string_attribute
52
+ string_attribute:
53
+ key: http.route
54
+ values: [/healthz, /readyz]
55
+ - name: budget
56
+ type: composite
57
+ composite:
58
+ max_total_spans_per_second: 1000
59
+ policy_order: [errors-first, rest]
60
+ composite_sub_policy:
61
+ - name: errors-first
62
+ type: status_code
63
+ status_code:
64
+ status_codes: [ERROR]
65
+ - name: rest
66
+ type: always_sample
67
+ rate_allocation:
68
+ - policy: errors-first
69
+ percent: 60
70
+ - policy: rest
71
+ percent: 40
72
+
73
+ exporters:
74
+ loadbalancing:
75
+ routing_key: traceID
76
+ protocol:
77
+ otlp:
78
+ timeout: 2s
79
+ tls:
80
+ insecure: true
81
+ resolver:
82
+ dns:
83
+ hostname: otel-sampling-headless.observability.svc.cluster.local
84
+ port: "14317"
85
+ otlp/tempo:
86
+ endpoint: tempo.observability:4317
87
+ headers:
88
+ authorization: "Bearer ${env:TEMPO_TOKEN}"
89
+ tls:
90
+ insecure: false
91
+ ca_file: /etc/tls/ca.pem
92
+ sending_queue:
93
+ enabled: true
94
+ queue_size: 10000
95
+ retry_on_failure:
96
+ enabled: true
97
+ max_elapsed_time: 5m
98
+ prometheus:
99
+ endpoint: "0.0.0.0:8889"
100
+ namespace: gateway
101
+ resource_to_telemetry_conversion:
102
+ enabled: true
103
+
104
+ connectors:
105
+ spanmetrics:
106
+ namespace: traces.span.metrics
107
+ dimensions:
108
+ - name: http.route
109
+ - name: deployment.environment
110
+ default: "${env:DEPLOY_ENV}"
111
+ histogram:
112
+ explicit:
113
+ buckets: [10ms, 50ms, 100ms, 250ms, 1s, 5s]
114
+ exemplars:
115
+ enabled: true
116
+ metrics_flush_interval: 15s
117
+
118
+ extensions:
119
+ health_check:
120
+ endpoint: 0.0.0.0:13133
121
+ pprof:
122
+ endpoint: localhost:1777
123
+ zpages: {}
124
+
125
+ service:
126
+ extensions: [zpages, health_check]
127
+ telemetry:
128
+ logs:
129
+ level: info
130
+ encoding: json
131
+ metrics:
132
+ level: detailed
133
+ readers:
134
+ - pull:
135
+ exporter:
136
+ prometheus:
137
+ host: 0.0.0.0
138
+ port: 8888
139
+ resource:
140
+ service.name: otel-gateway
141
+ pipelines:
142
+ traces:
143
+ receivers: [otlp]
144
+ processors: [memory_limiter]
145
+ exporters: [loadbalancing]
146
+ traces/sampling:
147
+ receivers: [otlp/sampling]
148
+ processors: [memory_limiter, tail_sampling, batch]
149
+ exporters: [otlp/tempo, spanmetrics]
150
+ metrics/red:
151
+ receivers: [spanmetrics]
152
+ processors: [batch]
153
+ exporters: [prometheus]