log10x-mcp 1.29.11 → 1.29.12
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 +1 -0
- package/build/product-kb/docs/apps/mcp/tools/install/advise-install.md +15 -5
- package/build/product-kb/docs/apps/mcp/tools/install/configure-engine.md +101 -26
- package/build/product-kb/docs/apps/mcp/tools/install/setup-recurring.md +9 -6
- package/build/product-kb/docs/engine/launcher/extension.md +228 -0
- package/build/product-kb/docs/engine/launcher/index.md +8 -0
- package/build/product-kb/docs/summary.md +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ This server is open source under MIT. A Log10x product license (API key) unlocks
|
|
|
18
18
|
| "What's driving my cost right now?" | The repeating message types and services driving volume and cost, and what moved week over week. `log10x_top_patterns`, `log10x_whats_changing`, `log10x_services` |
|
|
19
19
|
| "Why did payments-svc spike?" | A single-call investigation: timeline, correlated patterns, and the strongest temporal evidence, with confidence shown so nothing is presented as proven cause. `log10x_investigate`, `log10x_metrics_that_moved`, `log10x_metric_overlay` |
|
|
20
20
|
| "This message type is noise, cut it." | Sample, drop, compact, tier down, or offload a chosen message type, with examples and trend so the action is clear. `log10x_pattern_mitigate`, `log10x_pattern_examples`, `log10x_pattern_trend` |
|
|
21
|
+
| "We are 100% Lambda, no cluster. Install there." | The install plan comes back for the serverless estate: the engine as a Lambda extension paired with the function's OTel collector, a CDK construct, and an AWS-native recurring tick over an S3 config plane. `log10x_advise_install`, `log10x_setup_recurring` |
|
|
21
22
|
| "Get me the actual events I offloaded." | Fetch the exact events back on demand from your own S3. `log10x_retriever_query`, `log10x_offload_add`, `log10x_retriever_register` |
|
|
22
23
|
| "Recognize more of my message types." | Build a custom symbol library from your own logs so the engine finds more savings. `log10x_compile`, `log10x_compile_link`, `log10x_compile_status` |
|
|
23
24
|
|
|
@@ -8,6 +8,8 @@ After [Discover env](discover-env.md) ran, pick the right Log10x app to deploy a
|
|
|
8
8
|
|
|
9
9
|
It returns a ranked comparison across Reporter, Receiver, and [Retriever](advise-retriever.md) when no goal is set, or a single concrete checklist when a goal is given (`cut-cost`, `compact`, `archive`, `just-metrics`).
|
|
10
10
|
|
|
11
|
+
On a serverless snapshot (Lambda functions running an OTel collector extension, no reachable cluster) the Kubernetes wizard is skipped entirely: the tool returns the [Extension](../../../../engine/launcher/extension.md) plan, collector splice, engine environment, CDK construct, and the Coralogix TCO policy path.
|
|
12
|
+
|
|
11
13
|
## :material-code-braces: Example
|
|
12
14
|
|
|
13
15
|
!!! tenx-ask "You"
|
|
@@ -96,11 +98,11 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
96
98
|
"prometheus"
|
|
97
99
|
]
|
|
98
100
|
},
|
|
99
|
-
"description": "Where the engine emits TenXSummary metrics. Multi-destination
|
|
101
|
+
"description": "Where the engine emits TenXSummary metrics. Multi-destination — a user can report to log10x SaaS AND their own backend simultaneously, e.g. `[\"log10x\", \"datadog\"]`. Choices: **log10x** (Log10x-managed Prometheus — recommended; no infra to run), **datadog**, **elastic**, **cloudwatch**, **prometheus** (customer-owned). The wizard pre-fills detected backends from the snapshot. The only mutual exclusion is `airgapped: true` + `\"log10x\"` in this list."
|
|
100
102
|
},
|
|
101
103
|
"airgapped": {
|
|
102
104
|
"type": "boolean",
|
|
103
|
-
"description": "When true, the Log10x agents send nothing to log10x.com
|
|
105
|
+
"description": "When true, the Log10x agents send nothing to log10x.com — engine metrics, license re-validation, and update checks all go silent. Use to reduce CISO friction. Conflicts with `\"log10x\"` in `backends` (the wizard surfaces the conflict). **Demo licenses cannot actually run airgapped** — the engine downgrades to online mode with a warning. The wizard surfaces this softly when both are picked."
|
|
104
106
|
},
|
|
105
107
|
"backend_credentials": {
|
|
106
108
|
"type": "object",
|
|
@@ -133,7 +135,7 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
133
135
|
"prometheus"
|
|
134
136
|
]
|
|
135
137
|
},
|
|
136
|
-
"description": "Per-backend credential configuration, keyed by backend kind (must be one of: log10x, datadog, elastic, cloudwatch, prometheus). **Only set for non-`log10x` backends
|
|
138
|
+
"description": "Per-backend credential configuration, keyed by backend kind (must be one of: log10x, datadog, elastic, cloudwatch, prometheus). **Only set for non-`log10x` backends** — `log10x` SaaS uses the license JWT and needs no extra credentials. Each entry has a `secretName` (the Kubernetes Secret the user creates out-of-band holding sensitive env vars like `DD_API_KEY`; default per backend is `<backend>-credentials`) and optional `plainValues` (overrides for non-sensitive env vars like `DD_SITE`). Example: `{ \"datadog\": { \"secretName\": \"datadog-secret\", \"plainValues\": { \"DD_SITE\": \"us5.datadoghq.com\" } } }`."
|
|
137
139
|
},
|
|
138
140
|
"license_source": {
|
|
139
141
|
"type": "string",
|
|
@@ -143,7 +145,7 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
143
145
|
"paste"
|
|
144
146
|
],
|
|
145
147
|
"default": "signin",
|
|
146
|
-
"description": "How the wizard should acquire the engine's license JWT. **Defaults to `\"signin\"`** when omitted
|
|
148
|
+
"description": "How the wizard should acquire the engine's license JWT. **Defaults to `\"signin\"`** when omitted — the wizard tries to mint a user-scoped license via the user's Auth0 session, and emits `signin_required` mode (chain through `log10x_signin_start` then re-invoke) when no session exists. Pass **`\"demo\"`** ONLY when the user explicitly asks for a quick 14-day anonymous demo (transient, can't run airgapped). Pass **`\"paste\"`** with `license_jwt_paste: \"<jwt>\"` when the user already has a JWT."
|
|
147
149
|
},
|
|
148
150
|
"license_jwt_paste": {
|
|
149
151
|
"type": "string",
|
|
@@ -171,7 +173,8 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
171
173
|
"required": [
|
|
172
174
|
"snapshot_id"
|
|
173
175
|
],
|
|
174
|
-
"additionalProperties": false
|
|
176
|
+
"additionalProperties": false,
|
|
177
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
175
178
|
}
|
|
176
179
|
```
|
|
177
180
|
|
|
@@ -263,6 +266,7 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
263
266
|
// `data.mode` and narrow to the per-mode shape.
|
|
264
267
|
mode:
|
|
265
268
|
| 'plan'
|
|
269
|
+
| 'serverless_plan'
|
|
266
270
|
| 'next_question'
|
|
267
271
|
| 'missing_snapshot'
|
|
268
272
|
| 'session_error'
|
|
@@ -299,6 +303,12 @@ A fresh `snapshot_id` from [Discover env](discover-env.md). No Log10x components
|
|
|
299
303
|
suggestions?: Array<{ unknown: string; did_you_mean: string | null }>;
|
|
300
304
|
valid_keys?: string[];
|
|
301
305
|
|
|
306
|
+
// mode === 'serverless_plan'
|
|
307
|
+
estate?: 'serverless';
|
|
308
|
+
function_count?: number;
|
|
309
|
+
functions_with_otel_extension?: number;
|
|
310
|
+
log_groups_unsubscribed?: number;
|
|
311
|
+
|
|
302
312
|
// mode === 'plan', fields below come from AdvisePlanSummary.
|
|
303
313
|
app?: 'reporter' | 'receiver' | 'retriever';
|
|
304
314
|
release_name?: string;
|
|
@@ -8,6 +8,8 @@ The unified per-pattern action-plan PR author. Derives a per-pattern policy from
|
|
|
8
8
|
|
|
9
9
|
The engine hot-reloads the CSV on the next gitops poll, with no restart and no event drops.
|
|
10
10
|
|
|
11
|
+
The rendered policy is two engine files: `caps.csv` (per-container byte caps) and a sibling `actions.csv` deciding each service's over-cap disposition. `kubectl_configmap` delivery writes both, plus `config-generation.csv` and `action-intent.json`, straight to the ConfigMap the engine's [Kubernetes lane](../../../../config/k8s.md) pulls.
|
|
12
|
+
|
|
11
13
|
Two modes:
|
|
12
14
|
|
|
13
15
|
- **configure** (default): derive a fresh policy and open a PR
|
|
@@ -63,6 +65,24 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
63
65
|
"default": "configure",
|
|
64
66
|
"description": "`configure` (default) = derive a fresh per-pattern policy and open a PR. `refresh` = re-pull TSDB metrics for an already-deployed policy, compare observed volume to the cap-CSV preamble baseline, and open a delta PR only when the volume has drifted beyond `tolerance_pct`. Use `refresh` from cron/agent loops after the engine is live and 10x metrics are flowing. Requires `current_csv` carrying the prior `# target_percent=N` preamble; if absent, falls back to `target_percent` arg or returns target_resolution."
|
|
65
67
|
},
|
|
68
|
+
"delivery": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": [
|
|
71
|
+
"gitops",
|
|
72
|
+
"kubectl_configmap",
|
|
73
|
+
"stdout_only"
|
|
74
|
+
],
|
|
75
|
+
"default": "gitops",
|
|
76
|
+
"description": "How the rendered policy is delivered. `gitops` (default) opens a PR against the customer gitops repo (requires `gitops_repo`). `kubectl_configmap` writes caps.csv + actions.csv + config-generation.csv + action-intent.json directly to a k8s ConfigMap on the active cluster (no GitHub needed; the engine's ConfigMap pull driver reads from the ConfigMap named via $K8S_CONFIGMAP, default `log10x-action-intent`). `stdout_only` returns the proposed config in the response without writing anywhere."
|
|
77
|
+
},
|
|
78
|
+
"kubectl_namespace": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"description": "k8s namespace for the policy ConfigMap when delivery=\"kubectl_configmap\". Defaults to `default` — pass the namespace the receiver runs in (the engine's ConfigMap pull driver reads from its own pod namespace)."
|
|
81
|
+
},
|
|
82
|
+
"kubectl_configmap_name": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "k8s ConfigMap name when delivery=\"kubectl_configmap\". Defaults to `log10x-action-intent` (matching the engine's default $K8S_CONFIGMAP env var). The ConfigMap holds `caps.csv` (engine per-container byte caps), `actions.csv` (engine per-service action for the over-cap slice), `config-generation.csv` (policy-generation stamp), and `action-intent.json` (per-pattern intent read back by commitment_report / estimate_savings; the engine ignores it)."
|
|
85
|
+
},
|
|
66
86
|
"tolerance_pct": {
|
|
67
87
|
"type": "number",
|
|
68
88
|
"minimum": 0,
|
|
@@ -103,11 +123,11 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
103
123
|
"gcp-logging",
|
|
104
124
|
"sumo"
|
|
105
125
|
],
|
|
106
|
-
"description": "Destination
|
|
126
|
+
"description": "Destination log platform. Auto-detect only works when a `snapshot_id` from log10x_discover_env is supplied (the snapshot carries `recommendations.destination`) or when the active env in `~/.log10x/envs.json` explicitly sets a `destination` field. Most active envs do NOT carry that field, so for typical use you should pass `destination` explicitly: `splunk` | `datadog` | `elasticsearch` | `clickhouse` | `cloudwatch` | `azure-monitor` | `gcp-logging` | `sumo`."
|
|
107
127
|
},
|
|
108
128
|
"es_pruned": {
|
|
109
129
|
"type": "boolean",
|
|
110
|
-
"description": "Elasticsearch only: are compactable fields excluded from `_source` via index template? Default `false` (unpruned). Auto-detection requires reading the customer index template; this knob is the explicit override.
|
|
130
|
+
"description": "Elasticsearch only: are compactable fields excluded from `_source` via index template? Default `false` (unpruned). Auto-detection requires reading the customer index template; this knob is the explicit override."
|
|
111
131
|
},
|
|
112
132
|
"contract_type": {
|
|
113
133
|
"type": "string",
|
|
@@ -148,6 +168,19 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
148
168
|
"action_defaults": {
|
|
149
169
|
"type": "object",
|
|
150
170
|
"properties": {
|
|
171
|
+
"error": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"enum": [
|
|
174
|
+
"pass",
|
|
175
|
+
"sample",
|
|
176
|
+
"compact",
|
|
177
|
+
"tier_down",
|
|
178
|
+
"offload",
|
|
179
|
+
"drop"
|
|
180
|
+
],
|
|
181
|
+
"default": "pass",
|
|
182
|
+
"description": "Default action for error-tier patterns (severity `error`/`warn`/`warning`; `critical`/`fatal` are audit-tier and always `pass`). Defaults to `pass` — error-class lines are kept verbatim, which is what the POC report tells the customer. Set this explicitly to opt into reducing them, and prefer a lossless lever (`compact`/`tier_down`/`offload`) over `sample`/`drop`."
|
|
183
|
+
},
|
|
151
184
|
"standard": {
|
|
152
185
|
"type": "string",
|
|
153
186
|
"enum": [
|
|
@@ -190,7 +223,12 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
190
223
|
},
|
|
191
224
|
"additionalProperties": false,
|
|
192
225
|
"default": {},
|
|
193
|
-
"description": "Tier-to-action defaults. Audit-tier is always `pass
|
|
226
|
+
"description": "Tier-to-action defaults. Audit-tier is always `pass` and is not configurable. Error-tier defaults to `pass` (kept verbatim); standard defaults to `compact`; debug and synthetic default to `drop`. When a pinned `sample` is projected, N=10 (keep 1 in 10)."
|
|
227
|
+
},
|
|
228
|
+
"respect_default_action": {
|
|
229
|
+
"type": "boolean",
|
|
230
|
+
"default": false,
|
|
231
|
+
"description": "When false (default), the solver shortcuts to `pass` on error/standard/debug/synthetic rows once `target_percent` has already been met by higher-priority rows earlier in the greedy walk — minimum work, may ignore your configured `action_defaults`. When true, the solver applies `action_defaults` to EVERY non-floor row in the matching tier, even after target is already met. Use when you want a predictable action mix (e.g., \"I asked for offload, give me offload\") and are OK with the policy overshooting target_percent. Surfaces in `action_default_resolution.respect_default_action` for audit."
|
|
194
232
|
},
|
|
195
233
|
"reduction": {
|
|
196
234
|
"type": "string",
|
|
@@ -232,7 +270,7 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
232
270
|
},
|
|
233
271
|
"from_poc_id": {
|
|
234
272
|
"type": "string",
|
|
235
|
-
"description": "POC snapshot id returned by `log10x_poc_from_siem_submit` (or the from-local equivalent). When set and the snapshot carries a `cap_csv` (i.e., the POC was run with `target_percent_reduction`), the tool reads that CSV verbatim and renders it as the PR body
|
|
273
|
+
"description": "POC snapshot id returned by `log10x_poc_from_siem_submit` (or the from-local equivalent). When set and the snapshot carries a `cap_csv` (i.e., the POC was run with `target_percent_reduction`), the tool reads that CSV verbatim and renders it as the PR body — no Prometheus pull, no greedy re-derivation. Falls back to the live-Prometheus derivation when the snapshot has no cap_csv (or no `target_percent_reduction` was supplied to the POC)."
|
|
236
274
|
},
|
|
237
275
|
"auto_apply": {
|
|
238
276
|
"type": "boolean",
|
|
@@ -244,26 +282,6 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
244
282
|
"default": false,
|
|
245
283
|
"description": "When `true`, behaves as if `auto_apply=false` regardless of other flags. Use for evaluation, audit, or in MCP contexts without an approval surface (cron, headless agents). Mirrors `github/github-mcp-server --read-only`."
|
|
246
284
|
},
|
|
247
|
-
"delivery": {
|
|
248
|
-
"type": "string",
|
|
249
|
-
"enum": [
|
|
250
|
-
"gitops",
|
|
251
|
-
"kubectl_configmap",
|
|
252
|
-
"stdout_only",
|
|
253
|
-
"auto"
|
|
254
|
-
],
|
|
255
|
-
"default": "auto",
|
|
256
|
-
"description": "Which writer delivers the rendered action-intent + cap CSV. `gitops` opens a PR via gh (slow review loop, safest). `kubectl_configmap` applies a ConfigMap directly to the receiver namespace (fast iteration, requires kubectl access). `stdout_only` returns the rendered files in the envelope without writing. `auto` (default) picks based on snapshot: gitops if `gitops.repo` is known; else kubectl_configmap if a cluster was probed; else stdout_only."
|
|
257
|
-
},
|
|
258
|
-
"delivery_namespace": {
|
|
259
|
-
"type": "string",
|
|
260
|
-
"description": "kubectl_configmap delivery only: target k8s namespace for the ConfigMap. Defaults to the receiver pod namespace discovered in the snapshot (typically `demo` or `otel-demo`). Falls back to `default` when no snapshot."
|
|
261
|
-
},
|
|
262
|
-
"delivery_configmap": {
|
|
263
|
-
"type": "string",
|
|
264
|
-
"default": "log10x-action-intent",
|
|
265
|
-
"description": "kubectl_configmap delivery only: name of the ConfigMap to write. The engine's ConfigMap pull source reads this name in the receiver namespace. Default matches the canonical name the engine expects."
|
|
266
|
-
},
|
|
267
285
|
"view": {
|
|
268
286
|
"type": "string",
|
|
269
287
|
"enum": [
|
|
@@ -272,13 +290,70 @@ Reporter deployed for metrics. GitOps repo configured (`gitops_repo` arg or `git
|
|
|
272
290
|
"pr_command_only"
|
|
273
291
|
],
|
|
274
292
|
"default": "summary",
|
|
275
|
-
"description": "Response shape. `summary` (default) returns
|
|
293
|
+
"description": "Response shape. `summary` (default) returns slim payload: phase, target_percent, action_mix counts, totals (bytes_in / bytes_saved / dollars_saved monthly), top_5_per_pattern, and a short PR-command prose summary. Target: under 8K tokens for a 119-pattern policy. `detail` returns the full envelope with pr_command, per_pattern_rows, and csv_diff included. `pr_command_only` returns ONLY the pr_command string for copy-paste callers."
|
|
294
|
+
},
|
|
295
|
+
"service_policy": {
|
|
296
|
+
"type": "object",
|
|
297
|
+
"additionalProperties": {
|
|
298
|
+
"type": "object",
|
|
299
|
+
"properties": {
|
|
300
|
+
"standard_action": {
|
|
301
|
+
"type": "string",
|
|
302
|
+
"enum": [
|
|
303
|
+
"pass",
|
|
304
|
+
"sample",
|
|
305
|
+
"compact",
|
|
306
|
+
"tier_down",
|
|
307
|
+
"offload",
|
|
308
|
+
"drop"
|
|
309
|
+
],
|
|
310
|
+
"description": "Pin this service (k8s_container) standard-tier action, overriding the auto-recommendation. An action that is illegal or zero-saving on the env destination (e.g. compact on Datadog, tier_down with no cheaper tier) is rejected with a warning and the service falls back to its normal resolution (the compressibility auto-recommendation, or the global action_defaults.standard when auto_recommend is off)."
|
|
311
|
+
},
|
|
312
|
+
"keep_queryable": {
|
|
313
|
+
"type": "boolean",
|
|
314
|
+
"description": "When true, force the in-platform compact action wherever compact is legal on the destination, keeping this service queryable in the destination rather than offloading to S3, even when its compaction is modest. No effect on destinations where compact is a no-op (Datadog/CloudWatch/Azure/GCP/Sumo); there the queryable lever is tier_down, already preferred when it has a priced cheaper tier."
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"additionalProperties": false
|
|
318
|
+
},
|
|
319
|
+
"description": "Per-service override map keyed by k8s_container name. A service absent from the map is auto-recommended. Pinned actions win unless illegal on the destination."
|
|
320
|
+
},
|
|
321
|
+
"auto_recommend": {
|
|
322
|
+
"type": "boolean",
|
|
323
|
+
"default": true,
|
|
324
|
+
"description": "When true (default), services without a `service_policy` entry get a per-service auto-recommended standard-tier action (cost-optimal within the destination legal set, compressibility-driven). When false, every service falls back to the single global `action_defaults.standard` (legacy one-size behavior)."
|
|
325
|
+
},
|
|
326
|
+
"compact_worth_it_ratio": {
|
|
327
|
+
"type": "number",
|
|
328
|
+
"minimum": 0,
|
|
329
|
+
"maximum": 1,
|
|
330
|
+
"default": 0.6,
|
|
331
|
+
"description": "Compressibility threshold for the compact-vs-offload auto-recommendation: a service whose measured optimized/input ratio (or the destination modeled compaction band when no measured ratio is available) is at or below this keeps `compact` (queryable plus a meaningful cut); above it `offload` is recommended (compact would save little). Default 0.6."
|
|
332
|
+
},
|
|
333
|
+
"service_compaction": {
|
|
334
|
+
"type": "object",
|
|
335
|
+
"additionalProperties": {
|
|
336
|
+
"type": "object",
|
|
337
|
+
"properties": {
|
|
338
|
+
"compaction_ratio_x": {
|
|
339
|
+
"type": "number",
|
|
340
|
+
"exclusiveMinimum": 0,
|
|
341
|
+
"description": "Measured aggregate compaction (original bytes / encoded bytes) for this service, from `log10x_measure_compaction.data.payload.aggregate_compaction_ratio_x`."
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
"required": [
|
|
345
|
+
"compaction_ratio_x"
|
|
346
|
+
],
|
|
347
|
+
"additionalProperties": false
|
|
348
|
+
},
|
|
349
|
+
"description": "Per-service measured compaction from `log10x_measure_compaction`, keyed by k8s_container. Grounds the per-service advisory in the real codec BEFORE optimize mode is deployed (the live optimize-mode metric only exists after deployment). Precedence for each service compressibility signal: live production metric (when optimize mode is running) wins, else this on-demand sample, else the static destination band. Run `log10x_measure_compaction` per service first, then pass `{ \"<k8s_container>\": { compaction_ratio_x: N } }`."
|
|
276
350
|
}
|
|
277
351
|
},
|
|
278
352
|
"required": [
|
|
279
353
|
"service"
|
|
280
354
|
],
|
|
281
|
-
"additionalProperties": false
|
|
355
|
+
"additionalProperties": false,
|
|
356
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
282
357
|
}
|
|
283
358
|
```
|
|
284
359
|
|
|
@@ -11,6 +11,7 @@ The scheduler manifest is one of:
|
|
|
11
11
|
- Kubernetes CronJob
|
|
12
12
|
- GitHub Actions workflow
|
|
13
13
|
- crontab + wrapper script
|
|
14
|
+
- EventBridge Scheduler + CodeBuild (CloudFormation template, S3 config plane)
|
|
14
15
|
|
|
15
16
|
## :material-code-braces: Example
|
|
16
17
|
|
|
@@ -31,10 +32,11 @@ The scheduler manifest is one of:
|
|
|
31
32
|
- *"recurring policy: payments and checkout, 40%, daily 3am UTC"*
|
|
32
33
|
- *"emit a k8s CronJob that trims 25% off cart-svc weekly"*
|
|
33
34
|
- *"schedule a GitHub Actions tick every 6h against acme/log10x-config"*
|
|
35
|
+
- *"AWS-native tick for our Lambda estate, no cluster, no GitHub"*
|
|
34
36
|
|
|
35
37
|
## :material-check-decagram-outline: Prerequisites
|
|
36
38
|
|
|
37
|
-
Reporter deployed (metrics drive the per-pattern planner that the tick invokes). A
|
|
39
|
+
Reporter deployed (metrics drive the per-pattern planner that the tick invokes). A config plane for `policy.yaml`, a gitops repo, local path, or S3 prefix, and credentials for the chosen scheduler (`kubectl` access for `k8s_cron`, repo write for `github_actions`, host shell for `crontab`, CloudFormation deploy rights for `eventbridge`).
|
|
38
40
|
|
|
39
41
|
## :material-code-json: Schema and samples
|
|
40
42
|
|
|
@@ -63,7 +65,7 @@ Reporter deployed (metrics drive the per-pattern planner that the tick invokes).
|
|
|
63
65
|
"properties": {
|
|
64
66
|
"session_id": {
|
|
65
67
|
"type": "string",
|
|
66
|
-
"description": "Wizard session handle. Omit on the first call
|
|
68
|
+
"description": "Wizard session handle. Omit on the first call — a new session is minted and returned. Pass it back unchanged on every subsequent call."
|
|
67
69
|
},
|
|
68
70
|
"target_services": {
|
|
69
71
|
"type": "array",
|
|
@@ -102,14 +104,15 @@ Reporter deployed (metrics drive the per-pattern planner that the tick invokes).
|
|
|
102
104
|
"enum": [
|
|
103
105
|
"k8s_cron",
|
|
104
106
|
"github_actions",
|
|
105
|
-
"crontab"
|
|
107
|
+
"crontab",
|
|
108
|
+
"eventbridge"
|
|
106
109
|
],
|
|
107
|
-
"description": "Where the recurring tick runs. k8s_cron = Kubernetes CronJob (default when kubectl reachable), github_actions = GHA workflow, crontab = crontab + wrapper script."
|
|
110
|
+
"description": "Where the recurring tick runs. k8s_cron = Kubernetes CronJob (default when kubectl reachable), github_actions = GHA workflow, crontab = crontab + wrapper script, eventbridge = AWS-native (EventBridge Scheduler + CodeBuild, S3 config plane — no cluster, no GitHub; the fit for serverless estates)."
|
|
108
111
|
},
|
|
109
112
|
"config_plane": {
|
|
110
113
|
"type": "string",
|
|
111
114
|
"minLength": 1,
|
|
112
|
-
"description": "
|
|
115
|
+
"description": "Where the recurring CLI reads policy.yaml and writes updated cap CSVs: a gitops repo URL (e.g. https://github.com/acme/log10x-config), a local path, or — required when scheduler=eventbridge — an S3 prefix (e.g. s3://acme-logs/log10x-config)."
|
|
113
116
|
},
|
|
114
117
|
"exceptions": {
|
|
115
118
|
"type": "array",
|
|
@@ -117,7 +120,7 @@ Reporter deployed (metrics drive the per-pattern planner that the tick invokes).
|
|
|
117
120
|
"type": "string",
|
|
118
121
|
"minLength": 1
|
|
119
122
|
},
|
|
120
|
-
"description": "Service names the policy must never touch (audit / regulatory / executive). Optional
|
|
123
|
+
"description": "Service names the policy must never touch (audit / regulatory / executive). Optional — defaults to empty. Pass [] to explicitly clear all exceptions."
|
|
121
124
|
},
|
|
122
125
|
"min_delta_pp": {
|
|
123
126
|
"type": "integer",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: material/puzzle-outline
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Extension runs the 10x Engine as its own [Lambda extension](https://docs.aws.amazon.com/lambda/latest/dg/lambda-extensions.html){target="\_blank"} inside each function's execution environment, paired over loopback with the [OTel collector extension](https://github.com/open-telemetry/opentelemetry-lambda){target="\_blank"} the function already runs. The collector hands every log record to the engine and receives it back regulated, routed, and hashed. No code changes, no new infrastructure, and nothing leaves the sandbox.
|
|
6
|
+
|
|
7
|
+
:material-ice-cream: This launcher employs the [Runtime flavor](https://doc.log10x.com/engine/flavors/#runtime) (native binary).
|
|
8
|
+
|
|
9
|
+
***Use-case***:
|
|
10
|
+
|
|
11
|
+
Per-pattern regulation on serverless estates. A 100% Lambda shop has no node, no DaemonSet, and no forwarder host to install onto; the execution environment itself is the edge. The extension applies the same receive pipeline the [Receiver](https://doc.log10x.com/apps/receiver/) runs on Kubernetes: tag noisy patterns for cheaper storage tiers, offload slices to your own S3, and mute what nobody reads, before the first byte leaves the function.
|
|
12
|
+
|
|
13
|
+
## :material-puzzle-outline: Benefits
|
|
14
|
+
|
|
15
|
+
### :material-layers-outline: A Layer, Not a Rebuild
|
|
16
|
+
|
|
17
|
+
The engine ships as a single Lambda layer: the native bootstrap under `extensions/`, with modules, config, and the symbol library under `/opt/tenx`. Attaching it to a function is a layer ARN plus environment variables; removing it is removing them. The layer unpacks to ~180 MB of Lambda's 250 MB shared layer budget.
|
|
18
|
+
|
|
19
|
+
### :material-target: Per-Pattern Control
|
|
20
|
+
|
|
21
|
+
Dispositions are keyed by pattern identity (`message_pattern`), not by function. A mute file decides each pattern's rate, with an explicit expiry and reason per entry, and a severity retention floor keeps ERROR/FATAL traffic flowing even under a full mute.
|
|
22
|
+
|
|
23
|
+
### :material-cloud-sync-outline: Policy Without Redeploys
|
|
24
|
+
|
|
25
|
+
`TENX_RECEIVE_MUTE_S3_URI` points the extension at a mute file in your own bucket. It fetches at INIT and refreshes on invoke (default 5 minutes), so one `aws s3 cp` converges every function. A failed fetch keeps the last good copy; dispositions degrade to the previous state, never to none.
|
|
26
|
+
|
|
27
|
+
### :material-lock-outline: Nothing Leaves the Sandbox
|
|
28
|
+
|
|
29
|
+
The collector pairing is loopback-only, and `TENX_AIRGAPPED=true` silences all engine egress to log10x. The only network path the extension adds is to your own S3 bucket, and only when you configure one.
|
|
30
|
+
|
|
31
|
+
## :material-hexagon-multiple-outline: Architecture Flow
|
|
32
|
+
|
|
33
|
+
<div style="text-align: center;">
|
|
34
|
+
|
|
35
|
+
```mermaid
|
|
36
|
+
graph LR
|
|
37
|
+
A["Function<br/>Code"] -->|"Logs"| B["OTel Collector<br/>Extension"]
|
|
38
|
+
B -->|"1. OTLP<br/>127.0.0.1:4317"| C["10x Engine<br/>Extension"]
|
|
39
|
+
C -->|"2. Regulated events<br/>127.0.0.1:24225"| B
|
|
40
|
+
B -->|"3. routeState<br/>routing"| D["Destination<br/>(SIEM)"]
|
|
41
|
+
B -->|"offload slice"| E["Your S3<br/>Bucket"]
|
|
42
|
+
|
|
43
|
+
classDef aws fill:#ff9900,stroke:#cc7a00,color:#ffffff,stroke-width:2px,rx:8,ry:8
|
|
44
|
+
classDef tenx fill:#059669,stroke:#047857,color:#ffffff,stroke-width:2px,rx:8,ry:8
|
|
45
|
+
classDef forwarder fill:#3b82f6,stroke:#1d4ed8,color:#ffffff,stroke-width:2px,rx:8,ry:8
|
|
46
|
+
classDef destination fill:#6b7280,stroke:#4b5563,color:#ffffff,stroke-width:2px,rx:8,ry:8
|
|
47
|
+
|
|
48
|
+
class A aws
|
|
49
|
+
class B forwarder
|
|
50
|
+
class C tenx
|
|
51
|
+
class D destination
|
|
52
|
+
class E aws
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="diagram-controls">
|
|
58
|
+
<button class="md-button md-button--primary enlarge-diagram"
|
|
59
|
+
onclick="enlargeDiagram(this)"
|
|
60
|
+
data-diagram="extension"
|
|
61
|
+
data-tooltip="Click to enlarge diagram">
|
|
62
|
+
<span class="twemoji">
|
|
63
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
|
|
64
|
+
<path d="M10 2c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9L20.59 19l-1.41 1.41-4.09-4.09A7.84 7.84 0 0 1 10 18c-4.42 0-8-3.58-8-8s3.58-8 8-8m0 2a6 6 0 1 0 0 12 6 6 0 0 0 0-12m1 3h2v2h-2V7m-4 0h2v2H7V7m2 4h2v2H9v-2Z"/>
|
|
65
|
+
</svg>
|
|
66
|
+
</span>
|
|
67
|
+
Enlarge Diagram
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
<!-- Mermaid enhanced diagram functionality loaded via external files -->
|
|
71
|
+
|
|
72
|
+
**1. The function logs** as it always has. The collector extension picks events up through its existing receivers.
|
|
73
|
+
|
|
74
|
+
**2. The collector hands each record** to the engine over loopback OTLP/gRPC (`127.0.0.1:4317`) and receives it back on `127.0.0.1:24225`, now carrying `tenx_hash` (stable pattern identity) and `routeState` (the pattern's disposition) as log attributes.
|
|
75
|
+
|
|
76
|
+
**3. A routing connector fans out** on `routeState`: the SIEM slice ships through the existing exporter unchanged, the offload slice lands in your S3 bucket in the layout the [Retriever](https://doc.log10x.com/apps/retriever/) indexes, and drops end at the sandbox.
|
|
77
|
+
|
|
78
|
+
## :material-rocket-launch: Deployment
|
|
79
|
+
|
|
80
|
+
The [log10x MCP](https://doc.log10x.com/apps/mcp/) emits this entire plan from a discovery snapshot ([Advise](https://doc.log10x.com/apps/mcp/tools/install/advise-install/) returns it directly on a serverless estate, including a CDK construct). The steps below are the manual path.
|
|
81
|
+
|
|
82
|
+
??? tenx-bootstrap "Step 1: Prerequisites"
|
|
83
|
+
|
|
84
|
+
| Requirement | Description |
|
|
85
|
+
|-------------|-------------|
|
|
86
|
+
| Log10x License | A full (non-demo) license ([get one](https://doc.log10x.com/run/bootstrap/#apikey)). Demo licenses cannot run airgapped, and `TENX_AIRGAPPED=true` is required here |
|
|
87
|
+
| AWS CLI | [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html){target="\_blank"} configured with Lambda and S3 permissions |
|
|
88
|
+
| GitHub CLI | [gh](https://cli.github.com){target="\_blank"} for pulling release artifacts |
|
|
89
|
+
| OTel Collector Extension | The target functions already run a collector extension with `routing` and `decouple` components (the community Lambda collector layer has both; a minimal custom build may not) |
|
|
90
|
+
| S3 Bucket | Optional. One bucket serves both the offload slice and live mute-file delivery |
|
|
91
|
+
|
|
92
|
+
??? tenx-cloud "Step 2: Build and Publish the Layer"
|
|
93
|
+
|
|
94
|
+
The layer builds from the published release artifacts. Engine 1.1.68 or later carries the S3 mute fetch:
|
|
95
|
+
|
|
96
|
+
``` { .console .copy }
|
|
97
|
+
gh release download 1.1.68 -R log-10x/pipeline-releases \
|
|
98
|
+
-p 'tenx-edge-1.1.68-amd64-native' -p 'tenx-modules-1.1.68.tar.gz' \
|
|
99
|
+
-p 'tenx-config-1.1.68.tar.gz' -p 'tenx-symbols-1.1.68.10x.tar' \
|
|
100
|
+
-p 'build-receive-layer.sh'
|
|
101
|
+
|
|
102
|
+
mkdir modules config symbols
|
|
103
|
+
tar xzf tenx-modules-1.1.68.tar.gz -C modules
|
|
104
|
+
tar xzf tenx-config-1.1.68.tar.gz -C config
|
|
105
|
+
cp tenx-symbols-1.1.68.10x.tar symbols/
|
|
106
|
+
|
|
107
|
+
chmod +x build-receive-layer.sh
|
|
108
|
+
./build-receive-layer.sh \
|
|
109
|
+
./tenx-edge-1.1.68-amd64-native ./modules ./config ./symbols \
|
|
110
|
+
./tenx-receive.zip
|
|
111
|
+
|
|
112
|
+
# Bake your license into the layer at /opt/tenx/license.jwt
|
|
113
|
+
mkdir -p tenx && cp license.jwt tenx/
|
|
114
|
+
zip -ur tenx-receive.zip tenx/license.jwt
|
|
115
|
+
|
|
116
|
+
# The zip is ~90 MB; direct upload caps at ~70 MB, so stage through S3
|
|
117
|
+
aws s3 cp tenx-receive.zip s3://<your-bucket>/layers/tenx-receive.zip
|
|
118
|
+
aws lambda publish-layer-version \
|
|
119
|
+
--layer-name tenx-receive \
|
|
120
|
+
--compatible-architectures x86_64 \
|
|
121
|
+
--content S3Bucket=<your-bucket>,S3Key=layers/tenx-receive.zip
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
??? tenx-config "Step 3: Attach the Layer and Environment"
|
|
125
|
+
|
|
126
|
+
Write the environment as a JSON file. `TENX_RECEIVE_APPS` contains commas, which the AWS CLI's `--environment Variables={...}` shorthand silently mis-parses; `file://` is the reliable form.
|
|
127
|
+
|
|
128
|
+
``` { .json title="env.json" }
|
|
129
|
+
{
|
|
130
|
+
"Variables": {
|
|
131
|
+
"TENX_MODULES": "/opt/tenx/modules",
|
|
132
|
+
"TENX_CONFIG": "/opt/tenx/config",
|
|
133
|
+
"TENX_SYMBOLS_PATH": "/opt/tenx/symbols",
|
|
134
|
+
"TENX_LICENSE_FILE": "/opt/tenx/license.jwt",
|
|
135
|
+
"TENX_AIRGAPPED": "true",
|
|
136
|
+
"TENX_LOG_PATH": "/tmp/tenx/",
|
|
137
|
+
"outputOffload": "true",
|
|
138
|
+
"symbolMessageHashField": "tenx_hash",
|
|
139
|
+
"log10xMetricsEnabled": "false"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
``` { .console .copy }
|
|
145
|
+
aws lambda update-function-configuration --function-name <fn> \
|
|
146
|
+
--layers <tenx-receive-layer-arn> <otel-collector-layer-arn> \
|
|
147
|
+
--environment file://env.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`TENX_LOG_PATH` matters: Lambda's filesystem is read-only outside `/tmp`, and a log appender that cannot create its directory poisons the pipeline launch.
|
|
151
|
+
|
|
152
|
+
??? tenx-forwarderinputs "Step 4: Splice the Collector Config"
|
|
153
|
+
|
|
154
|
+
Merge the loopback pairing into the collector config the functions already run. Existing receivers, processors, and the destination exporter stay untouched:
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
receivers:
|
|
158
|
+
# Return path from the engine extension (loopback, same sandbox)
|
|
159
|
+
otlp/tenx:
|
|
160
|
+
protocols:
|
|
161
|
+
grpc:
|
|
162
|
+
endpoint: 127.0.0.1:24225
|
|
163
|
+
|
|
164
|
+
exporters:
|
|
165
|
+
# Hand-off to the engine extension
|
|
166
|
+
otlp/tenx:
|
|
167
|
+
endpoint: 127.0.0.1:4317
|
|
168
|
+
tls:
|
|
169
|
+
insecure: true
|
|
170
|
+
# The collector's first dial happens before the engine listens, and
|
|
171
|
+
# default exponential retry intervals stretch across freeze until
|
|
172
|
+
# exports fail forever. Bounded intervals keep retries inside a
|
|
173
|
+
# thaw window.
|
|
174
|
+
retry_on_failure:
|
|
175
|
+
enabled: true
|
|
176
|
+
initial_interval: 200ms
|
|
177
|
+
max_interval: 1s
|
|
178
|
+
max_elapsed_time: 0s
|
|
179
|
+
|
|
180
|
+
connectors:
|
|
181
|
+
routing/tenx:
|
|
182
|
+
default_pipelines: [logs/tenx-siem]
|
|
183
|
+
table:
|
|
184
|
+
# context: log is required -- routeState is a LOG attribute; the
|
|
185
|
+
# resource context never matches it.
|
|
186
|
+
- context: log
|
|
187
|
+
condition: attributes["routeState"] == "offload"
|
|
188
|
+
pipelines: [logs/tenx-offload]
|
|
189
|
+
- context: log
|
|
190
|
+
condition: attributes["routeState"] == "drop"
|
|
191
|
+
pipelines: [logs/tenx-drop]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The full config, including the offload pipeline, the `decouple` processor placement, and the destination-side storage-tier policy, is emitted per estate by [Advise](https://doc.log10x.com/apps/mcp/tools/install/advise-install/).
|
|
195
|
+
|
|
196
|
+
??? tenx-mainconfig "Step 5: Per-Pattern Dispositions (Optional)"
|
|
197
|
+
|
|
198
|
+
Without a mute file every lever is estate-wide. With one, each pattern gets its own disposition. Entries are `<pattern>,<rate>:<untilEpochSec>:<reason>`; rate `0` is a full mute, `0.25` keeps 25%, and past the epoch the entry expires on its own. The first line is a header row the engine's lookup consumes as column names:
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
pattern,disposition
|
|
202
|
+
heartbeat_check_ok,0:1786400000:liveness spam OPS-4821
|
|
203
|
+
jwt_validated,0.25:1786400000:auth flood after deploy
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Upload it to your bucket and add three variables to `env.json`:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
TENX_RECEIVE_APPS=@run/input/forwarder/otel-collector,@apps/receiver,@run/receive/rate
|
|
210
|
+
rateReceiverFieldNames=message_pattern
|
|
211
|
+
rateReceiverLookupFile=/tmp/tenx/mutes.csv
|
|
212
|
+
TENX_RECEIVE_MUTE_S3_URI=s3://<your-bucket>/<prefix>/pipelines/run/receive/rate/mutes.csv
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The extension fetches the file at INIT and refreshes on invoke (`TENX_RECEIVE_MUTE_REFRESH_MS`, default 5 minutes), so changing a disposition is one `aws s3 cp` with no redeploy. The function role needs `s3:GetObject` on that key. Alternatively, bake the file into the layer with `build-receive-layer.sh`'s sixth argument; the policy is then static and a change means republishing the layer.
|
|
216
|
+
|
|
217
|
+
For a recurring loop that recomputes dispositions from cost data on a schedule, [Setup recurring](https://doc.log10x.com/apps/mcp/tools/install/setup-recurring/) with `scheduler: "eventbridge"` emits an EventBridge Scheduler + CodeBuild stack that writes this same S3 key.
|
|
218
|
+
|
|
219
|
+
??? tenx-monitoring "Step 6: Verify"
|
|
220
|
+
|
|
221
|
+
The extension logs its lifecycle to the function's log group:
|
|
222
|
+
|
|
223
|
+
``` { .console .copy }
|
|
224
|
+
aws logs filter-log-events --log-group-name /aws/lambda/<fn> \
|
|
225
|
+
--filter-pattern "tenx-receive" --max-items 10
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
At the destination, processed records carry `tenx_hash` and `routeState` as log attributes; a muted pattern shows `routeState` of `drop` on all but its retention floor. If dispositions have no effect, check that the mute file's first line is the header row and that `rateReceiverFieldNames` is `message_pattern`.
|
|
@@ -54,4 +54,12 @@ The 10x Engine uses an extensible launcher framework to run [apps](https://doc.l
|
|
|
54
54
|
|
|
55
55
|
[:octicons-arrow-right-24: Learn more](https://doc.log10x.com/engine/launcher/lambda)
|
|
56
56
|
|
|
57
|
+
- :material-puzzle-outline:{ .lg .middle } __Extension__
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
Run the 10x Engine as a Lambda extension paired with the function's OTel collector.
|
|
62
|
+
|
|
63
|
+
[:octicons-arrow-right-24: Learn more](https://doc.log10x.com/engine/launcher/extension)
|
|
64
|
+
|
|
57
65
|
</div>
|
|
@@ -239,6 +239,7 @@
|
|
|
239
239
|
* [Trigger](engine/launcher/trigger.md)
|
|
240
240
|
* [Sidecar](engine/launcher/sidecar.md)
|
|
241
241
|
* [Lambda](engine/launcher/lambda.md)
|
|
242
|
+
* [Extension](engine/launcher/extension.md)
|
|
242
243
|
* [Flavors](engine/flavors.md)
|
|
243
244
|
* [Pipelines](engine/pipeline.md)
|
|
244
245
|
* [Modules](engine/module.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "log10x-mcp",
|
|
3
|
-
"version": "1.29.
|
|
3
|
+
"version": "1.29.12",
|
|
4
4
|
"description": "Log10x MCP Server \u2014 per-pattern log cost attribution, root-cause investigation, pasted-batch triage, archive query/backfill, and cross-pillar correlation against customer metric backends (Grafana Cloud, Mimir, Thanos, AMP) with structural validation that refuses when it cannot prove linkage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|