logstrip 1.0.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.
- package/LICENSE +21 -0
- package/README.md +341 -0
- package/action.yml +19 -0
- package/dist/action/index.d.ts +5 -0
- package/dist/action/index.js +26980 -0
- package/dist/cli/index.d.ts +31 -0
- package/dist/cli/index.js +224 -0
- package/dist/core/logstrip-config.d.ts +19 -0
- package/dist/core/logstrip-config.js +268 -0
- package/dist/core/logstrip-parser.d.ts +58 -0
- package/dist/core/logstrip-parser.js +1302 -0
- package/package.json +86 -0
|
@@ -0,0 +1,1302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.KNOWN_LOG_SOURCES = exports.LOG_SOURCE_SIGNATURES = exports.MAX_REPEAT_DELTA_VALUES = exports.TFIDF_MAP_LIMIT = exports.TFIDF_PENALTY = exports.TFIDF_REPEAT_THRESHOLD = exports.SCORE_KEEP_THRESHOLD = exports.CONTEXT_WINDOW_AFTER = exports.CONTEXT_WINDOW_BEFORE = exports.INTERNAL_STACK_MARKER = void 0;
|
|
7
|
+
exports.detectLogSources = detectLogSources;
|
|
8
|
+
exports.parseAggressiveness = parseAggressiveness;
|
|
9
|
+
exports.sanitizeLine = sanitizeLine;
|
|
10
|
+
exports.createRepeatSignature = createRepeatSignature;
|
|
11
|
+
exports.shouldKeepLine = shouldKeepLine;
|
|
12
|
+
exports.looksLikeDiagnosticLine = looksLikeDiagnosticLine;
|
|
13
|
+
exports.isInternalStackTraceLine = isInternalStackTraceLine;
|
|
14
|
+
exports.estimateTokens = estimateTokens;
|
|
15
|
+
exports.scoreLineRelevance = scoreLineRelevance;
|
|
16
|
+
exports.buildMergedConfig = buildMergedConfig;
|
|
17
|
+
exports.processLogStream = processLogStream;
|
|
18
|
+
exports.processLogFile = processLogFile;
|
|
19
|
+
exports.pathsReferToSameFile = pathsReferToSameFile;
|
|
20
|
+
const node_events_1 = require("node:events");
|
|
21
|
+
const node_fs_1 = require("node:fs");
|
|
22
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
23
|
+
const node_readline_1 = require("node:readline");
|
|
24
|
+
const promises_1 = require("node:stream/promises");
|
|
25
|
+
const logstrip_config_js_1 = require("./logstrip-config.js");
|
|
26
|
+
exports.INTERNAL_STACK_MARKER = '[... hidden internal library frames ...]';
|
|
27
|
+
const AGGRESSIVENESS_LEVELS = [
|
|
28
|
+
'low',
|
|
29
|
+
'medium',
|
|
30
|
+
'high',
|
|
31
|
+
'aggressive',
|
|
32
|
+
];
|
|
33
|
+
const IGNORED_LOG_TAG_PATTERN = /\[(?:INFO|DEBUG|TRACE|VERBOSE)\]|"level"\s*:\s*"(?:info|debug|trace|verbose)"/i;
|
|
34
|
+
const IMPORTANT_LOG_TAG_PATTERN = /\[(?:ERROR|WARN|FATAL|CRITICAL|FAIL)\]/i;
|
|
35
|
+
const EXPLICIT_LOG_TAG_PATTERN = /\[[A-Z]+\]/i;
|
|
36
|
+
const STACK_FRAME_PATTERN = /^\s*at\s+.*(?:\(|\s).+:\d+:\d+\)?$/;
|
|
37
|
+
const JAVA_STACK_FRAME_PATTERN = /^\s*at\s+[\w$_.<>/]+\([^)]+:\d+\)$/;
|
|
38
|
+
const PYTHON_STACK_FRAME_PATTERN = /^\s*File\s+"[^"]+",\s+line\s+\d+,\s+in\s+.+$/;
|
|
39
|
+
const GO_STACK_FRAME_PATTERN = /^\s*(?:(?:[\w.-]+\/)+[\w./-]+|[\w.-]+\.\(\*?[\w.]+\)\.[\w.]+|[\w.-]+\.[A-Z]\w*)\(.*\)$/;
|
|
40
|
+
const GO_FILE_FRAME_PATTERN = /^\s*(?:\/[^\s]+|[A-Za-z]:[\\/][^\s]+):\d+(?:\s+\+\S+)?$/;
|
|
41
|
+
const GO_GOROUTINE_PATTERN = /^\s*goroutine\s+\d+\s+\[.+\]:$/i;
|
|
42
|
+
const PYTHON_TRACEBACK_PATTERN = /^Traceback \(most recent call last\):$/;
|
|
43
|
+
const STACK_MORE_PATTERN = /^\s*\.\.\. \d+ more$/;
|
|
44
|
+
const GITHUB_ACTIONS_ANNOTATION_PATTERN = /^::(?:error|warning|notice)\b/u;
|
|
45
|
+
const GRADLE_FAILURE_PATTERN = /\b(?:Execution failed|What went wrong|BUILD FAILED|Task failed with an exception)\b/i;
|
|
46
|
+
const MAKE_ERROR_PATTERN = /^make[:\s*]+/u;
|
|
47
|
+
const GO_TEST_FAIL_PATTERN = /---\s*FAIL:/u;
|
|
48
|
+
const SYSTEMD_STATUS_PATTERN = /\b(?:Failed to start|Failed to load|Failed to listen|Failed to mount|Failed to open|Failed to connect|status=\d+\s+\w+)\b/i;
|
|
49
|
+
const CIRCLECI_STEP_PATTERN = /\b(?:Spin Cancelled|Step failed|job was not approved)\b/i;
|
|
50
|
+
const JENKINS_MARKER_PATTERN = /\[(?:Pipeline|Checks|FCMaker)\]/u;
|
|
51
|
+
const AZURE_PIPELINE_PATTERN = /^##vso\[task\.(?:LogIssue|Complete)\b/u;
|
|
52
|
+
const TEAMCITY_MARKER_PATTERN = /^##teamcity\[(?:buildProblem|compilationFinished|message)\b/u;
|
|
53
|
+
const DIAGNOSTIC_PATTERN = /\b(?:Error|Exception|AssertionError|TypeError|ReferenceError|SyntaxError|RangeError|NullPointerException|Unhandled|failed|failure|fatal|panic|refused|timeout|timed\s+out|unreachable|unavailable|disconnected|killed|aborted|crashed|terminated|unauthorized)\b/i;
|
|
54
|
+
const JSON_SEVERITY_PATTERN = /"(?:level|severity)"\s*:\s*"(?:fatal|error|critical|warn|warning)"/i;
|
|
55
|
+
const NPM_ERROR_PATTERN = /\b(?:npm|pnpm)\s+ERR!/i;
|
|
56
|
+
const YARN_ERROR_PATTERN = /\byarn\s+error\b/i;
|
|
57
|
+
const SCANNER_FINDING_PATTERN = /\b(?:CVE-\d{4}-\d{4,7}|GHSA-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}|vulnerabilit(?:y|ies)|severity:\s*(?:critical|high|medium)|(?:critical|high)\s+severity)\b/i;
|
|
58
|
+
const CONTAINER_FAILURE_PATTERN = /\b(?:CrashLoopBackOff|ImagePullBackOff|ErrImagePull|OOMKilled|Back[- ]off restarting failed container|failed to pull image|(?:containerd|runc).*?(?:failed|error|panic|timeout|refused)|(?:failed|error|panic|timeout|refused).*?(?:containerd|runc)|rpc error: code = Unknown desc = failed to resolve reference)\b/i;
|
|
59
|
+
const INTERNAL_STACK_PATTERN = /(?:node_modules[\\/]|node:internal|internal[\\/]modules|bootstrap_node|[\\/]usr[\\/]lib[\\/]|[\\/]usr[\\/]local[\\/]lib[\\/]|[\\/]usr[\\/]local[\\/]go[\\/]src[\\/]runtime[\\/]|site-packages[\\/]|dist-packages[\\/]|\.venv[\\/]|java\.base[\\/]|jdk\.internal|org\.springframework\.|[\\/]pkg[\\/]mod[\\/]|\.cargo[\\/]registry[\\/])/i;
|
|
60
|
+
const UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
|
|
61
|
+
const ISO_TIME_PATTERN = /\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:?\d{2})?)?\b/g;
|
|
62
|
+
const UTC_TIME_PATTERN = /\b(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s+\d{1,2}\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{4}\s+\d{2}:\d{2}:\d{2}\s+(?:GMT|UTC)\b/gi;
|
|
63
|
+
const COMMON_LOG_TIME_PATTERN = /\b\d{1,2}\/(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\/\d{4}:\d{2}:\d{2}:\d{2}\s+[+-]\d{4}\b/gi;
|
|
64
|
+
const NGINX_ERROR_TIME_PATTERN = /\b\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2}\b/g;
|
|
65
|
+
const ANSI_ESCAPE_PATTERN = /\u001b\[[0-9;]*m/gu;
|
|
66
|
+
const IPV4_WITH_PORT_PATTERN = /\b(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}:(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]?\d{1,4})\b/g;
|
|
67
|
+
const IPV4_PATTERN = /\b(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}\b/g;
|
|
68
|
+
const HEX_HASH_PATTERN = /\b(?=[a-f0-9]*\d)(?=[a-f0-9]*[a-f])[a-f0-9]{16,}\b/gi;
|
|
69
|
+
const ALPHANUMERIC_HASH_PATTERN = /\b(?=[A-Za-z0-9]*\d)(?=[A-Za-z0-9]*[A-Za-z])[A-Za-z0-9]{24,}\b/g;
|
|
70
|
+
const AWS_ACCESS_KEY_PATTERN = /\b(?:AKIA|ABIA|ASIA)[0-9A-Z]{16}\b/g;
|
|
71
|
+
const AWS_ARN_ACCOUNT_PATTERN = /arn:aws:[a-z]+:[a-z0-9-]+:(\d{12})/g;
|
|
72
|
+
// In sanitizeLine, replace AWS ARN account IDs
|
|
73
|
+
// Applied inline below via replace callback
|
|
74
|
+
const LOW_EXTRA_TAG_PATTERN = /\[(?:NOTICE|STATUS)\]/i;
|
|
75
|
+
const AGGRESSIVE_WARN_PATTERN = /\[(?:WARN|WARNING)\]/i;
|
|
76
|
+
const AGGRESSIVE_WARNING_SIGNAL_PATTERN = DIAGNOSTIC_PATTERN;
|
|
77
|
+
// Hybrid detection: context window + TF-IDF dampening constants
|
|
78
|
+
exports.CONTEXT_WINDOW_BEFORE = 3;
|
|
79
|
+
exports.CONTEXT_WINDOW_AFTER = 2;
|
|
80
|
+
exports.SCORE_KEEP_THRESHOLD = 40;
|
|
81
|
+
exports.TFIDF_REPEAT_THRESHOLD = 3;
|
|
82
|
+
exports.TFIDF_PENALTY = 8;
|
|
83
|
+
exports.TFIDF_MAP_LIMIT = 50_000;
|
|
84
|
+
exports.MAX_REPEAT_DELTA_VALUES = 3;
|
|
85
|
+
exports.LOG_SOURCE_SIGNATURES = [
|
|
86
|
+
['vitest', ['vitest']],
|
|
87
|
+
['jest', ['jest']],
|
|
88
|
+
['mocha', ['mocha']],
|
|
89
|
+
['ava', ['ava test']],
|
|
90
|
+
['tap', ['tap version', 'node-tap']],
|
|
91
|
+
['node-test-runner', ['node:test']],
|
|
92
|
+
['cypress', ['cypress']],
|
|
93
|
+
['playwright', ['playwright']],
|
|
94
|
+
['storybook', ['storybook']],
|
|
95
|
+
['karma', ['karma']],
|
|
96
|
+
['webpack', ['webpack']],
|
|
97
|
+
['vite', ['vite']],
|
|
98
|
+
['rollup', ['rollup']],
|
|
99
|
+
['esbuild', ['esbuild']],
|
|
100
|
+
['babel', ['babel']],
|
|
101
|
+
['swc', ['swc']],
|
|
102
|
+
['typescript', ['typescript', 'tsc', 'ts2322', 'ts18048']],
|
|
103
|
+
['eslint', ['eslint']],
|
|
104
|
+
['prettier', ['prettier']],
|
|
105
|
+
['rome', ['rome']],
|
|
106
|
+
['npm', ['npm err!', 'npm warn', 'npm run']],
|
|
107
|
+
['pnpm', ['pnpm err!', 'pnpm']],
|
|
108
|
+
['yarn', ['yarn error', 'yarn run']],
|
|
109
|
+
['bun', ['bun install', 'bun run']],
|
|
110
|
+
['nx', ['nx ']],
|
|
111
|
+
['turborepo', ['turbo run', 'turborepo']],
|
|
112
|
+
['lerna', ['lerna']],
|
|
113
|
+
['pytest', ['pytest', 'tests/', 'assertionerror: assert']],
|
|
114
|
+
['keploy', ['keploy']],
|
|
115
|
+
['testkube', ['testkube']],
|
|
116
|
+
['python-unittest', ['unittest', 'ran ', 'failed (failures=']],
|
|
117
|
+
['tox', ['tox -e', 'tox:']],
|
|
118
|
+
['nox', ['nox >']],
|
|
119
|
+
['pip', ['pip install', 'pip uninstall']],
|
|
120
|
+
['pipenv', ['pipenv']],
|
|
121
|
+
['poetry', ['poetry install', 'poetry lock']],
|
|
122
|
+
['uv', ['uv pip', 'astral uv']],
|
|
123
|
+
['django', ['django', 'manage.py']],
|
|
124
|
+
['flask', ['flask app']],
|
|
125
|
+
['fastapi', ['fastapi', 'uvicorn']],
|
|
126
|
+
['gunicorn', ['gunicorn']],
|
|
127
|
+
['uvicorn', ['uvicorn']],
|
|
128
|
+
['celery', ['celery']],
|
|
129
|
+
['airflow', ['airflow']],
|
|
130
|
+
['maven', ['maven', 'mvn ', 'mojofailureexception']],
|
|
131
|
+
['gradle', ['gradle', 'task :', 'build failed with an exception']],
|
|
132
|
+
['bazel', ['bazel', 'build did not complete successfully']],
|
|
133
|
+
['cmake', ['cmake error', 'cmakefiles']],
|
|
134
|
+
['ninja-build', ['ninja: build stopped']],
|
|
135
|
+
['sbt', ['sbt compile', 'sbt run', 'sbt test', 'sbt publish', 'sbt update', '[sbt]']],
|
|
136
|
+
['ant', ['apache ant', 'build.xml']],
|
|
137
|
+
['junit', ['junit']],
|
|
138
|
+
['spring-boot', ['spring', 'springboot']],
|
|
139
|
+
['logback', ['logback']],
|
|
140
|
+
['go-test', ['go test', '--- fail:']],
|
|
141
|
+
['go-build', ['go build', 'go: downloading']],
|
|
142
|
+
['golangci-lint', ['golangci-lint']],
|
|
143
|
+
['gin', ['gin-gonic']],
|
|
144
|
+
['cobra', ['spf13/cobra']],
|
|
145
|
+
['cargo', ['cargo build', 'cargo test']],
|
|
146
|
+
['rustc', ['rustc', 'error[e']],
|
|
147
|
+
['clippy', ['clippy']],
|
|
148
|
+
['actix', ['actix']],
|
|
149
|
+
['tokio', ['tokio']],
|
|
150
|
+
['dotnet', ['dotnet ', 'asp.net']],
|
|
151
|
+
['msbuild', ['msbuild', 'error msb']],
|
|
152
|
+
['nuget', ['nuget']],
|
|
153
|
+
['xunit', ['xunit']],
|
|
154
|
+
['nunit', ['nunit']],
|
|
155
|
+
['serilog', ['serilog']],
|
|
156
|
+
['phpunit', ['phpunit']],
|
|
157
|
+
['composer', ['composer']],
|
|
158
|
+
['laravel', ['laravel']],
|
|
159
|
+
['symfony', ['symfony']],
|
|
160
|
+
['bundler', ['bundle install', 'bundler']],
|
|
161
|
+
['rspec', ['rspec']],
|
|
162
|
+
['rails', ['rails']],
|
|
163
|
+
['sidekiq', ['sidekiq']],
|
|
164
|
+
['docker', ['docker', 'dockerfile']],
|
|
165
|
+
['buildkit', ['buildkit', '#0 [internal]']],
|
|
166
|
+
['docker-compose', ['docker-compose', 'compose']],
|
|
167
|
+
['podman', ['podman']],
|
|
168
|
+
['containerd', ['containerd']],
|
|
169
|
+
['runc', ['runc']],
|
|
170
|
+
['kubernetes', ['kubernetes', 'kubectl', 'k8s']],
|
|
171
|
+
['kubelet', ['kubelet']],
|
|
172
|
+
['helm', ['helm']],
|
|
173
|
+
['kustomize', ['kustomize']],
|
|
174
|
+
['skaffold', ['skaffold']],
|
|
175
|
+
['tilt', ['tilt up', 'tiltfile']],
|
|
176
|
+
['openshift', ['openshift', 'oc ']],
|
|
177
|
+
['concourse', ['concourse', 'fly -t']],
|
|
178
|
+
['werf', ['werf']],
|
|
179
|
+
['nomad', ['hashicorp nomad', 'nomad']],
|
|
180
|
+
['consul', ['hashicorp consul', 'consul']],
|
|
181
|
+
['istio', ['istio']],
|
|
182
|
+
['linkerd', ['linkerd']],
|
|
183
|
+
['cilium', ['cilium']],
|
|
184
|
+
['calico', ['calico']],
|
|
185
|
+
['keda', ['keda']],
|
|
186
|
+
['knative', ['knative']],
|
|
187
|
+
['openfaas', ['openfaas']],
|
|
188
|
+
['cert-manager', ['cert-manager', 'cert manager']],
|
|
189
|
+
['external-dns', ['external-dns', 'external dns']],
|
|
190
|
+
['sealed-secrets', ['sealed-secrets', 'sealed secrets']],
|
|
191
|
+
['kyverno', ['kyverno']],
|
|
192
|
+
['opa-gatekeeper', ['gatekeeper', 'opa gatekeeper']],
|
|
193
|
+
['argo-rollouts', ['argo rollouts', 'argo-rollouts']],
|
|
194
|
+
['flagger', ['flagger']],
|
|
195
|
+
['crossplane', ['crossplane']],
|
|
196
|
+
['telepresence', ['telepresence']],
|
|
197
|
+
['k9s', ['k9s']],
|
|
198
|
+
['stern', ['stern']],
|
|
199
|
+
['kubescape', ['kubescape']],
|
|
200
|
+
['tracetest', ['tracetest']],
|
|
201
|
+
['polaris', ['fairwinds polaris', 'polaris audit']],
|
|
202
|
+
['kube-bench', ['kube-bench']],
|
|
203
|
+
['kube-hunter', ['kube-hunter', 'kube hunter']],
|
|
204
|
+
['envoy', ['envoy']],
|
|
205
|
+
['github-actions', ['github actions', '##[error]', '::error::']],
|
|
206
|
+
['gitlab-ci', ['gitlab-ci', 'running with gitlab-runner']],
|
|
207
|
+
['jenkins', ['jenkins', '[pipeline]']],
|
|
208
|
+
['argocd', ['argocd', 'argo cd']],
|
|
209
|
+
['fluxcd', ['fluxcd', 'flux cd']],
|
|
210
|
+
['renovate', ['renovate bot', 'renovate']],
|
|
211
|
+
['circleci', ['circleci']],
|
|
212
|
+
['travis-ci', ['travis ci', 'travis build']],
|
|
213
|
+
['azure-pipelines', ['azure pipelines', '##vso']],
|
|
214
|
+
['teamcity', ['teamcity', '##teamcity']],
|
|
215
|
+
['buildkite', ['buildkite']],
|
|
216
|
+
['spinnaker', ['spinnaker']],
|
|
217
|
+
['harness', ['harness']],
|
|
218
|
+
['armory', ['armory']],
|
|
219
|
+
['bamboo', ['atlassian bamboo', 'bamboo build']],
|
|
220
|
+
['appveyor', ['appveyor']],
|
|
221
|
+
['codefresh', ['codefresh']],
|
|
222
|
+
['octopus-deploy', ['octopus deploy', 'octopus']],
|
|
223
|
+
['drone-ci', ['drone.io', 'drone ci']],
|
|
224
|
+
['tekton', ['tekton', 'taskrun', 'pipelinerun']],
|
|
225
|
+
['argo-workflows', ['argo workflows', 'workflow failed']],
|
|
226
|
+
['trivy', ['trivy', 'vulnerability', 'cve-']],
|
|
227
|
+
['snyk', ['snyk']],
|
|
228
|
+
['grype', ['grype']],
|
|
229
|
+
['semgrep', ['semgrep']],
|
|
230
|
+
['gitleaks', ['gitleaks']],
|
|
231
|
+
['dependabot', ['dependabot']],
|
|
232
|
+
['npm-audit', ['npm audit']],
|
|
233
|
+
['osv-scanner', ['osv-scanner']],
|
|
234
|
+
['checkov', ['checkov']],
|
|
235
|
+
['bandit', ['bandit']],
|
|
236
|
+
['sonarqube', ['sonarqube', 'sonar']],
|
|
237
|
+
['nginx', ['nginx']],
|
|
238
|
+
['apache-httpd', ['apache', 'httpd']],
|
|
239
|
+
['caddy', ['caddy']],
|
|
240
|
+
['varnish', ['varnish']],
|
|
241
|
+
['traefik', ['traefik']],
|
|
242
|
+
['haproxy', ['haproxy']],
|
|
243
|
+
['postgresql', ['postgres', 'postgresql']],
|
|
244
|
+
['mysql', ['mysql']],
|
|
245
|
+
['mariadb', ['mariadb']],
|
|
246
|
+
['mongodb', ['mongodb', 'mongod']],
|
|
247
|
+
['redis', ['redis']],
|
|
248
|
+
['valkey', ['valkey']],
|
|
249
|
+
['keydb', ['keydb']],
|
|
250
|
+
['dragonflydb', ['dragonflydb', 'dragonfly']],
|
|
251
|
+
['memcached', ['memcached']],
|
|
252
|
+
['aerospike', ['aerospike']],
|
|
253
|
+
['dynamodb', ['dynamodb']],
|
|
254
|
+
['cockroachdb', ['cockroachdb']],
|
|
255
|
+
['scylladb', ['scylladb']],
|
|
256
|
+
['yugabytedb', ['yugabytedb', 'yugabyte']],
|
|
257
|
+
['tidb', ['tidb']],
|
|
258
|
+
['influxdb', ['influxdb']],
|
|
259
|
+
['timescaledb', ['timescaledb']],
|
|
260
|
+
['questdb', ['questdb']],
|
|
261
|
+
['eventstoredb', ['eventstoredb', 'event store db']],
|
|
262
|
+
['pgbouncer', ['pgbouncer']],
|
|
263
|
+
['proxysql', ['proxysql']],
|
|
264
|
+
['vitess', ['vitess']],
|
|
265
|
+
['cassandra', ['cassandra']],
|
|
266
|
+
['clickhouse', ['clickhouse']],
|
|
267
|
+
['opensearch', ['opensearch']],
|
|
268
|
+
['elasticsearch', ['elasticsearch']],
|
|
269
|
+
['oracle-db', ['oracle', 'ora-']],
|
|
270
|
+
['sqlserver', ['sql server', 'mssql']],
|
|
271
|
+
['db2', ['db2']],
|
|
272
|
+
['neo4j', ['neo4j']],
|
|
273
|
+
['kafka', ['kafka']],
|
|
274
|
+
['aws-kinesis', ['kinesis']],
|
|
275
|
+
['aws-msk', ['amazon msk', 'aws msk']],
|
|
276
|
+
['confluent', ['confluent']],
|
|
277
|
+
['schema-registry', ['schema registry']],
|
|
278
|
+
['rabbitmq', ['rabbitmq']],
|
|
279
|
+
['nats', ['nats']],
|
|
280
|
+
['apache-pulsar', ['pulsar']],
|
|
281
|
+
['activemq', ['activemq']],
|
|
282
|
+
['debezium-server', ['debezium server']],
|
|
283
|
+
['streamsets', ['streamsets']],
|
|
284
|
+
['bytewax', ['bytewax']],
|
|
285
|
+
['materialize', ['materialize']],
|
|
286
|
+
['risingwave', ['risingwave']],
|
|
287
|
+
['emqx', ['emqx']],
|
|
288
|
+
['mosquitto', ['mosquitto']],
|
|
289
|
+
['aws-sqs', ['aws sqs', 'amazon sqs']],
|
|
290
|
+
['aws-sns', ['aws sns', 'amazon sns']],
|
|
291
|
+
['gcp-pubsub', ['pub/sub', 'google pubsub', 'gcp pubsub']],
|
|
292
|
+
['redpanda', ['redpanda']],
|
|
293
|
+
['zeromq', ['zeromq', '0mq']],
|
|
294
|
+
['ibm-mq', ['ibm mq', 'websphere mq']],
|
|
295
|
+
['cloudformation', ['cloudformation']],
|
|
296
|
+
['cloud-custodian', ['cloud custodian', 'custodian run']],
|
|
297
|
+
['infracost', ['infracost']],
|
|
298
|
+
['terraform-cloud', ['terraform cloud']],
|
|
299
|
+
['terraform-enterprise', ['terraform enterprise']],
|
|
300
|
+
['terraform', ['terraform']],
|
|
301
|
+
['terragrunt', ['terragrunt']],
|
|
302
|
+
['opentofu', ['opentofu']],
|
|
303
|
+
['atlantis', ['atlantis']],
|
|
304
|
+
['spacelift', ['spacelift']],
|
|
305
|
+
['ansible', ['ansible']],
|
|
306
|
+
['pulumi', ['pulumi']],
|
|
307
|
+
['packer', ['packer']],
|
|
308
|
+
['chef', ['chef']],
|
|
309
|
+
['puppet', ['puppet']],
|
|
310
|
+
['saltstack', ['saltstack']],
|
|
311
|
+
['vault', ['vault']],
|
|
312
|
+
['aws-lambda', ['aws lambda', 'lambda']],
|
|
313
|
+
['cloudwatch', ['cloudwatch']],
|
|
314
|
+
['gcp-cloud-run', ['cloud run']],
|
|
315
|
+
['azure-functions', ['azure functions']],
|
|
316
|
+
['gcp-cloud-functions', ['cloud functions']],
|
|
317
|
+
['aws-ecs', ['aws ecs', 'amazon ecs']],
|
|
318
|
+
['aws-eks', ['aws eks', 'amazon eks']],
|
|
319
|
+
['aws-fargate', ['fargate']],
|
|
320
|
+
['aws-cloudfront', ['cloudfront']],
|
|
321
|
+
['aws-alb', ['application load balancer', 'aws alb']],
|
|
322
|
+
['aws-api-gateway', ['api gateway', 'execute-api']],
|
|
323
|
+
['azure-aks', ['azure aks', 'aks cluster']],
|
|
324
|
+
['azure-app-service', ['azure app service', 'app service']],
|
|
325
|
+
['gcp-gke', ['google kubernetes engine', 'gke']],
|
|
326
|
+
['azure-monitor', ['azure monitor']],
|
|
327
|
+
['cloudflare', ['cloudflare']],
|
|
328
|
+
['fastly', ['fastly']],
|
|
329
|
+
['vercel', ['vercel']],
|
|
330
|
+
['netlify', ['netlify']],
|
|
331
|
+
['heroku', ['heroku']],
|
|
332
|
+
['railway', ['railway']],
|
|
333
|
+
['fly-io', ['fly.io', 'flyctl']],
|
|
334
|
+
['prometheus', ['prometheus']],
|
|
335
|
+
['grafana', ['grafana']],
|
|
336
|
+
['loki', ['loki']],
|
|
337
|
+
['logstash', ['logstash']],
|
|
338
|
+
['fluentd', ['fluentd']],
|
|
339
|
+
['fluent-bit', ['fluent bit', 'fluent-bit']],
|
|
340
|
+
['graylog', ['graylog']],
|
|
341
|
+
['splunk', ['splunk']],
|
|
342
|
+
['kibana', ['kibana']],
|
|
343
|
+
['zabbix', ['zabbix']],
|
|
344
|
+
['nagios', ['nagios']],
|
|
345
|
+
['jaeger', ['jaeger']],
|
|
346
|
+
['zipkin', ['zipkin']],
|
|
347
|
+
['honeycomb', ['honeycomb']],
|
|
348
|
+
['elastic-apm', ['elastic apm']],
|
|
349
|
+
['datadog', ['datadog']],
|
|
350
|
+
['newrelic', ['new relic']],
|
|
351
|
+
['sentry', ['sentry']],
|
|
352
|
+
['sumologic', ['sumologic']],
|
|
353
|
+
['logz-io', ['logz.io', 'logz io']],
|
|
354
|
+
['mezmo', ['mezmo', 'logdna']],
|
|
355
|
+
['parca', ['parca']],
|
|
356
|
+
['pixie', ['pixie']],
|
|
357
|
+
['falco', ['falco']],
|
|
358
|
+
['aquasec', ['aquasec', 'aqua security']],
|
|
359
|
+
['wiz', ['wiz']],
|
|
360
|
+
['tenable', ['tenable']],
|
|
361
|
+
['prisma-cloud', ['prisma cloud']],
|
|
362
|
+
['qualys', ['qualys']],
|
|
363
|
+
['crowdstrike', ['crowdstrike']],
|
|
364
|
+
['aws-guardduty', ['guardduty']],
|
|
365
|
+
['aws-security-hub', ['security hub']],
|
|
366
|
+
['aws-cloudtrail', ['cloudtrail']],
|
|
367
|
+
['vanta', ['vanta']],
|
|
368
|
+
['drata', ['drata']],
|
|
369
|
+
['panther', ['panther']],
|
|
370
|
+
['falcon-logscale', ['falcon logscale', 'humio']],
|
|
371
|
+
['owasp-zap', ['owasp zap', 'zap baseline']],
|
|
372
|
+
['sonatype-nexus', ['sonatype nexus', 'nexus repository']],
|
|
373
|
+
['jfrog-artifactory', ['artifactory', 'jfrog']],
|
|
374
|
+
['harbor', ['harbor']],
|
|
375
|
+
['syslog', ['syslog']],
|
|
376
|
+
['journald', ['journald', 'systemd']],
|
|
377
|
+
['hadoop', ['hadoop']],
|
|
378
|
+
['spark', ['apache spark', 'spark executor']],
|
|
379
|
+
['flink', ['apache flink', 'flink job']],
|
|
380
|
+
['kubeflow', ['kubeflow']],
|
|
381
|
+
['ray', ['ray cluster']],
|
|
382
|
+
['mlflow', ['mlflow']],
|
|
383
|
+
['langfuse', ['langfuse']],
|
|
384
|
+
['langsmith', ['langsmith']],
|
|
385
|
+
['arize-phoenix', ['arize phoenix', 'phoenix tracing']],
|
|
386
|
+
['weights-and-biases', ['weights & biases', 'wandb']],
|
|
387
|
+
['neptune-ai', ['neptune.ai', 'neptune run']],
|
|
388
|
+
['mlrun', ['mlrun']],
|
|
389
|
+
['seldon-core', ['seldon core', 'seldon']],
|
|
390
|
+
['kserve', ['kserve']],
|
|
391
|
+
['bentoml', ['bentoml']],
|
|
392
|
+
['triton-inference-server', ['triton inference server', 'nvidia triton']],
|
|
393
|
+
['feast', ['feast feature store', 'feast apply']],
|
|
394
|
+
['llamaindex', ['llamaindex']],
|
|
395
|
+
['haystack', ['deepset haystack', 'haystack pipeline']],
|
|
396
|
+
['milvus', ['milvus']],
|
|
397
|
+
['qdrant', ['qdrant']],
|
|
398
|
+
['weaviate', ['weaviate']],
|
|
399
|
+
['pinecone', ['pinecone']],
|
|
400
|
+
['chromadb', ['chromadb', 'chroma db']],
|
|
401
|
+
['vespa', ['vespa']],
|
|
402
|
+
['singlestore', ['singlestore', 'memsql']],
|
|
403
|
+
['dbt', ['dbt run', 'dbt test']],
|
|
404
|
+
['dagster', ['dagster']],
|
|
405
|
+
['airbyte', ['airbyte']],
|
|
406
|
+
['fivetran', ['fivetran']],
|
|
407
|
+
['stitch-data', ['stitch data']],
|
|
408
|
+
['kafka-connect', ['kafka connect']],
|
|
409
|
+
['debezium', ['debezium']],
|
|
410
|
+
['trino', ['trino']],
|
|
411
|
+
['presto', ['presto']],
|
|
412
|
+
['apache-druid', ['apache druid', 'druid coordinator']],
|
|
413
|
+
['apache-pinot', ['apache pinot', 'pinot controller']],
|
|
414
|
+
['snowflake', ['snowflake']],
|
|
415
|
+
['bigquery', ['bigquery']],
|
|
416
|
+
['redshift', ['redshift']],
|
|
417
|
+
['azure-synapse', ['azure synapse', 'synapse sql']],
|
|
418
|
+
['databricks', ['databricks']],
|
|
419
|
+
['tableau', ['tableau']],
|
|
420
|
+
['powerbi', ['power bi', 'powerbi']],
|
|
421
|
+
['metabase', ['metabase']],
|
|
422
|
+
['superset', ['apache superset', 'superset']],
|
|
423
|
+
['looker', ['looker']],
|
|
424
|
+
['qlik', ['qlik']],
|
|
425
|
+
['mode-analytics', ['mode analytics']],
|
|
426
|
+
['apache-beam', ['apache beam', 'beam pipeline']],
|
|
427
|
+
['apache-nifi', ['apache nifi', 'nifi flow']],
|
|
428
|
+
['meltano', ['meltano']],
|
|
429
|
+
['hevo-data', ['hevo data']],
|
|
430
|
+
['matillion', ['matillion']],
|
|
431
|
+
['talend', ['talend']],
|
|
432
|
+
['informatica', ['informatica']],
|
|
433
|
+
['dataform', ['dataform']],
|
|
434
|
+
['great-expectations', ['great expectations', 'gx checkpoint']],
|
|
435
|
+
['monte-carlo', ['monte carlo']],
|
|
436
|
+
['soda-core', ['soda core', 'soda scan']],
|
|
437
|
+
['apache-hudi', ['apache hudi', 'hudi deltastreamer']],
|
|
438
|
+
['delta-lake', ['delta lake']],
|
|
439
|
+
['apache-iceberg', ['apache iceberg', 'iceberg table']],
|
|
440
|
+
['starrocks', ['starrocks']],
|
|
441
|
+
['greenplum', ['greenplum']],
|
|
442
|
+
['teradata', ['teradata']],
|
|
443
|
+
['supabase', ['supabase']],
|
|
444
|
+
['firebase', ['firebase']],
|
|
445
|
+
['hasura', ['hasura']],
|
|
446
|
+
['gitpod', ['gitpod']],
|
|
447
|
+
['dynatrace', ['dynatrace']],
|
|
448
|
+
['appdynamics', ['appdynamics']],
|
|
449
|
+
['bugsnag', ['bugsnag']],
|
|
450
|
+
['rollbar', ['rollbar']],
|
|
451
|
+
['lacework', ['lacework']],
|
|
452
|
+
['openstack', ['openstack', 'nova', 'neutron']],
|
|
453
|
+
['oracle-cloud', ['oracle cloud infrastructure', 'oci tenancy']],
|
|
454
|
+
['alibaba-cloud', ['alibaba cloud', 'aliyun']],
|
|
455
|
+
['tencent-cloud', ['tencent cloud', 'tke cluster']],
|
|
456
|
+
['digitalocean', ['digitalocean', 'doctl']],
|
|
457
|
+
['linode', ['linode']],
|
|
458
|
+
['minio', ['minio']],
|
|
459
|
+
['ceph', ['ceph']],
|
|
460
|
+
['etcd', ['etcd']],
|
|
461
|
+
['zookeeper', ['zookeeper']],
|
|
462
|
+
['kong', ['kong gateway', 'kong route']],
|
|
463
|
+
['apisix', ['apache apisix', 'apisix route']],
|
|
464
|
+
['keycloak', ['keycloak']],
|
|
465
|
+
['okta', ['okta']],
|
|
466
|
+
['auth0', ['auth0']],
|
|
467
|
+
['launchdarkly', ['launchdarkly']],
|
|
468
|
+
['unleash', ['unleash']],
|
|
469
|
+
['splitio', ['split.io', 'splitio']],
|
|
470
|
+
['flagsmith', ['flagsmith']],
|
|
471
|
+
['pagerduty', ['pagerduty']],
|
|
472
|
+
['opsgenie', ['opsgenie']],
|
|
473
|
+
['victorops', ['victorops']],
|
|
474
|
+
['statuspage', ['statuspage']],
|
|
475
|
+
['incident-io', ['incident.io', 'incident io']],
|
|
476
|
+
['firehydrant', ['firehydrant']],
|
|
477
|
+
['rootly', ['rootly']],
|
|
478
|
+
['squadcast', ['squadcast']],
|
|
479
|
+
['grafana-oncall', ['grafana oncall']],
|
|
480
|
+
['cloudbees', ['cloudbees']],
|
|
481
|
+
['jenkins-x', ['jenkins x', 'jenkins-x']],
|
|
482
|
+
['backstage', ['backstage']],
|
|
483
|
+
['portainer', ['portainer']],
|
|
484
|
+
['rancher', ['rancher']],
|
|
485
|
+
['longhorn', ['longhorn']],
|
|
486
|
+
['rook-ceph', ['rook-ceph', 'rook ceph']],
|
|
487
|
+
['temporal', ['temporal']],
|
|
488
|
+
['prefect', ['prefect']],
|
|
489
|
+
['camunda', ['camunda']],
|
|
490
|
+
['zeebe', ['zeebe']],
|
|
491
|
+
['n8n', ['n8n']],
|
|
492
|
+
['mulesoft', ['mulesoft']],
|
|
493
|
+
['boomi', ['boomi']],
|
|
494
|
+
['apigee', ['apigee']],
|
|
495
|
+
['gravitee', ['gravitee']],
|
|
496
|
+
['kong-konnect', ['kong konnect', 'kong-konnect']],
|
|
497
|
+
['consul-connect', ['consul connect', 'consul-connect']],
|
|
498
|
+
['boundary', ['hashicorp boundary', 'boundary']],
|
|
499
|
+
['gremlin', ['gremlin']],
|
|
500
|
+
['litmuschaos', ['litmuschaos', 'litmus chaos']],
|
|
501
|
+
['chaos-mesh', ['chaos mesh', 'chaos-mesh']],
|
|
502
|
+
['steadybit', ['steadybit']],
|
|
503
|
+
['eventbridge', ['eventbridge']],
|
|
504
|
+
['aws-step-functions', ['step functions', 'states execution']],
|
|
505
|
+
['dapr', ['dapr']],
|
|
506
|
+
['eventarc', ['eventarc']],
|
|
507
|
+
['workato', ['workato']],
|
|
508
|
+
['tray-io', ['tray.io', 'tray io']],
|
|
509
|
+
['k6', ['k6 run', 'k6 cloud']],
|
|
510
|
+
['gatling', ['gatling']],
|
|
511
|
+
['locust', ['locust']],
|
|
512
|
+
['jmeter', ['jmeter']],
|
|
513
|
+
['artillery', ['artillery']],
|
|
514
|
+
['vegeta', ['vegeta']],
|
|
515
|
+
['fortio', ['fortio']],
|
|
516
|
+
['chaosblade', ['chaosblade']],
|
|
517
|
+
['salesforce', ['salesforce']],
|
|
518
|
+
['servicenow', ['servicenow', 'service now']],
|
|
519
|
+
['jira', ['jira']],
|
|
520
|
+
['confluence', ['confluence']],
|
|
521
|
+
['slack', ['slack']],
|
|
522
|
+
['workday', ['workday']],
|
|
523
|
+
['netsuite', ['netsuite']],
|
|
524
|
+
['sap', ['sap']],
|
|
525
|
+
['zendesk', ['zendesk']],
|
|
526
|
+
['freshdesk', ['freshdesk']],
|
|
527
|
+
['hubspot', ['hubspot']],
|
|
528
|
+
['stripe', ['stripe']],
|
|
529
|
+
['adyen', ['adyen']],
|
|
530
|
+
['braintree', ['braintree']],
|
|
531
|
+
['paypal', ['paypal']],
|
|
532
|
+
['square', ['square']],
|
|
533
|
+
['plaid', ['plaid']],
|
|
534
|
+
['twilio', ['twilio']],
|
|
535
|
+
['sendgrid', ['sendgrid']],
|
|
536
|
+
['mailgun', ['mailgun']],
|
|
537
|
+
['segment', ['segment']],
|
|
538
|
+
['rudderstack', ['rudderstack']],
|
|
539
|
+
['opentelemetry', ['opentelemetry', 'otel']],
|
|
540
|
+
// ── Web Frameworks (JS/TS) ──────────────────────────────────────
|
|
541
|
+
['express', ['express', 'expressjs', 'express server']],
|
|
542
|
+
['fastify', ['fastify', 'fastify server']],
|
|
543
|
+
['hapi', ['hapi', '@hapi/hapi']],
|
|
544
|
+
['koa', ['koa', 'koa server']],
|
|
545
|
+
['nestjs', ['nestjs', '@nestjs', 'nest.js']],
|
|
546
|
+
['nextjs', ['next.js', 'nextjs', 'next build', 'next start', 'next dev']],
|
|
547
|
+
['nuxt', ['nuxt', 'nuxt3', 'nuxt build', 'nuxt generate']],
|
|
548
|
+
['sveltekit', ['sveltekit', 'svelte kit', 'sveltekit adapter']],
|
|
549
|
+
['remix', ['remix', '@remix-run', 'remix build']],
|
|
550
|
+
['astro', ['astro', 'astro build', 'astro dev', 'astro check']],
|
|
551
|
+
['adonis', ['adonisjs', 'adonis', 'ace make:']],
|
|
552
|
+
['hono', ['hono', 'honojs', 'hono server']],
|
|
553
|
+
['deno-runtime', ['deno', 'deno task', 'deno run', 'deno compile']],
|
|
554
|
+
['elysia', ['elysia', 'elysiajs']],
|
|
555
|
+
['feathers', ['feathers', 'feathersjs', '@feathersjs']],
|
|
556
|
+
// ── Logging Libraries ────────────────────────────────────────────
|
|
557
|
+
['pino', ['pino', 'pino pretty', 'pino.info']],
|
|
558
|
+
['winston', ['winston', 'winston logger']],
|
|
559
|
+
['bunyan', ['bunyan', 'bunyan logger']],
|
|
560
|
+
['morgan', ['morgan', 'morgan logger']],
|
|
561
|
+
['log4js', ['log4js', 'log4js-node']],
|
|
562
|
+
['log4j', ['log4j', 'org.apache.log4j']],
|
|
563
|
+
['slf4j', ['slf4j', 'org.slf4j']],
|
|
564
|
+
['zap-logger', ['zap logger', 'go.uber.org/zap']],
|
|
565
|
+
['zerolog', ['zerolog', 'rs/zerolog']],
|
|
566
|
+
['structlog', ['structlog', 'python-structlog']],
|
|
567
|
+
['loguru', ['loguru', 'loguru.py']],
|
|
568
|
+
['spdlog', ['spdlog']],
|
|
569
|
+
// ── Mobile Frameworks ────────────────────────────────────────────
|
|
570
|
+
['react-native', ['react native', 'react-native', 'reactnative']],
|
|
571
|
+
['flutter', ['flutter', 'flutter test', 'flutter build']],
|
|
572
|
+
['expo', ['expo', 'expo-cli', 'expo start', 'eas build']],
|
|
573
|
+
['capacitor', ['capacitor', '@capacitor', 'capacitor run']],
|
|
574
|
+
['ionic', ['ionic', 'ionic framework', 'ionic cap']],
|
|
575
|
+
// ── Desktop Frameworks ────────────────────────────────────────────
|
|
576
|
+
['electron', ['electron', 'electron-builder', 'electron-forge']],
|
|
577
|
+
['tauri', ['tauri', 'tauri app', 'tauri build']],
|
|
578
|
+
['qt', ['qt framework', 'qwarning', 'qdebug', 'qcritical']],
|
|
579
|
+
// ── CMS Platforms ────────────────────────────────────────────────
|
|
580
|
+
['wordpress', ['wordpress', 'wp-content', 'wp-admin', 'wp-includes']],
|
|
581
|
+
['drupal', ['drupal', 'drupal.org']],
|
|
582
|
+
['strapi', ['strapi', 'strapi start']],
|
|
583
|
+
['ghost-cms', ['ghost cms', 'ghost blog', 'ghost-cli']],
|
|
584
|
+
['contentful', ['contentful']],
|
|
585
|
+
['sanity', ['sanity.io', 'sanity studio', 'sanity start']],
|
|
586
|
+
['payload', ['payload cms', 'payloadcms', 'payload start']],
|
|
587
|
+
['directus', ['directus', 'directus start']],
|
|
588
|
+
['webflow', ['webflow']],
|
|
589
|
+
// ── E-commerce ───────────────────────────────────────────────────
|
|
590
|
+
['shopify', ['shopify', 'shopify-cli']],
|
|
591
|
+
['magento', ['magento', 'magento2']],
|
|
592
|
+
['woocommerce', ['woocommerce']],
|
|
593
|
+
['bigcommerce', ['bigcommerce']],
|
|
594
|
+
['medusa', ['medusajs', 'medusa start', 'medusa new']],
|
|
595
|
+
// ── Search Engines ───────────────────────────────────────────────
|
|
596
|
+
['meilisearch', ['meilisearch', 'meili search', 'meilisearch index']],
|
|
597
|
+
['typesense', ['typesense', 'typesense server']],
|
|
598
|
+
['solr', ['solr', 'apache solr', 'solrconfig']],
|
|
599
|
+
['algolia', ['algolia', 'algolia index']],
|
|
600
|
+
// ── Java App Servers ─────────────────────────────────────────────
|
|
601
|
+
['tomcat', ['tomcat', 'apache tomcat', 'catalina.start']],
|
|
602
|
+
['jetty', ['jetty', 'eclipse jetty', 'jetty.server']],
|
|
603
|
+
['wildfly', ['wildfly', 'jboss', 'jboss-as']],
|
|
604
|
+
['glassfish', ['glassfish', 'glassfish server']],
|
|
605
|
+
['websphere', ['websphere', 'ibm websphere', 'was server']],
|
|
606
|
+
['weblogic', ['weblogic', 'oracle weblogic']],
|
|
607
|
+
// ── Java Frameworks ──────────────────────────────────────────────
|
|
608
|
+
['micronaut', ['micronaut', 'micronaut startup']],
|
|
609
|
+
['quarkus', ['quarkus', 'quarkus dev', 'quarkus build']],
|
|
610
|
+
['vertx', ['vert.x', 'vertx', 'io.vertx']],
|
|
611
|
+
['helidon', ['helidon', 'helidon se', 'helidon mp']],
|
|
612
|
+
['jakarta-ee', ['jakarta ee', 'jakarta.ee', 'javax.']],
|
|
613
|
+
// ── Python Lint/Format ──────────────────────────────────────────
|
|
614
|
+
['ruff', ['ruff', 'ruff check', 'ruff format']],
|
|
615
|
+
['mypy', ['mypy', 'mypy: error:', 'mypy: warning:']],
|
|
616
|
+
['pyright', ['pyright', 'pyright -']],
|
|
617
|
+
['pylint', ['pylint', 'pylint --']],
|
|
618
|
+
['isort', ['isort', 'isort --']],
|
|
619
|
+
// ── Python Async Frameworks ─────────────────────────────────────
|
|
620
|
+
['aiohttp', ['aiohttp', 'aiohttp.server']],
|
|
621
|
+
['sanic', ['sanic', 'sanic server']],
|
|
622
|
+
['tornado-framework', ['tornado', 'tornado.web']],
|
|
623
|
+
['twisted', ['twisted', 'twisted.internet']],
|
|
624
|
+
['scrapy', ['scrapy', 'scrapy crawl', 'scrapy.spider']],
|
|
625
|
+
// ── Go Frameworks ────────────────────────────────────────────────
|
|
626
|
+
['echo-framework', ['echo lab', 'labstack/echo', 'echo v4']],
|
|
627
|
+
['fiber', ['fiber', 'gofiber', 'fiber v2']],
|
|
628
|
+
['chi', ['chi router', 'go-chi', 'chi.middleware']],
|
|
629
|
+
['buffalo', ['buffalo', 'gobuffalo', 'buffalo dev']],
|
|
630
|
+
['revel', ['revel', 'revel framework', 'revel run']],
|
|
631
|
+
['go-kit', ['go-kit', 'go kit', 'go-kit/kit']],
|
|
632
|
+
['go-micro', ['go-micro', 'go micro', 'micro server']],
|
|
633
|
+
// ── Rust Frameworks ──────────────────────────────────────────────
|
|
634
|
+
['rocket', ['rocket.rs', 'rocket rust', 'rocket server']],
|
|
635
|
+
['warp-framework', ['warp filter', 'seanmonstar/warp', 'warp server']],
|
|
636
|
+
['axum', ['axum', 'tokio-rs/axum', 'axum router']],
|
|
637
|
+
['tide', ['tide', 'http-rs/tide', 'tide server']],
|
|
638
|
+
// ── Ruby Frameworks ──────────────────────────────────────────────
|
|
639
|
+
['sinatra', ['sinatra', 'sinatra app']],
|
|
640
|
+
['hanami', ['hanami', 'hanami server']],
|
|
641
|
+
['puma', ['puma webserver', 'puma worker', 'puma starting']],
|
|
642
|
+
['unicorn-rb', ['unicorn worker', 'unicorn master', 'unicorn_rails']],
|
|
643
|
+
['passenger', ['passenger', 'phusion passenger']],
|
|
644
|
+
// ── ORM / Database Tools ─────────────────────────────────────────
|
|
645
|
+
['prisma', ['prisma', 'prisma migrate', 'prisma generate', 'prisma db']],
|
|
646
|
+
['drizzle-orm', ['drizzle-orm', 'drizzle kit', 'drizzle push']],
|
|
647
|
+
['typeorm', ['typeorm', 'typeorm query', 'typeorm:']],
|
|
648
|
+
['sequelize', ['sequelize', 'sequelize-cli']],
|
|
649
|
+
['knex', ['knex', 'knexfile', 'knex migrate']],
|
|
650
|
+
['flyway', ['flyway', 'flyway migrate', 'flyway validate']],
|
|
651
|
+
['liquibase', ['liquibase', 'liquibase update']],
|
|
652
|
+
['alembic', ['alembic', 'alembic upgrade', 'alembic revision']],
|
|
653
|
+
['sqlalchemy', ['sqlalchemy', 'sqlalchemy.orm']],
|
|
654
|
+
['mongoose', ['mongoose', 'mongoose:', 'mongoose.connect']],
|
|
655
|
+
['mikro-orm', ['mikro-orm', 'mikroorm', 'mikro-orm migrate']],
|
|
656
|
+
['objection', ['objection.js', 'objectionjs']],
|
|
657
|
+
// ── Edge / Serverless Runtimes ────────────────────────────────────
|
|
658
|
+
['cloudflare-workers', ['cloudflare workers', 'wrangler', 'wrangler dev']],
|
|
659
|
+
['deno-deploy', ['deno deploy', 'deployctl']],
|
|
660
|
+
['serverless-framework', ['serverless framework', 'serverless deploy', 'serverless invoke']],
|
|
661
|
+
['openwhisk', ['openwhisk', 'wsk action']],
|
|
662
|
+
['nuclio', ['nuclio', 'nuclio function']],
|
|
663
|
+
// ── Real-time / WebSocket ────────────────────────────────────────
|
|
664
|
+
['socketio', ['socket.io', 'socketio', 'socket.io server']],
|
|
665
|
+
['pusher', ['pusher', 'pusher channel']],
|
|
666
|
+
['ably', ['ably', 'ably channel', 'ably realtime']],
|
|
667
|
+
['livekit', ['livekit', 'livekit-server']],
|
|
668
|
+
['centrifugo', ['centrifugo', 'centrifugal']],
|
|
669
|
+
// ── GraphQL ──────────────────────────────────────────────────────
|
|
670
|
+
['apollo-server', ['apollo server', 'apollo-server', 'apollographql']],
|
|
671
|
+
['graphql-yoga', ['graphql yoga', 'graphql-yoga']],
|
|
672
|
+
['mercurius', ['mercurius', 'mercurius upload']],
|
|
673
|
+
['dgraph', ['dgraph', 'dgraph query', 'dgraph ratel']],
|
|
674
|
+
// ── Observability (continued) ────────────────────────────────────
|
|
675
|
+
['instana', ['instana', 'instana sensor']],
|
|
676
|
+
['signalfx', ['signalfx', 'signal fx', 'signalfx ingest']],
|
|
677
|
+
['lightstep', ['lightstep', 'lightstep tracer']],
|
|
678
|
+
['thanos', ['thanos', 'thanos.io', 'thanos query']],
|
|
679
|
+
['cortex', ['cortexmetrics', 'cortex metrics', 'cortex ruler']],
|
|
680
|
+
['victoriametrics', ['victoriametrics', 'victoria metrics', 'vminsert']],
|
|
681
|
+
['grafana-tempo', ['grafana tempo', 'tempo query', 'tempo-distributor']],
|
|
682
|
+
// ── AI / ML ──────────────────────────────────────────────────────
|
|
683
|
+
['openai-api', ['openai', 'openai api', 'openai.error']],
|
|
684
|
+
['huggingface', ['huggingface', 'hugging face', 'huggingface.co']],
|
|
685
|
+
['ollama', ['ollama', 'ollama run', 'ollama serve']],
|
|
686
|
+
['vllm', ['vllm', 'vllm serve', 'vllm engine']],
|
|
687
|
+
['torchserve', ['torchserve', 'torch serve', 'ts torchserve']],
|
|
688
|
+
['comfyui', ['comfyui', 'comfyui manager']],
|
|
689
|
+
['stable-diffusion', ['stable diffusion', 'stablediffusion', 'sd-webui']],
|
|
690
|
+
['deepspeed', ['deepspeed', 'deepspeed runner']],
|
|
691
|
+
['llama-cpp', ['llama.cpp', 'llama cpp', 'llama-cpp-python']],
|
|
692
|
+
// ── Auth / Identity ──────────────────────────────────────────────
|
|
693
|
+
['clerk', ['clerk', 'clerk.dev']],
|
|
694
|
+
['firebase-auth', ['firebase auth', 'firebaseauthentication']],
|
|
695
|
+
['supabase-auth', ['supabase auth', 'gotrue']],
|
|
696
|
+
['authelia', ['authelia', 'authelia portal']],
|
|
697
|
+
['lldap', ['lldap']],
|
|
698
|
+
['dex-idp', ['dex idp', 'dexidp/dex']],
|
|
699
|
+
['zitadel', ['zitadel', 'zitadel auth']],
|
|
700
|
+
// ── Secrets / Config Management ──────────────────────────────────
|
|
701
|
+
['aws-secrets-manager', ['secrets manager', 'aws secretsmanager']],
|
|
702
|
+
['aws-kms', ['aws kms', 'kms.amazonaws']],
|
|
703
|
+
['doppler', ['doppler', 'doppler secrets', 'doppler run']],
|
|
704
|
+
['infisical', ['infisical', 'infisical scan']],
|
|
705
|
+
['aws-ssm', ['ssm parameter', 'aws ssm', 'amazon ssm']],
|
|
706
|
+
// ── Storage / CDN ────────────────────────────────────────────────
|
|
707
|
+
['aws-s3', ['s3 bucket', 'aws s3', 'amazon s3', 's3.amazonaws']],
|
|
708
|
+
['gcs', ['google cloud storage', 'gcs bucket', 'storage.googleapis']],
|
|
709
|
+
['azure-blob', ['azure blob', 'blob storage', 'blob.core.windows']],
|
|
710
|
+
['backblaze-b2', ['backblaze b2', 'b2 cloud', 'b2api']],
|
|
711
|
+
['wasabi', ['wasabi', 'wasabisys']],
|
|
712
|
+
['akamai', ['akamai', 'akamaihd.net', 'akamai edge']],
|
|
713
|
+
['imperva', ['imperva', 'imperva waf', 'incapsula']],
|
|
714
|
+
// ── Game Engines ─────────────────────────────────────────────────
|
|
715
|
+
['unity', ['unity', 'unityengine', 'unityplayer']],
|
|
716
|
+
['unreal-engine', ['unreal engine', 'unrealengine', 'ue5']],
|
|
717
|
+
['godot', ['godot engine', 'godot', 'godot project']],
|
|
718
|
+
['bevy', ['bevy engine', 'bevy', 'bevy_ecs']],
|
|
719
|
+
// ── IoT / Embedded ──────────────────────────────────────────────
|
|
720
|
+
['platformio', ['platformio', 'platformio.org', 'pio run']],
|
|
721
|
+
['arduino', ['arduino', 'arduino-cli']],
|
|
722
|
+
['esphome', ['esphome', 'esphome config']],
|
|
723
|
+
['home-assistant', ['home assistant', 'homeassistant', 'hassio']],
|
|
724
|
+
['tasmota', ['tasmota', 'tasmota mqtt']],
|
|
725
|
+
['openhab', ['openhab', 'openhabian']],
|
|
726
|
+
// ── Networking / VPN ─────────────────────────────────────────────
|
|
727
|
+
['wireguard', ['wireguard', 'wg0']],
|
|
728
|
+
['tailscale', ['tailscale', 'tailscale up']],
|
|
729
|
+
['ngrok', ['ngrok', 'ngrok http']],
|
|
730
|
+
['cloudflare-tunnel', ['cloudflare tunnel', 'cloudflared']],
|
|
731
|
+
['zerotier', ['zerotier', 'zerotier-one']],
|
|
732
|
+
// ── Analytics ────────────────────────────────────────────────────
|
|
733
|
+
['posthog', ['posthog', 'posthog capture']],
|
|
734
|
+
['amplitude', ['amplitude', 'amplitude identify']],
|
|
735
|
+
['mixpanel', ['mixpanel', 'mixpanel track']],
|
|
736
|
+
['heap-analytics', ['heap analytics', 'heap.io', 'heap track']],
|
|
737
|
+
['plausible', ['plausible', 'plausible analytics']],
|
|
738
|
+
['matomo', ['matomo', 'piwik']],
|
|
739
|
+
['countly', ['countly', 'countly server']],
|
|
740
|
+
// ── Email Services ───────────────────────────────────────────────
|
|
741
|
+
['aws-ses', ['amazon ses', 'aws ses', 'email.amazonaws']],
|
|
742
|
+
['mailchimp', ['mailchimp', 'mandrill']],
|
|
743
|
+
['brevo', ['brevo', 'sendinblue']],
|
|
744
|
+
['postmark', ['postmark', 'postmarkapp']],
|
|
745
|
+
['resend', ['resend', 'resend.com']],
|
|
746
|
+
['sparkpost', ['sparkpost', 'sparkpost mail']],
|
|
747
|
+
// ── Databases (more) ────────────────────────────────────────────
|
|
748
|
+
['surrealdb', ['surrealdb', 'surrealdb start']],
|
|
749
|
+
['planetscale', ['planetscale', 'pscale', 'planetscale database']],
|
|
750
|
+
['neon-db', ['neon database', 'neondatabase', 'neon.tech']],
|
|
751
|
+
['d1-database', ['cloudflare d1', 'd1 database', 'wrangler d1']],
|
|
752
|
+
['tigerbeetle', ['tigerbeetle', 'tigerbeetle start']],
|
|
753
|
+
['foundationdb', ['foundationdb', 'foundation db', 'fdbserver']],
|
|
754
|
+
['apache-geode', ['apache geode', 'geode', 'gfsh']],
|
|
755
|
+
['orientdb', ['orientdb', 'orientdb server']],
|
|
756
|
+
['arangodb', ['arangodb', 'arangoimp']],
|
|
757
|
+
// ── Mobile CI/CD ─────────────────────────────────────────────────
|
|
758
|
+
['bitrise', ['bitrise', 'bitrise.io']],
|
|
759
|
+
['codemagic', ['codemagic', 'codemagic-cli']],
|
|
760
|
+
['appcenter', ['app center', 'appcenter', 'appcenter.ms']],
|
|
761
|
+
['fastlane', ['fastlane', 'fastlane lane']],
|
|
762
|
+
// ── CI/CD (more) ─────────────────────────────────────────────────
|
|
763
|
+
['dagger', ['dagger', 'dagger.io', 'dagger do']],
|
|
764
|
+
['woodpecker-ci', ['woodpecker', 'woodpecker-ci', 'woodpecker pipeline']],
|
|
765
|
+
['agola', ['agola', 'agola run', 'agoladb']],
|
|
766
|
+
// ── Testing (more) ──────────────────────────────────────────────
|
|
767
|
+
['testcafe', ['testcafe', 'testcafe runner']],
|
|
768
|
+
['nightwatch', ['nightwatch', 'nightwatchjs', 'nightwatch test']],
|
|
769
|
+
['webdriverio', ['webdriverio', 'wdio', 'wdio runner']],
|
|
770
|
+
['selenium', ['selenium', 'selenium webdriver', 'selenium grid']],
|
|
771
|
+
['cucumber', ['cucumber', 'cucumber-js', 'cucumber test']],
|
|
772
|
+
['robot-framework', ['robot framework', 'robotframework', 'robot --test']],
|
|
773
|
+
['behave', ['behave', 'behave bdd']],
|
|
774
|
+
// ── Load Testing (more) ─────────────────────────────────────────
|
|
775
|
+
['hey', ['rakyll/hey', 'hey -z']],
|
|
776
|
+
['wrk', ['wg/wrk', 'wrk -t']],
|
|
777
|
+
// ── Documentation ────────────────────────────────────────────────
|
|
778
|
+
['docusaurus', ['docusaurus', 'docusaurus build', 'docusaurus start']],
|
|
779
|
+
['mkdocs-material', ['mkdocs-material', 'mkdocs build']],
|
|
780
|
+
['sphinx', ['sphinx', 'sphinx-build', 'sphinx-autogen']],
|
|
781
|
+
['mdbook', ['mdbook', 'rust-lang/mdbook', 'mdbook build']],
|
|
782
|
+
// ── Workflow (more) ──────────────────────────────────────────────
|
|
783
|
+
['kestra', ['kestra', 'kestra flow']],
|
|
784
|
+
['windmill', ['windmill', 'windmill-dev', 'windmill script']],
|
|
785
|
+
['inngest', ['inngest', 'inngest function']],
|
|
786
|
+
['triggerdev', ['trigger.dev', 'triggerdev', 'trigger.dev job']],
|
|
787
|
+
// ── Messaging (more) ────────────────────────────────────────────
|
|
788
|
+
['bullmq', ['bullmq', 'bull mq', 'bullmq queue']],
|
|
789
|
+
['bull-redis', ['bull redis', 'bull queue', 'bull.process']],
|
|
790
|
+
// ── Infrastructure (more) ────────────────────────────────────────
|
|
791
|
+
['aws-cdk', ['aws cdk', 'cdk deploy', 'cdk synth', 'cdk diff']],
|
|
792
|
+
['cdktf', ['cdktf', 'cdk for terraform', 'cdktf deploy']],
|
|
793
|
+
['minikube', ['minikube', 'minikube start', 'minikube dashboard']],
|
|
794
|
+
['kind', ['kind create', 'sigs.k8s.io/kind']],
|
|
795
|
+
['k3s', ['k3s', 'k3s server', 'k3s agent']],
|
|
796
|
+
['k3d', ['k3d', 'k3d cluster', 'k3d create']],
|
|
797
|
+
// ── AI Frameworks (continued) ────────────────────────────────────
|
|
798
|
+
['langchain', ['langchain', 'langchain.py', 'langchain.js']],
|
|
799
|
+
// ── FinOps / Cost ────────────────────────────────────────────────
|
|
800
|
+
['opencost', ['opencost', 'opencost metrics']],
|
|
801
|
+
['kubecost', ['kubecost', 'kubecost api']],
|
|
802
|
+
['aws-cost-explorer', ['cost explorer', 'aws cost']],
|
|
803
|
+
// ── Policy / Governance ──────────────────────────────────────────
|
|
804
|
+
['opa', ['open policy agent', 'opa eval', 'rego:']],
|
|
805
|
+
['sentinel', ['sentinel policy', 'hashicorp sentinel']],
|
|
806
|
+
// ── Browser Automation ───────────────────────────────────────────
|
|
807
|
+
['puppeteer', ['puppeteer', 'puppeteer browser']],
|
|
808
|
+
['playwright-test', ['playwright test', '@playwright/test']],
|
|
809
|
+
// ── Container Registries (more) ──────────────────────────────────
|
|
810
|
+
['ecr', ['amazon ecr', 'aws ecr', 'ecr.amazonaws']],
|
|
811
|
+
['gcr', ['gcr.io', 'google container registry']],
|
|
812
|
+
['acr', ['azure container registry', 'azurecr.io']],
|
|
813
|
+
// ── Config Management (more) ──────────────────────────────────────
|
|
814
|
+
['cosign', ['cosign', 'cosign sign', 'cosign verify']],
|
|
815
|
+
['sbom', ['sbom', 'syft sbom', 'spdx']],
|
|
816
|
+
['syft', ['syft', 'syft packages']],
|
|
817
|
+
['scorecard', ['openssf scorecard', 'scorecard', 'oss scorecard']],
|
|
818
|
+
// ── Git Tools ────────────────────────────────────────────────────
|
|
819
|
+
['gitlab', ['gitlab.com', 'gitlab runner', 'gitlab api']],
|
|
820
|
+
['bitbucket', ['bitbucket', 'bitbucket-pipelines', 'bitbucket.org']],
|
|
821
|
+
['pre-commit', ['pre-commit', 'pre-commit run']],
|
|
822
|
+
['husky', ['husky', 'husky install']],
|
|
823
|
+
// ── Language Runtimes ────────────────────────────────────────────
|
|
824
|
+
['graalvm', ['graalvm', 'native-image']],
|
|
825
|
+
['jvm', ['hotspot', 'openjdk', 'java version']],
|
|
826
|
+
['v8', ['v8 engine', 'v8::']],
|
|
827
|
+
['cpython', ['cpython', 'python3.1', 'python3.1']],
|
|
828
|
+
// ── Network / DNS ────────────────────────────────────────────────
|
|
829
|
+
['coredns', ['coredns', 'coredns plugin']],
|
|
830
|
+
['powerdns', ['powerdns', 'pdns']],
|
|
831
|
+
['bind9', ['bind9', 'named:', 'isc bind']],
|
|
832
|
+
// ── Service Mesh (more) ──────────────────────────────────────────
|
|
833
|
+
['aws-app-mesh', ['app mesh', 'aws app mesh']],
|
|
834
|
+
['consul-service-mesh', ['consul service mesh', 'consul connect proxy']],
|
|
835
|
+
// ── Backup / DR ──────────────────────────────────────────────────
|
|
836
|
+
['velero', ['velero', 'velero backup', 'velero restore']],
|
|
837
|
+
['restic', ['restic', 'restic backup', 'restic restore']],
|
|
838
|
+
['borg', ['borg backup', 'borgmatic']],
|
|
839
|
+
];
|
|
840
|
+
exports.KNOWN_LOG_SOURCES = exports.LOG_SOURCE_SIGNATURES.map(([source]) => source);
|
|
841
|
+
function collectDetectedSourceHits(line, hits, sources = exports.LOG_SOURCE_SIGNATURES) {
|
|
842
|
+
const normalized = line.toLowerCase();
|
|
843
|
+
for (const [source, markers] of sources) {
|
|
844
|
+
for (const marker of markers) {
|
|
845
|
+
if (normalized.includes(marker)) {
|
|
846
|
+
hits.set(source, (hits.get(source) ?? 0) + 1);
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
function rankDetectedSources(hits, limit = 12) {
|
|
853
|
+
if (limit <= 0) {
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
return [...hits.entries()]
|
|
857
|
+
.sort((left, right) => {
|
|
858
|
+
if (right[1] !== left[1]) {
|
|
859
|
+
return right[1] - left[1];
|
|
860
|
+
}
|
|
861
|
+
return left[0].localeCompare(right[0]);
|
|
862
|
+
})
|
|
863
|
+
.slice(0, limit)
|
|
864
|
+
.map(([source]) => source);
|
|
865
|
+
}
|
|
866
|
+
function detectLogSources(input, limit = 12) {
|
|
867
|
+
const hits = new Map();
|
|
868
|
+
const lines = typeof input === 'string' ? input.split(/\r?\n/u) : [...input];
|
|
869
|
+
for (const line of lines) {
|
|
870
|
+
collectDetectedSourceHits(line, hits);
|
|
871
|
+
}
|
|
872
|
+
return rankDetectedSources(hits, limit);
|
|
873
|
+
}
|
|
874
|
+
function parseAggressiveness(value) {
|
|
875
|
+
const normalized = (value ?? 'high').toLowerCase();
|
|
876
|
+
if (AGGRESSIVENESS_LEVELS.includes(normalized)) {
|
|
877
|
+
return normalized;
|
|
878
|
+
}
|
|
879
|
+
throw new Error(`Unsupported aggressiveness "${value}". Expected one of: ${AGGRESSIVENESS_LEVELS.join(', ')}.`);
|
|
880
|
+
}
|
|
881
|
+
function sanitizeLine(line) {
|
|
882
|
+
return line
|
|
883
|
+
.replace(ANSI_ESCAPE_PATTERN, '')
|
|
884
|
+
.replace(UUID_PATTERN, '[ID]')
|
|
885
|
+
.replace(UTC_TIME_PATTERN, '[TIME]')
|
|
886
|
+
.replace(COMMON_LOG_TIME_PATTERN, '[TIME]')
|
|
887
|
+
.replace(NGINX_ERROR_TIME_PATTERN, '[TIME]')
|
|
888
|
+
.replace(ISO_TIME_PATTERN, '[TIME]')
|
|
889
|
+
.replace(IPV4_WITH_PORT_PATTERN, '[IP]:[PORT]')
|
|
890
|
+
.replace(IPV4_PATTERN, '[IP]')
|
|
891
|
+
.replace(HEX_HASH_PATTERN, '[HASH]')
|
|
892
|
+
.replace(ALPHANUMERIC_HASH_PATTERN, '[HASH]')
|
|
893
|
+
.replace(AWS_ACCESS_KEY_PATTERN, '[REDACTED]')
|
|
894
|
+
.replace(AWS_ARN_ACCOUNT_PATTERN, (match, accountId) => match.replace(accountId, '[ACCOUNT]'))
|
|
895
|
+
.replace(/[ \t]+$/u, '');
|
|
896
|
+
}
|
|
897
|
+
function createRepeatSignature(line) {
|
|
898
|
+
return tokenizeRepeatLine(line)
|
|
899
|
+
.map((token) => {
|
|
900
|
+
const tokenValue = splitRepeatToken(token);
|
|
901
|
+
return tokenValue === undefined
|
|
902
|
+
? token
|
|
903
|
+
: `${tokenValue.prefix}[VALUE]`;
|
|
904
|
+
})
|
|
905
|
+
.join(' ');
|
|
906
|
+
}
|
|
907
|
+
function tokenizeRepeatLine(line) {
|
|
908
|
+
return line.trim().split(/\s+/u);
|
|
909
|
+
}
|
|
910
|
+
function splitRepeatToken(token) {
|
|
911
|
+
const separator = token.indexOf('=');
|
|
912
|
+
if (separator <= 0 || separator === token.length - 1) {
|
|
913
|
+
return undefined;
|
|
914
|
+
}
|
|
915
|
+
return {
|
|
916
|
+
prefix: token.slice(0, separator + 1),
|
|
917
|
+
value: token.slice(separator + 1),
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
function createRepeatGroup(line) {
|
|
921
|
+
return {
|
|
922
|
+
firstLine: line,
|
|
923
|
+
firstTokens: tokenizeRepeatLine(line),
|
|
924
|
+
signature: createRepeatSignature(line),
|
|
925
|
+
deltas: new Map(),
|
|
926
|
+
count: 1,
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
function addRepeatGroupLine(group, line) {
|
|
930
|
+
const tokens = tokenizeRepeatLine(line);
|
|
931
|
+
for (const [index, firstToken] of group.firstTokens.entries()) {
|
|
932
|
+
const firstValue = splitRepeatToken(firstToken);
|
|
933
|
+
const nextValue = splitRepeatToken(tokens[index]);
|
|
934
|
+
if (firstValue === undefined ||
|
|
935
|
+
nextValue === undefined ||
|
|
936
|
+
firstValue.prefix !== nextValue.prefix ||
|
|
937
|
+
firstValue.value === nextValue.value) {
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
const delta = group.deltas.get(index) ?? {
|
|
941
|
+
prefix: firstValue.prefix,
|
|
942
|
+
values: [firstValue.value],
|
|
943
|
+
hasMoreValues: false,
|
|
944
|
+
};
|
|
945
|
+
if (!group.deltas.has(index)) {
|
|
946
|
+
group.deltas.set(index, delta);
|
|
947
|
+
}
|
|
948
|
+
if (delta.values.includes(nextValue.value)) {
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
if (delta.values.length < exports.MAX_REPEAT_DELTA_VALUES) {
|
|
952
|
+
delta.values.push(nextValue.value);
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
delta.hasMoreValues = true;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
group.count += 1;
|
|
959
|
+
}
|
|
960
|
+
function renderRepeatGroup(group) {
|
|
961
|
+
if (group.deltas.size === 0) {
|
|
962
|
+
return group.firstLine;
|
|
963
|
+
}
|
|
964
|
+
const tokens = [...group.firstTokens];
|
|
965
|
+
for (const [index, delta] of group.deltas) {
|
|
966
|
+
const values = delta.hasMoreValues
|
|
967
|
+
? [...delta.values, '…']
|
|
968
|
+
: delta.values;
|
|
969
|
+
tokens[index] = `${delta.prefix}[${values.join(' | ')}]`;
|
|
970
|
+
}
|
|
971
|
+
return tokens.join(' ');
|
|
972
|
+
}
|
|
973
|
+
function shouldKeepLine(line) {
|
|
974
|
+
if (line.trim().length === 0) {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
if (IGNORED_LOG_TAG_PATTERN.test(line)) {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
if (IMPORTANT_LOG_TAG_PATTERN.test(line)) {
|
|
981
|
+
return true;
|
|
982
|
+
}
|
|
983
|
+
if (!EXPLICIT_LOG_TAG_PATTERN.test(line) && looksLikeDiagnosticLine(line)) {
|
|
984
|
+
return true;
|
|
985
|
+
}
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
function looksLikeDiagnosticLine(line) {
|
|
989
|
+
return (STACK_FRAME_PATTERN.test(line) ||
|
|
990
|
+
JAVA_STACK_FRAME_PATTERN.test(line) ||
|
|
991
|
+
PYTHON_STACK_FRAME_PATTERN.test(line) ||
|
|
992
|
+
GO_STACK_FRAME_PATTERN.test(line) ||
|
|
993
|
+
GO_FILE_FRAME_PATTERN.test(line) ||
|
|
994
|
+
GO_GOROUTINE_PATTERN.test(line) ||
|
|
995
|
+
PYTHON_TRACEBACK_PATTERN.test(line) ||
|
|
996
|
+
STACK_MORE_PATTERN.test(line) ||
|
|
997
|
+
DIAGNOSTIC_PATTERN.test(line) ||
|
|
998
|
+
JSON_SEVERITY_PATTERN.test(line) ||
|
|
999
|
+
NPM_ERROR_PATTERN.test(line) ||
|
|
1000
|
+
YARN_ERROR_PATTERN.test(line) ||
|
|
1001
|
+
SCANNER_FINDING_PATTERN.test(line) ||
|
|
1002
|
+
CONTAINER_FAILURE_PATTERN.test(line) ||
|
|
1003
|
+
GITHUB_ACTIONS_ANNOTATION_PATTERN.test(line) ||
|
|
1004
|
+
GRADLE_FAILURE_PATTERN.test(line) ||
|
|
1005
|
+
MAKE_ERROR_PATTERN.test(line) ||
|
|
1006
|
+
GO_TEST_FAIL_PATTERN.test(line) ||
|
|
1007
|
+
SYSTEMD_STATUS_PATTERN.test(line) ||
|
|
1008
|
+
CIRCLECI_STEP_PATTERN.test(line) ||
|
|
1009
|
+
JENKINS_MARKER_PATTERN.test(line) ||
|
|
1010
|
+
AZURE_PIPELINE_PATTERN.test(line) ||
|
|
1011
|
+
TEAMCITY_MARKER_PATTERN.test(line));
|
|
1012
|
+
}
|
|
1013
|
+
function isInternalStackTraceLine(line) {
|
|
1014
|
+
if (IMPORTANT_LOG_TAG_PATTERN.test(line))
|
|
1015
|
+
return false;
|
|
1016
|
+
return looksLikeDiagnosticLine(line) && INTERNAL_STACK_PATTERN.test(line);
|
|
1017
|
+
}
|
|
1018
|
+
function estimateTokens(wordCount) {
|
|
1019
|
+
return Math.ceil(wordCount * 1.3);
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Multi-signal relevance score for a single (sanitized) log line.
|
|
1023
|
+
* >= SCORE_KEEP_THRESHOLD → emit immediately
|
|
1024
|
+
* 0 to <SCORE_KEEP_THRESHOLD → buffer in context window
|
|
1025
|
+
* < 0 or -Infinity → drop
|
|
1026
|
+
*/
|
|
1027
|
+
function scoreLineRelevance(line, aggressiveness, seenCount = 0) {
|
|
1028
|
+
if (line.trim().length === 0)
|
|
1029
|
+
return -Infinity;
|
|
1030
|
+
// Noise tags always drop – callers may short-circuit before this
|
|
1031
|
+
if (IGNORED_LOG_TAG_PATTERN.test(line))
|
|
1032
|
+
return -Infinity;
|
|
1033
|
+
let score = 0;
|
|
1034
|
+
// High-value signals (additive – a line can match multiple)
|
|
1035
|
+
if (IMPORTANT_LOG_TAG_PATTERN.test(line))
|
|
1036
|
+
score += 100;
|
|
1037
|
+
if (JSON_SEVERITY_PATTERN.test(line))
|
|
1038
|
+
score += 80;
|
|
1039
|
+
if (SCANNER_FINDING_PATTERN.test(line))
|
|
1040
|
+
score += 70;
|
|
1041
|
+
if (CONTAINER_FAILURE_PATTERN.test(line))
|
|
1042
|
+
score += 70;
|
|
1043
|
+
if (GITHUB_ACTIONS_ANNOTATION_PATTERN.test(line))
|
|
1044
|
+
score += 70;
|
|
1045
|
+
if (GRADLE_FAILURE_PATTERN.test(line))
|
|
1046
|
+
score += 60;
|
|
1047
|
+
if (NPM_ERROR_PATTERN.test(line) || YARN_ERROR_PATTERN.test(line))
|
|
1048
|
+
score += 60;
|
|
1049
|
+
if (DIAGNOSTIC_PATTERN.test(line))
|
|
1050
|
+
score += 50;
|
|
1051
|
+
if (GO_TEST_FAIL_PATTERN.test(line))
|
|
1052
|
+
score += 50;
|
|
1053
|
+
if (MAKE_ERROR_PATTERN.test(line))
|
|
1054
|
+
score += 50;
|
|
1055
|
+
if (SYSTEMD_STATUS_PATTERN.test(line))
|
|
1056
|
+
score += 50;
|
|
1057
|
+
if (CIRCLECI_STEP_PATTERN.test(line))
|
|
1058
|
+
score += 50;
|
|
1059
|
+
if (JENKINS_MARKER_PATTERN.test(line))
|
|
1060
|
+
score += 40;
|
|
1061
|
+
if (AZURE_PIPELINE_PATTERN.test(line))
|
|
1062
|
+
score += 40;
|
|
1063
|
+
if (TEAMCITY_MARKER_PATTERN.test(line))
|
|
1064
|
+
score += 40;
|
|
1065
|
+
// Stack-frame signals
|
|
1066
|
+
if (STACK_FRAME_PATTERN.test(line) ||
|
|
1067
|
+
JAVA_STACK_FRAME_PATTERN.test(line) ||
|
|
1068
|
+
PYTHON_STACK_FRAME_PATTERN.test(line) ||
|
|
1069
|
+
GO_GOROUTINE_PATTERN.test(line) ||
|
|
1070
|
+
PYTHON_TRACEBACK_PATTERN.test(line) ||
|
|
1071
|
+
STACK_MORE_PATTERN.test(line)) {
|
|
1072
|
+
score += 40;
|
|
1073
|
+
}
|
|
1074
|
+
// Aggressiveness modifiers
|
|
1075
|
+
if (aggressiveness === 'aggressive' &&
|
|
1076
|
+
AGGRESSIVE_WARN_PATTERN.test(line) &&
|
|
1077
|
+
!AGGRESSIVE_WARNING_SIGNAL_PATTERN.test(line)) {
|
|
1078
|
+
score = -1; // pure WARN without error keyword → drop
|
|
1079
|
+
}
|
|
1080
|
+
if (aggressiveness === 'low' && LOW_EXTRA_TAG_PATTERN.test(line)) {
|
|
1081
|
+
score += 30;
|
|
1082
|
+
}
|
|
1083
|
+
// TF-IDF dampening: penalise lines seen many times in this stream
|
|
1084
|
+
if (seenCount >= exports.TFIDF_REPEAT_THRESHOLD) {
|
|
1085
|
+
score -= exports.TFIDF_PENALTY * (seenCount - exports.TFIDF_REPEAT_THRESHOLD + 1);
|
|
1086
|
+
}
|
|
1087
|
+
return score;
|
|
1088
|
+
}
|
|
1089
|
+
function buildMergedConfig(options = {}) {
|
|
1090
|
+
const config = (0, logstrip_config_js_1.loadLogStripConfig)(options.configPath);
|
|
1091
|
+
const mergedSources = [
|
|
1092
|
+
...exports.LOG_SOURCE_SIGNATURES,
|
|
1093
|
+
];
|
|
1094
|
+
for (const sig of config.sources) {
|
|
1095
|
+
const existing = mergedSources.find(([name]) => name === sig.name);
|
|
1096
|
+
if (existing !== undefined) {
|
|
1097
|
+
const merged = [...new Set([...existing[1], ...sig.markers])];
|
|
1098
|
+
const idx = mergedSources.indexOf(existing);
|
|
1099
|
+
mergedSources[idx] = [sig.name, merged];
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
mergedSources.push([sig.name, sig.markers]);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return { ...config, mergedSources };
|
|
1106
|
+
}
|
|
1107
|
+
async function processLogStream(input, output, options = {}) {
|
|
1108
|
+
const aggressiveness = parseAggressiveness(options.aggressiveness);
|
|
1109
|
+
const merged = buildMergedConfig(options);
|
|
1110
|
+
// Compile custom patterns once per stream
|
|
1111
|
+
const customDiagnosticRegexes = merged.diagnosticPatterns.map((p) => new RegExp(p, 'u'));
|
|
1112
|
+
const customIgnoreRegexes = merged.ignorePatterns.map((p) => new RegExp(p, 'u'));
|
|
1113
|
+
const customInternalStackRegexes = merged.internalStackPatterns.map((p) => new RegExp(p, 'u'));
|
|
1114
|
+
const customSanitizeRules = merged.sanitizePatterns.map((r) => ({ regex: new RegExp(r.pattern, r.flags ?? 'gu'), replacement: r.replacement }));
|
|
1115
|
+
const stats = createEmptyStats();
|
|
1116
|
+
const detectedSourceHits = new Map();
|
|
1117
|
+
// TF-IDF: frequency map for sanitized lines (bounded for memory safety)
|
|
1118
|
+
const seenLines = new Map();
|
|
1119
|
+
// Context window: ring-buffer of soft-scored lines pending near-error promotion
|
|
1120
|
+
const contextBefore = [];
|
|
1121
|
+
let afterContextRemaining = 0;
|
|
1122
|
+
const lines = (0, node_readline_1.createInterface)({ input, crlfDelay: Infinity });
|
|
1123
|
+
let previousGroup;
|
|
1124
|
+
let hidingInternalStack = false;
|
|
1125
|
+
const flushPreviousLine = async () => {
|
|
1126
|
+
if (previousGroup === undefined) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
const line = previousGroup.count > 1
|
|
1130
|
+
? `[x${previousGroup.count}] ${renderRepeatGroup(previousGroup)}`
|
|
1131
|
+
: previousGroup.firstLine;
|
|
1132
|
+
if (previousGroup.count > 1) {
|
|
1133
|
+
stats.duplicateLines += previousGroup.count - 1;
|
|
1134
|
+
}
|
|
1135
|
+
await writeOutputLine(output, line, stats);
|
|
1136
|
+
previousGroup = undefined;
|
|
1137
|
+
};
|
|
1138
|
+
const emitCandidate = async (line) => {
|
|
1139
|
+
const signature = createRepeatSignature(line);
|
|
1140
|
+
if (previousGroup?.signature === signature) {
|
|
1141
|
+
addRepeatGroupLine(previousGroup, line);
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
await flushPreviousLine();
|
|
1145
|
+
previousGroup = createRepeatGroup(line);
|
|
1146
|
+
};
|
|
1147
|
+
// Flush buffered context lines (retroactive promotion near an error)
|
|
1148
|
+
const flushContextBefore = async () => {
|
|
1149
|
+
for (const buffered of contextBefore) {
|
|
1150
|
+
await emitCandidate(buffered);
|
|
1151
|
+
}
|
|
1152
|
+
contextBefore.length = 0;
|
|
1153
|
+
};
|
|
1154
|
+
for await (const rawLine of lines) {
|
|
1155
|
+
const line = String(rawLine);
|
|
1156
|
+
collectDetectedSourceHits(line, detectedSourceHits, merged.mergedSources);
|
|
1157
|
+
stats.inputLines += 1;
|
|
1158
|
+
stats.inputWords += countWords(line);
|
|
1159
|
+
stats.inputBytes += Buffer.byteLength(`${line}\n`, 'utf8');
|
|
1160
|
+
// Empty lines always dropped; don't disturb context state
|
|
1161
|
+
if (line.trim().length === 0) {
|
|
1162
|
+
stats.droppedLines += 1;
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
// Custom ignore patterns (drop matching lines early)
|
|
1166
|
+
if (customIgnoreRegexes.some((r) => r.test(line))) {
|
|
1167
|
+
stats.droppedLines += 1;
|
|
1168
|
+
hidingInternalStack = false;
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
// Noise tags (INFO/DEBUG/TRACE/VERBOSE) are silently dropped without
|
|
1172
|
+
// disturbing afterContextRemaining so that sparse INFO lines between
|
|
1173
|
+
// errors do not close the context window prematurely.
|
|
1174
|
+
if (IGNORED_LOG_TAG_PATTERN.test(line)) {
|
|
1175
|
+
stats.droppedLines += 1;
|
|
1176
|
+
hidingInternalStack = false;
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
let sanitized = sanitizeLine(line);
|
|
1180
|
+
// Apply custom sanitize rules
|
|
1181
|
+
for (const rule of customSanitizeRules) {
|
|
1182
|
+
sanitized = sanitized.replace(rule.regex, rule.replacement);
|
|
1183
|
+
}
|
|
1184
|
+
// Internal stack-frame collapsing (priority over scoring)
|
|
1185
|
+
const isCustomInternalStack = customInternalStackRegexes.length > 0 &&
|
|
1186
|
+
customInternalStackRegexes.some((r) => r.test(sanitized));
|
|
1187
|
+
if (isInternalStackTraceLine(sanitized) || isCustomInternalStack) {
|
|
1188
|
+
stats.hiddenInternalStackLines += 1;
|
|
1189
|
+
if (!hidingInternalStack) {
|
|
1190
|
+
await flushContextBefore();
|
|
1191
|
+
await emitCandidate(exports.INTERNAL_STACK_MARKER);
|
|
1192
|
+
hidingInternalStack = true;
|
|
1193
|
+
afterContextRemaining = 0;
|
|
1194
|
+
}
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
hidingInternalStack = false;
|
|
1198
|
+
// TF-IDF: track how many times this sanitized form has appeared.
|
|
1199
|
+
let seenCount = (seenLines.get(sanitized) ?? 0) + 1;
|
|
1200
|
+
if (seenCount === 1 && seenLines.size >= exports.TFIDF_MAP_LIMIT) {
|
|
1201
|
+
seenLines.clear();
|
|
1202
|
+
seenCount = 1;
|
|
1203
|
+
}
|
|
1204
|
+
seenLines.set(sanitized, seenCount);
|
|
1205
|
+
// Score the sanitized line (built-in + custom diagnostic patterns)
|
|
1206
|
+
let score = scoreLineRelevance(sanitized, aggressiveness, seenCount);
|
|
1207
|
+
// Custom diagnostic patterns contribute +50 per match (same as built-in DIAGNOSTIC_PATTERN)
|
|
1208
|
+
for (const regex of customDiagnosticRegexes) {
|
|
1209
|
+
if (regex.test(sanitized)) {
|
|
1210
|
+
score += 50;
|
|
1211
|
+
break;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
if (score >= exports.SCORE_KEEP_THRESHOLD) {
|
|
1215
|
+
// Hard keep: flush buffered context, emit, open after-context window
|
|
1216
|
+
await flushContextBefore();
|
|
1217
|
+
await emitCandidate(sanitized);
|
|
1218
|
+
afterContextRemaining = exports.CONTEXT_WINDOW_AFTER;
|
|
1219
|
+
}
|
|
1220
|
+
else if (afterContextRemaining > 0) {
|
|
1221
|
+
// Inside after-context window: emit regardless of score
|
|
1222
|
+
await emitCandidate(sanitized);
|
|
1223
|
+
afterContextRemaining -= 1;
|
|
1224
|
+
}
|
|
1225
|
+
else if (score >= 0) {
|
|
1226
|
+
// Soft: buffer in context ring (oldest evicted & counted as dropped)
|
|
1227
|
+
if (contextBefore.length >= exports.CONTEXT_WINDOW_BEFORE) {
|
|
1228
|
+
contextBefore.shift();
|
|
1229
|
+
stats.droppedLines += 1;
|
|
1230
|
+
}
|
|
1231
|
+
contextBefore.push(sanitized);
|
|
1232
|
+
}
|
|
1233
|
+
else {
|
|
1234
|
+
// Hard drop (score < 0): negative TF-IDF or aggressive WARN suppression
|
|
1235
|
+
stats.droppedLines += 1;
|
|
1236
|
+
afterContextRemaining = 0;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
// Context lines left without a triggering error are discarded
|
|
1240
|
+
stats.droppedLines += contextBefore.length;
|
|
1241
|
+
contextBefore.length = 0;
|
|
1242
|
+
await flushPreviousLine();
|
|
1243
|
+
const inputTokens = estimateTokens(stats.inputWords);
|
|
1244
|
+
const outputTokens = estimateTokens(stats.outputWords);
|
|
1245
|
+
const savedTokens = Math.max(inputTokens - outputTokens, 0);
|
|
1246
|
+
const savingsPercent = inputTokens === 0 ? 0 : Math.round((savedTokens / inputTokens) * 10000) / 100;
|
|
1247
|
+
return {
|
|
1248
|
+
stats,
|
|
1249
|
+
inputTokens,
|
|
1250
|
+
outputTokens,
|
|
1251
|
+
savedTokens,
|
|
1252
|
+
savingsPercent,
|
|
1253
|
+
detectedSources: rankDetectedSources(detectedSourceHits),
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
async function processLogFile(inputPath, outputPath, options = {}) {
|
|
1257
|
+
if (pathsReferToSameFile(inputPath, outputPath)) {
|
|
1258
|
+
throw new Error('Input and output paths must be different; refusing to overwrite the input log');
|
|
1259
|
+
}
|
|
1260
|
+
const input = (0, node_fs_1.createReadStream)(inputPath, { encoding: 'utf8' });
|
|
1261
|
+
const output = (0, node_fs_1.createWriteStream)(outputPath, { encoding: 'utf8' });
|
|
1262
|
+
try {
|
|
1263
|
+
const result = await processLogStream(input, output, options);
|
|
1264
|
+
output.end();
|
|
1265
|
+
await (0, promises_1.finished)(output);
|
|
1266
|
+
return { ...result, outputPath };
|
|
1267
|
+
}
|
|
1268
|
+
catch (error) {
|
|
1269
|
+
input.destroy();
|
|
1270
|
+
output.destroy();
|
|
1271
|
+
throw error;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
function pathsReferToSameFile(inputPath, outputPath) {
|
|
1275
|
+
return (node_path_1.default.resolve(inputPath).toLowerCase() ===
|
|
1276
|
+
node_path_1.default.resolve(outputPath).toLowerCase());
|
|
1277
|
+
}
|
|
1278
|
+
function createEmptyStats() {
|
|
1279
|
+
return {
|
|
1280
|
+
inputLines: 0,
|
|
1281
|
+
outputLines: 0,
|
|
1282
|
+
inputWords: 0,
|
|
1283
|
+
outputWords: 0,
|
|
1284
|
+
inputBytes: 0,
|
|
1285
|
+
outputBytes: 0,
|
|
1286
|
+
droppedLines: 0,
|
|
1287
|
+
duplicateLines: 0,
|
|
1288
|
+
hiddenInternalStackLines: 0,
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
function countWords(line) {
|
|
1292
|
+
return line.trim().match(/\S+/gu)?.length ?? 0;
|
|
1293
|
+
}
|
|
1294
|
+
async function writeOutputLine(output, line, stats) {
|
|
1295
|
+
const rendered = `${line}\n`;
|
|
1296
|
+
stats.outputLines += 1;
|
|
1297
|
+
stats.outputWords += countWords(line);
|
|
1298
|
+
stats.outputBytes += Buffer.byteLength(rendered, 'utf8');
|
|
1299
|
+
if (!output.write(rendered)) {
|
|
1300
|
+
await (0, node_events_1.once)(output, 'drain');
|
|
1301
|
+
}
|
|
1302
|
+
}
|