netlog-ai 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. netlog_ai-0.3.0/LICENSE +21 -0
  2. netlog_ai-0.3.0/PKG-INFO +464 -0
  3. netlog_ai-0.3.0/README.md +422 -0
  4. netlog_ai-0.3.0/pyproject.toml +74 -0
  5. netlog_ai-0.3.0/setup.cfg +4 -0
  6. netlog_ai-0.3.0/src/ai_log_analyzer/__init__.py +114 -0
  7. netlog_ai-0.3.0/src/ai_log_analyzer/adapters/__init__.py +6 -0
  8. netlog_ai-0.3.0/src/ai_log_analyzer/adapters/file.py +168 -0
  9. netlog_ai-0.3.0/src/ai_log_analyzer/adapters/frr.py +125 -0
  10. netlog_ai-0.3.0/src/ai_log_analyzer/adapters/network_tool.py +193 -0
  11. netlog_ai-0.3.0/src/ai_log_analyzer/adapters/tfsm_auto.py +194 -0
  12. netlog_ai-0.3.0/src/ai_log_analyzer/analyzer.py +862 -0
  13. netlog_ai-0.3.0/src/ai_log_analyzer/classifier.py +317 -0
  14. netlog_ai-0.3.0/src/ai_log_analyzer/cli.py +96 -0
  15. netlog_ai-0.3.0/src/ai_log_analyzer/compliance.py +206 -0
  16. netlog_ai-0.3.0/src/ai_log_analyzer/copilot.py +60 -0
  17. netlog_ai-0.3.0/src/ai_log_analyzer/correlate.py +224 -0
  18. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/_manifest.json +73 -0
  19. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/eos-rt-01.txt +2134 -0
  20. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/eos-sw-01.txt +461 -0
  21. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/junos-fw-01.txt +2963 -0
  22. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/junos-rt-01.txt +7266 -0
  23. netlog_ai-0.3.0/src/ai_log_analyzer/data/samples/junos-sw-01.txt +1815 -0
  24. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf1.txt +149 -0
  25. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf2.txt +2255 -0
  26. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf3.txt +99 -0
  27. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf4.txt +149 -0
  28. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf5.txt +2255 -0
  29. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/leaf6.txt +99 -0
  30. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/manifest.json +144 -0
  31. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/spine1.txt +2370 -0
  32. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/spine2.txt +141 -0
  33. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/clab-clos-evpn/spine3.txt +103 -0
  34. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/de-fra-core-01.txt +55 -0
  35. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/de-fra-core-02.txt +50 -0
  36. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/de-fra-dist-01.txt +35 -0
  37. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/de-fra-edge-01.txt +40 -0
  38. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/manifest.json +170 -0
  39. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/nl-ams-core-01.txt +50 -0
  40. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/nl-ams-edge-01.txt +35 -0
  41. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/uk-lon-core-01.txt +55 -0
  42. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/uk-lon-dist-01.txt +35 -0
  43. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/uk-lon-edge-01.txt +40 -0
  44. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/dcn-lab/us-nyc-core-01.txt +45 -0
  45. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/fw-01a.txt +269 -0
  46. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/fw-01b.txt +269 -0
  47. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/manifest.json +87 -0
  48. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/rt-01.txt +133 -0
  49. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/sw-01.txt +103 -0
  50. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-alpha/sw-02.txt +103 -0
  51. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/fw-01.txt +269 -0
  52. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/manifest.json +103 -0
  53. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/rt-01.txt +140 -0
  54. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/rt-02.txt +140 -0
  55. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/sw-01.txt +108 -0
  56. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/sw-02.txt +108 -0
  57. netlog_ai-0.3.0/src/ai_log_analyzer/data/sites/lab-bravo/sw-03.txt +108 -0
  58. netlog_ai-0.3.0/src/ai_log_analyzer/device_triage.py +272 -0
  59. netlog_ai-0.3.0/src/ai_log_analyzer/diff.py +147 -0
  60. netlog_ai-0.3.0/src/ai_log_analyzer/kb.py +1587 -0
  61. netlog_ai-0.3.0/src/ai_log_analyzer/llm.py +384 -0
  62. netlog_ai-0.3.0/src/ai_log_analyzer/mcp_server/__init__.py +8 -0
  63. netlog_ai-0.3.0/src/ai_log_analyzer/mcp_server/server.py +342 -0
  64. netlog_ai-0.3.0/src/ai_log_analyzer/postmortem.py +94 -0
  65. netlog_ai-0.3.0/src/ai_log_analyzer/reports.py +319 -0
  66. netlog_ai-0.3.0/src/ai_log_analyzer/runbook.py +160 -0
  67. netlog_ai-0.3.0/src/ai_log_analyzer/sanitize.py +237 -0
  68. netlog_ai-0.3.0/src/ai_log_analyzer/site_diagram.py +695 -0
  69. netlog_ai-0.3.0/src/ai_log_analyzer/site_doc.py +1427 -0
  70. netlog_ai-0.3.0/src/ai_log_analyzer/site_optimize.py +1075 -0
  71. netlog_ai-0.3.0/src/ai_log_analyzer/sources/__init__.py +38 -0
  72. netlog_ai-0.3.0/src/ai_log_analyzer/sources/base.py +145 -0
  73. netlog_ai-0.3.0/src/ai_log_analyzer/sources/kibana.py +160 -0
  74. netlog_ai-0.3.0/src/ai_log_analyzer/sources/librenms.py +93 -0
  75. netlog_ai-0.3.0/src/ai_log_analyzer/sources/loki.py +112 -0
  76. netlog_ai-0.3.0/src/ai_log_analyzer/sources/manager.py +167 -0
  77. netlog_ai-0.3.0/src/ai_log_analyzer/sources/splunk.py +115 -0
  78. netlog_ai-0.3.0/src/ai_log_analyzer/sources/syslog.py +157 -0
  79. netlog_ai-0.3.0/src/ai_log_analyzer/topology.py +695 -0
  80. netlog_ai-0.3.0/src/ai_log_analyzer/topology_infer.py +693 -0
  81. netlog_ai-0.3.0/src/ai_log_analyzer/web/__init__.py +4 -0
  82. netlog_ai-0.3.0/src/ai_log_analyzer/web/app.py +972 -0
  83. netlog_ai-0.3.0/src/ai_log_analyzer/web/static/app.js +2719 -0
  84. netlog_ai-0.3.0/src/ai_log_analyzer/web/static/index.html +1613 -0
  85. netlog_ai-0.3.0/src/ai_log_analyzer/web/static/vendor/cytoscape-elk.js +356 -0
  86. netlog_ai-0.3.0/src/ai_log_analyzer/web/static/vendor/cytoscape.min.js +32 -0
  87. netlog_ai-0.3.0/src/ai_log_analyzer/web/static/vendor/elk.bundled.js +6696 -0
  88. netlog_ai-0.3.0/src/ai_log_analyzer/webhooks.py +119 -0
  89. netlog_ai-0.3.0/src/netlog_ai.egg-info/PKG-INFO +464 -0
  90. netlog_ai-0.3.0/src/netlog_ai.egg-info/SOURCES.txt +117 -0
  91. netlog_ai-0.3.0/src/netlog_ai.egg-info/dependency_links.txt +1 -0
  92. netlog_ai-0.3.0/src/netlog_ai.egg-info/entry_points.txt +3 -0
  93. netlog_ai-0.3.0/src/netlog_ai.egg-info/requires.txt +20 -0
  94. netlog_ai-0.3.0/src/netlog_ai.egg-info/top_level.txt +1 -0
  95. netlog_ai-0.3.0/tests/test_adapters.py +254 -0
  96. netlog_ai-0.3.0/tests/test_analyzer.py +279 -0
  97. netlog_ai-0.3.0/tests/test_classifier.py +183 -0
  98. netlog_ai-0.3.0/tests/test_classifier_gate.py +64 -0
  99. netlog_ai-0.3.0/tests/test_correlate.py +176 -0
  100. netlog_ai-0.3.0/tests/test_data_dirs.py +56 -0
  101. netlog_ai-0.3.0/tests/test_device_triage.py +207 -0
  102. netlog_ai-0.3.0/tests/test_kb_phased.py +91 -0
  103. netlog_ai-0.3.0/tests/test_kb_rca.py +97 -0
  104. netlog_ai-0.3.0/tests/test_llm_providers.py +108 -0
  105. netlog_ai-0.3.0/tests/test_llm_transports.py +222 -0
  106. netlog_ai-0.3.0/tests/test_mcp_tools.py +20 -0
  107. netlog_ai-0.3.0/tests/test_network_tool.py +120 -0
  108. netlog_ai-0.3.0/tests/test_new_features.py +230 -0
  109. netlog_ai-0.3.0/tests/test_phase1_security.py +187 -0
  110. netlog_ai-0.3.0/tests/test_sanitize.py +237 -0
  111. netlog_ai-0.3.0/tests/test_site_optimize.py +234 -0
  112. netlog_ai-0.3.0/tests/test_site_sanitize.py +61 -0
  113. netlog_ai-0.3.0/tests/test_sources.py +391 -0
  114. netlog_ai-0.3.0/tests/test_streaming_analyze.py +139 -0
  115. netlog_ai-0.3.0/tests/test_tfsm_auto.py +130 -0
  116. netlog_ai-0.3.0/tests/test_topology_infer.py +140 -0
  117. netlog_ai-0.3.0/tests/test_web_correlate_triage.py +170 -0
  118. netlog_ai-0.3.0/tests/test_web_security.py +98 -0
  119. netlog_ai-0.3.0/tests/test_webhooks.py +164 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Georgi Gaydarov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,464 @@
1
+ Metadata-Version: 2.4
2
+ Name: netlog-ai
3
+ Version: 0.3.0
4
+ Summary: AI-powered network syslog analyzer with pluggable LLM providers (local Docker Model Runner / Anthropic Claude) and lab adapters.
5
+ Author: Georgi Gaydarov
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/gesh75/netlog-ai
8
+ Project-URL: Repository, https://github.com/gesh75/netlog-ai
9
+ Project-URL: Issues, https://github.com/gesh75/netlog-ai/issues
10
+ Keywords: network,syslog,log-analysis,ai,llm,claude,frr,junos,eos,bgp,ospf
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: Intended Audience :: Telecommunications Industry
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: System :: Networking
21
+ Classifier: Topic :: System :: Networking :: Monitoring
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: flask>=3.0
26
+ Requires-Dist: flask-cors>=5.0
27
+ Requires-Dist: requests>=2.32
28
+ Requires-Dist: python-dotenv>=1.0
29
+ Requires-Dist: gunicorn>=23.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.5; extra == "dev"
34
+ Provides-Extra: mcp
35
+ Requires-Dist: mcp>=1.0; extra == "mcp"
36
+ Provides-Extra: parse
37
+ Requires-Dist: tfsm-fire>=0.1.0; extra == "parse"
38
+ Provides-Extra: all
39
+ Requires-Dist: mcp>=1.0; extra == "all"
40
+ Requires-Dist: tfsm-fire>=0.1.0; extra == "all"
41
+ Dynamic: license-file
42
+
43
+ <p align="center">
44
+ <img src="docs/assets/hero.svg" alt="netlog-ai — architecture" width="100%">
45
+ </p>
46
+
47
+ # netlog-ai
48
+
49
+ ## 📖 Live documentation
50
+
51
+ [![netlog-ai — live documentation](docs/assets/preview.png)](https://gesh75.github.io/netlog-ai/)
52
+
53
+ > 🌐 **Live:** <https://gesh75.github.io/netlog-ai/> — an animated single-page guide: architecture diagrams, data flow, tech stack, and quickstart.
54
+ >
55
+ > 🗂️ Part of the **[gesh75 documentation hub](https://gesh75.github.io/)** — all my network & AI engineering project docs in one place.
56
+
57
+
58
+ > **Network logs in. Ranked actions out.** A local, dark-themed dashboard that classifies syslog events from any vendor (Junos, Arista EOS, FRR), builds a prioritized action list, and lets an LLM write the root-cause analysis with copy-pastable CLI fixes.
59
+
60
+ [![CI](https://github.com/gesh75/netlog-ai/actions/workflows/ci.yml/badge.svg)](https://github.com/gesh75/netlog-ai/actions/workflows/ci.yml) ![Tests](https://img.shields.io/badge/tests-294%20passing-brightgreen) ![License](https://img.shields.io/badge/license-MIT-blue) ![Python](https://img.shields.io/badge/python-3.10%2B-blue) ![Stack](https://img.shields.io/badge/stack-Flask%20%2B%20vanilla%20JS-1f6feb)
61
+
62
+ > 📓 Recent changes — cross-source correlation + per-device triage (MCP tools **and** Device-tab UI) — are in [`CHANGELOG.md`](CHANGELOG.md).
63
+
64
+ ---
65
+
66
+ ## Why this exists
67
+
68
+ Most "AI for ops" tools either ship your data to a SaaS or hide what the model actually saw. **netlog-ai** runs entirely on your laptop:
69
+
70
+ - Configs and logs **never leave the host** — the LLM only sees pre-sanitized text (passwords, public IPs, SSH keys redacted before any outbound call).
71
+ - Pluggable LLM backend — **local Docker Model Runner** (Qwen, Llama) or **Anthropic Claude**. No telemetry, no API keys required for the local path.
72
+ - Every finding ships with **executable CLI**: Junos `set` lines, EOS `running-config` patches, FRR `vtysh` commands, plus a rollback block and verify steps.
73
+ - Built for **multi-vendor reality** — not a Cisco-only tool retrofitted with a chatbot.
74
+
75
+ If you have ever watched an AI dashboard hallucinate a "root cause" with no actionable next step, this is the antidote.
76
+
77
+ ## What's new — connectors + MCP server
78
+
79
+ netlog-ai now ships a **pluggable connector layer** so it doesn't just analyze
80
+ pasted logs — it pulls from any common log source (full guide:
81
+ [docs/CONNECTORS.md](docs/CONNECTORS.md)).
82
+
83
+ | Connector | Source | One-line setup |
84
+ |------------|---------------------|----------------|
85
+ | `kibana` | Elasticsearch / Kibana | `NETLOG_SOURCE_kibana_URL=… NETLOG_SOURCE_kibana_API_TOKEN=…` |
86
+ | `splunk` | Splunk REST search | `NETLOG_SOURCE_splunk_URL=… NETLOG_SOURCE_splunk_API_TOKEN=…` |
87
+ | `loki` | Grafana Loki | `NETLOG_SOURCE_loki_URL=… NETLOG_SOURCE_loki_API_TOKEN=…` |
88
+ | `syslog` | UDP/TCP listener | Zero-config — point any device at port 5514 |
89
+ | `librenms` | LibreNMS REST | `NETLOG_SOURCE_librenms_URL=… NETLOG_SOURCE_librenms_API_TOKEN=…` |
90
+
91
+ And the analyzer engine is now **agent-callable** via a built-in MCP server:
92
+
93
+ ```bash
94
+ pip install 'netlog-ai[mcp]'
95
+ netlog-ai mcp # stdio transport — wire into Claude Code, Cursor, Continue
96
+ ```
97
+
98
+ Tools exposed: `list_sources`, `add_source`, `fetch_logs`, `search_logs`,
99
+ `analyze_logs`, `get_top_offenders`, `correlate_sources`, `analyze_device`,
100
+ `list_sites`, `analyze_site`, plus healthcheck + connector inventory. See
101
+ [docs/CONNECTORS.md](docs/CONNECTORS.md) for the full reference.
102
+
103
+ ## Features
104
+
105
+ | | |
106
+ |---|---|
107
+ | 🔌 **Pluggable sources** | Kibana, Splunk, Loki, LibreNMS, syslog UDP/TCP — one Protocol, one config dict, hot-pluggable |
108
+ | 🤖 **MCP server mode** | Claude Code / Cursor / Continue can call the analyzer directly as agent tools |
109
+ | 🔗 **Cross-source correlation** | **Device tab** → *Correlate Sources*: scans every registered source and tags each host `confirmed` (flagged by ≥ 2 sources) or `suspected` (1) in a sortable, severity-coded table |
110
+ | 🔬 **Per-device triage** | **Device tab** → *Triage Device*: one host's verdict + 0–100 health score, severity histogram, top processes, and deduped error patterns in a single panel |
111
+ | 🔎 **Classify** | 50+ regex patterns across Junos, EOS, FRR, IOS, RFC-3164/5424 |
112
+ | 🧭 **Prioritize** | Deduped action items, ranked by severity × count, recovery events excluded |
113
+ | 🧠 **Deep analyze** | Top-N items get an LLM-written root-cause + risk + remediation playbook |
114
+ | 🛡️ **Sanitize-first** | Every config/log payload is scrubbed (`$6$`, `$9$`, SSH keys, SNMP, RADIUS, public IPs) before LLM call |
115
+ | 📈 **Health score** | Weighted formula → 0–100 + A/B/C/D/F + sparkline trend |
116
+ | 🗺️ **Topology (multi-layer)** | Cytoscape.js + ELK layered renderer — PHYSICAL · BGP · OSPF · VXLAN as separate views over the same fabric, attributes (AS / RID / VTEP) on nodes, speed/area on edges |
117
+ | 🤖 **Copilot** | Ask free-form questions, grounded in the selected site's configs |
118
+ | 🔍 **Post-mortem search** | Grep a pattern across every device in a site in one shot |
119
+ | 📄 **Report export** | Markdown / HTML / CSV / PDF + site documentation in 3 formats |
120
+ | ⌨️ **Keyboard-first** | `1/2/3` to switch tabs, `⌘/Ctrl+↵` to run, full ARIA + `:focus-visible` |
121
+ | 📱 **PWA-ready** | Installable on iOS/Android home screen; theme-color tinted dark |
122
+
123
+ ## Quick start
124
+
125
+ ```bash
126
+ git clone https://github.com/gesh75/netlog-ai.git
127
+ cd netlog-ai
128
+ python3 -m venv .venv && source .venv/bin/activate
129
+ pip install -e ".[dev]"
130
+ cp .env.example .env
131
+
132
+ # Run the UI
133
+ ai-log-analyzer serve
134
+ # → http://localhost:6060
135
+ ```
136
+
137
+ Open the UI, pick a bundled site (`lab-alpha` or `lab-bravo`) under the **🌐 Site** tab, and hit **Analyze Whole Site**. Without an LLM key the rule-based knowledge base produces the analysis; with `ANTHROPIC_API_KEY` set, Claude writes a richer narrative.
138
+
139
+ ### CLI
140
+
141
+ ```bash
142
+ # List running FRR-lab containers (optional)
143
+ ai-log-analyzer containers
144
+
145
+ # Analyze a stream from any source
146
+ ai-log-analyzer analyze --frr r1 r2 --no-llm | jq .score
147
+ ai-log-analyzer analyze --file /var/log/syslog
148
+ docker logs my-router 2>&1 | ai-log-analyzer analyze --stdin
149
+
150
+ # Run the full test suite
151
+ pytest --cov=src --cov-report=term-missing
152
+ ```
153
+
154
+ ## Configure the LLM
155
+
156
+ Three providers, switchable at runtime from the UI dropdown — or via env / API:
157
+
158
+ | Mode | Order |
159
+ |---------------|-------|
160
+ | `local` | Local Docker Model Runner → falls back to Claude if `ANTHROPIC_API_KEY` is set |
161
+ | `claude` | Claude first → falls back to local |
162
+ | `claude-only` | Claude only, no fallback |
163
+
164
+ ```bash
165
+ LLM_PROVIDER=claude ANTHROPIC_API_KEY=sk-ant-... ai-log-analyzer serve
166
+
167
+ # Switch at runtime
168
+ curl -X POST localhost:6060/api/llm/provider \
169
+ -H 'content-type: application/json' \
170
+ -d '{"provider": "claude"}'
171
+
172
+ # Disable LLM entirely (rule-based KB only)
173
+ curl -X POST localhost:6060/api/llm/toggle \
174
+ -H 'content-type: application/json' \
175
+ -d '{"enabled": false}'
176
+ ```
177
+
178
+ ### Local LLM via Docker Model Runner
179
+
180
+ ```bash
181
+ docker model pull ai/qwen3 # 8B, ~5GB, recommended
182
+ # or
183
+ docker model pull ai/llama3.2 # 3B, ~2GB, faster
184
+ docker model list # confirm
185
+ ```
186
+
187
+ Auto-detected via TCP `:12434` first, then Unix sockets (`~/Library/Containers/com.docker.docker/Data/inference.sock` on macOS, `/run/docker-model-runner/inference.sock` on Linux).
188
+
189
+ ## Bundled demo sites
190
+
191
+ Four **fully synthetic** site bundles ship in `sites/` so you can exercise every feature out of the box. These are not derived from any real network — they're hand-built configs designed to demonstrate the analyzer's full feature set.
192
+
193
+ | Site | Devices | Vendors | What it shows |
194
+ |------|---------|---------|----|
195
+ | `lab-alpha` | 5 (2 SRX HA pair + 1 MX router + 2 EOS switches) | Junos + EOS | Cross-vendor edge, chassis-cluster, MLAG |
196
+ | `lab-bravo` | 6 (1 SRX firewall + 2 MX spines + 3 EX leaves) | Junos | Spine/leaf fabric, iBGP full mesh |
197
+ | `clab-clos-evpn` | 9 (3 spines + 6 leaves) | **Nokia SRL + Arista cEOS + FRR** | Mixed-vendor Clos EVPN-VXLAN fabric, L2/L3 VNIs, route reflectors |
198
+ | `dcn-lab` | 10 (5 cores + 3 edges + 2 dists) | FRR | Multi-POP backbone (DE-FRA · UK-LON · NL-AMS · US-NYC), eBGP + OSPF area 0 |
199
+
200
+ Each bundle includes intentional configuration gaps (missing BFD, no LLDP on some access switches, IoT VLAN without an L3 interface) so the analyzer's deep-analysis pipeline produces concrete, actionable findings.
201
+
202
+ ## Multi-layer topology
203
+
204
+ The topology view stacks four protocol overlays over the same fabric — each with the data that's actually relevant to that protocol. Drag a node to pin it; positions persist across layer toggles (BGP, OSPF, VXLAN all follow the L1/L3 layout). Reset Layout reruns ELK from scratch. Full reference: [docs/TOPOLOGY.md](docs/TOPOLOGY.md).
205
+
206
+ - **PHYSICAL** — node label: `hostname`; edge: `Et1` · `eth3` · `et1/3` at each end, link speed (e.g. `10G`, `100G`) at midpoint parallel to the line; IPs revealed via the **Show IPs** toggle. Solid blue.
207
+ - **BGP** — node label: `hostname · AS65001`; edge: `EBGP` / `IBGP` tag only (AS already on each node). Purple; eBGP solid w/ arrow, iBGP dashed.
208
+ - **OSPF** — node label: `hostname · RID 10.0.0.1`; edge: `area 0` (per-adjacency). Green dashed.
209
+ - **VXLAN** — node label: `hostname · VTEP 10.255.1.4`; edge: `VNI 10010,10020,10030` (only where VNIs differ). Coral dashed.
210
+
211
+ When a layer has no edges anywhere on the site (e.g. OSPF on a pure-BGP fabric), the view shows the devices as a list with an explicit empty-state banner instead of silently falling back.
212
+
213
+ ### Speed inference
214
+
215
+ Link speed is resolved in this order:
216
+
217
+ 1. **Explicit config directive** — EOS/IOS `speed 100g`, SRL `port-speed 100G`, Junos `gigether-options speed 100g`.
218
+ 2. **Interface-name convention** — `HundredGigE*` → 100G, `TenGig*` / `xe-*` → 10G, `GigabitEthernet*` / `ge-*` → 1G, `et-*` → 40G, `mge-*` → 100G. Skipped for ambiguous names like `Ethernet1` / `eth1`.
219
+ 3. **Site default** — `manifest.json` may declare `"default_link_speed": "10G"` (used by all four bundled sites for the docker veth links).
220
+
221
+ The link rate displayed is `min(src_speed, dst_speed)` — mismatches are surfaced so you can act on them.
222
+
223
+ ### Multi-vendor parsing coverage
224
+
225
+ The topology engine ingests configs from every shipped sample:
226
+
227
+ - **Junos** — `set interfaces ... family inet address ...`, `gigether-options speed`, OSPF area, chassis-cluster, BGP `local-as` / `peer-as`.
228
+ - **Arista EOS** — `interface EthernetN { ip address ... speed ... }`, `router bgp`, `vxlan source-interface`, OSPF process.
229
+ - **Nokia SRL** — `interface ethernet-1/X { subinterface 0 { ipv4 { address ... } } }`, `system0` loopback as implicit VTEP when `afi-safi evpn` is signaled.
230
+ - **FRR** — Quagga-style block syntax, `interface lo` as implicit VTEP when `advertise-all-vni` is present, `vrf X { vni Y }` for L3 VNIs.
231
+
232
+ ### Auto-detection fallback parser (optional)
233
+
234
+ For arbitrary `show` output where the platform isn't known up-front, install the `parse`
235
+ extra to enable [tfsm_fire](https://github.com/scottpeterman/tfsm_fire) — it scores every
236
+ TextFSM template in a 700-template DB and returns the best match:
237
+
238
+ ```bash
239
+ pip install -e ".[parse]"
240
+ ```
241
+
242
+ ```python
243
+ from ai_log_analyzer.adapters.tfsm_auto import auto_parse
244
+ result = auto_parse(raw_cli_output, filter_hint="bgp_summary", min_score=40.0)
245
+ ```
246
+
247
+ <p align="center">
248
+ <img src="demo/tfsm_demo.gif" alt="tfsm_fire auto-detect demo — paste Cisco LLDP, IOS show version, FRR BGP summary; each picks the right template and scores 78–89/100" width="100%">
249
+ </p>
250
+
251
+ See [`docs/TFSM_AUTO_PARSER.md`](docs/TFSM_AUTO_PARSER.md) for the API, scoring guide,
252
+ and filter-hint reference. The full WebM video is [`demo/tfsm_demo.webm`](demo/tfsm_demo.webm)
253
+ (19s, 311 KB) and the recording is reproducible via [`demo/record_tfsm_demo.sh`](demo/record_tfsm_demo.sh).
254
+
255
+ ## DCN AI port — correlation, triage, and expanded KB (2026-06-02)
256
+
257
+ Four capabilities backfilled from the closed-source DCN AI Intelligence Center:
258
+
259
+ - **Multi-source correlation** — `correlate_sources` MCP tool classifies events from every registered source and tags each device `confirmed` (seen in ≥ 2 independent sources) or `suspected` (1 source only). Eliminates single-source noise before escalation.
260
+ - **Richer RCA KB** — every KB entry (`bgp`, `ospf`, `interface`, `lag`, `hardware`, `compliance`, `security`, `system`) now carries a structured `rca` block: numbered root-cause list, risk sentence, ordered resolution steps, and copy-pastable Junos / EOS CLI commands. Two new categories added: `vpn` (IKE/IPsec failure) and `redundancy` (VRRP/HSRP failover); `hardware` extended with `fpc` (line-card errors) and `chassis` (PSU/fan/temperature alarms).
261
+ - **Expanded classifier patterns** — `inetd|xinetd|ftpd` added as a low-severity `system` pattern, positioned after all high-severity patterns so first-match-wins is preserved. Three new unit tests confirm matching and priority ordering.
262
+ - **Per-device triage** — `analyze_device` MCP tool pulls one hostname's events from all sources, returns a severity histogram, process breakdown, frequency-deduped error patterns, a KB verdict (e.g. `ROUTING`, `HARDWARE`), and a 0–100 health score.
263
+
264
+ Full details and usage examples: [`docs/PORTED_FROM_DCN_AI.md`](docs/PORTED_FROM_DCN_AI.md).
265
+
266
+ ## LOGS pipeline hardening (2026-05-27)
267
+
268
+ Three follow-up fixes to the LOGS tab: (1) the Executive Summary LLM call now
269
+ receives an `ALLOWED_HOSTNAMES` anchor and a post-validation scrubber so it
270
+ can no longer emit textbook placeholders like `R1-R3` or `SW1-SW2`,
271
+ (2) `classifier.strip_ansi` removes ANSI/VT100 escape codes from every event
272
+ at the LogEvent → ClassifiedEvent boundary (no more `[0;32m OK [0m` garbage
273
+ in the UI), and (3) `containerlab-multivendor/topologies/clos-evpn.clab.yml`
274
+ now caps cEOS / SRL / linux containers via the `kinds:` block so a runaway
275
+ control plane can't OOM-cascade the host. Full details and live validation
276
+ data in [`docs/LOGS_PIPELINE_HARDENING.md`](docs/LOGS_PIPELINE_HARDENING.md).
277
+
278
+ ## Site-Wide Optimization — split scoring + hostname anchoring
279
+
280
+ The Site-Wide Strategic Optimization widget now returns **two independent scores** instead of a
281
+ single ambiguous "maturity" number: `fabric_design_score` (routing, HA, lifecycle, BGP tuning,
282
+ overlay) and `operational_readiness_score` (NTP, syslog, AAA, SNMPv3, monitoring, compliance).
283
+ This separates architectural gaps from day-2 hygiene so an engineer knows whether to plan a
284
+ hardware change or just push config. The LLM prompt also injects an explicit `ALLOWED_HOSTNAMES`
285
+ inventory and post-validation drops any `config_changes` key not in that list — no more invented
286
+ `CR-01` / `BR-01` placeholders. Full design and validation in
287
+ [`docs/SCORING_SPLIT.md`](docs/SCORING_SPLIT.md).
288
+
289
+ ## 🏛️ Architecture
290
+
291
+ The analyzer core sits between the operators who drive it (browser, CLI, or AI agents over MCP), the log
292
+ platforms it pulls from, the LLM runtimes it can call, and the network devices that produce the logs and
293
+ configs. **Every outbound LLM call is gated by the sanitizer.** Full diagram set —
294
+ container map, runtime sequence, data-flow pipeline, provider-fallback state machine, ER model, and module
295
+ map — lives in **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**.
296
+
297
+ ```mermaid
298
+ flowchart TB
299
+ OP["NOC Operator - browser and CLI"]
300
+ AGENT["AI Agents - Claude Code and Cursor"]
301
+ NET(["netlog-ai analyzer core"])
302
+ LOGS["Log Platforms - Kibana, Splunk, Loki, LibreNMS, syslog"]
303
+ LLM["LLM Runtimes - Ollama, Docker Model Runner, Claude"]
304
+ DEV["Network Devices - Junos, EOS, SR Linux, FRR"]
305
+
306
+ OP -->|HTTP and JSON| NET
307
+ AGENT -->|MCP stdio| NET
308
+ LOGS -->|fetch logs| NET
309
+ DEV -.->|syslog and configs| LOGS
310
+ DEV -.->|docker logs and running-config| NET
311
+ NET -->|sanitized prompt| LLM
312
+ LLM -->|5-phase playbook JSON| NET
313
+ NET -->|ranked actions and CLI fixes| OP
314
+ NET -->|tool results| AGENT
315
+
316
+ classDef sys fill:#7c3aed,stroke:#c4b5fd,color:#fff,stroke-width:2px
317
+ classDef person fill:#0ea5e9,stroke:#7dd3fc,color:#fff
318
+ classDef ext fill:#475569,stroke:#94a3b8,color:#fff
319
+ classDef ai fill:#a16207,stroke:#fbbf24,color:#fff
320
+
321
+ class NET sys
322
+ class OP,AGENT person
323
+ class LOGS,DEV ext
324
+ class LLM ai
325
+ ```
326
+
327
+ <p align="center">
328
+ <img src="docs/architecture.svg" alt="netlog-ai animated architecture diagram — Sources → Adapters → Pipeline → Intelligence → Outputs" width="100%">
329
+ </p>
330
+
331
+ > **Flow:** any source (Kibana, Splunk, Loki, syslog, LibreNMS, FRR, file) → `SourceManager` adapter → **sanitize → classify → prioritize → deep-analyze → score** → outputs (Web UI, MCP server, reports, topology, copy-pastable CLI). Every byte that touches the LLM is scrubbed first.
332
+
333
+ <details>
334
+ <summary>ASCII fallback (for terminals / RSS readers)</summary>
335
+
336
+ ```
337
+ ┌────────────────────────────────────────────────────────────────────┐
338
+ │ Browser (vanilla JS, no build) │
339
+ │ index.html + app.js │
340
+ └──────────────────────────────┬─────────────────────────────────────┘
341
+ │ HTTP / JSON
342
+ ┌──────────────────────────────▼─────────────────────────────────────┐
343
+ │ Flask (port 6060) │
344
+ │ │
345
+ │ Adapters → Classifier → Action Items → Health Score → AI Summary │
346
+ │ │ │ │ │ │ │
347
+ │ ▼ ▼ ▼ ▼ ▼ │
348
+ │ FRR docker 50+ regex dedupe by weighted formula LLM or │
349
+ │ File patterns (sev, desc) → A/B/C/D/F KB │
350
+ │ Stdin/raw │
351
+ └─────────────────────────────────────────────────────────────────────┘
352
+ ```
353
+
354
+ </details>
355
+
356
+ ### Module layout
357
+
358
+ ```
359
+ src/ai_log_analyzer/
360
+ classifier.py 50+ regex patterns + severity/category lookup
361
+ kb.py Rule-based deep-analysis KB (fallback when LLM is off)
362
+ llm.py Docker Model Runner (TCP + UDS) + Anthropic Claude
363
+ analyzer.py End-to-end pipeline: classify → actions → score → summary
364
+ copilot.py Site-context Q&A with secret-sanitized prompts
365
+ diff.py Config-diff explainer
366
+ sanitize.py Pre-LLM redaction (passwords, public IPs, SSH keys)
367
+ site_optimize.py Site-wide cross-device gap finder + maturity score
368
+ site_diagram.py Mermaid + Graphviz DOT topology renderer
369
+ topology.py Build topology graph from device list
370
+ topology_infer.py Multi-signal edge inference (BGP, MLAG, descriptions, subnets)
371
+ reports.py MD / HTML / CSV / PDF report exporters
372
+ adapters/
373
+ frr.py docker logs <container> → LogEvent stream
374
+ file.py RFC3164 / RFC5424 / Junos / freeform parser
375
+ web/
376
+ app.py Flask routes + create_app()
377
+ static/ index.html + app.js (no build step)
378
+ cli.py `ai-log-analyzer serve | analyze | containers`
379
+ ```
380
+
381
+ ## API
382
+
383
+ | Method | Endpoint | Description |
384
+ |--------|----------|-------------|
385
+ | `GET` | `/api/health` | Liveness check |
386
+ | `GET` | `/api/llm/status` | Provider + availability for each provider |
387
+ | `POST` | `/api/llm/provider` | `{"provider": "local"\|"claude"\|"claude-only"}` |
388
+ | `POST` | `/api/llm/toggle` | `{"enabled": true\|false}` |
389
+ | `GET` | `/api/lab/containers` | Running FRR-lab container names |
390
+ | `GET` | `/api/sites` | List bundled site bundles |
391
+ | `POST` | `/api/analyze` | Full pipeline — see request shapes below |
392
+ | `POST` | `/api/optimize` | Device-level config audit + patches |
393
+ | `POST` | `/api/optimize/site` | Cross-device site analysis |
394
+ | `POST` | `/api/optimize/site-wide/<id>` | Strategic maturity scoring + phased roadmap |
395
+ | `POST` | `/api/correlate` | Cross-source correlation — confirmed (≥ 2 sources) vs suspected (1) devices |
396
+ | `POST` | `/api/triage` | Per-device triage — verdict, health score, severity histogram, top processes, patterns |
397
+ | `GET` | `/api/topology/<id>` | Topology graph (JSON / Mermaid / DOT) |
398
+ | `GET` | `/api/compliance/<id>` | Compliance rules pass/fail |
399
+ | `POST` | `/api/copilot` | Free-form Q&A grounded in selected site config |
400
+ | `POST` | `/api/postmortem/<id>` | Pattern search across all devices in a site |
401
+
402
+ ### `/api/analyze` request
403
+
404
+ ```json
405
+ {
406
+ "source": "frr",
407
+ "containers": ["r1", "r2"],
408
+ "tail": 500,
409
+ "use_llm": true
410
+ }
411
+ ```
412
+
413
+ ```json
414
+ {
415
+ "source": "raw",
416
+ "hostname": "test-router",
417
+ "text": "Mar 3 12:00:01 r1 rpd[1234]: bgp peer 10.0.0.1 down\n..."
418
+ }
419
+ ```
420
+
421
+ ## Security defaults
422
+
423
+ - **Sanitize-before-LLM** — every config/log payload is run through `sanitize.py` before any outbound call. Coverage:
424
+ - Linux/BSD shadow hashes (`$1$`, `$5$`, `$6$`)
425
+ - Junos `$9$` proprietary encoding
426
+ - SSH keys (RSA / Ed25519 / ECDSA / DSS)
427
+ - SNMP communities, RADIUS / TACACS+ keys
428
+ - IPsec pre-shared keys
429
+ - Public IPv4 addresses (mapped to RFC-5737 doc prefixes for the LLM context)
430
+ - **Localhost bind by default** — set `ANALYZER_HOST=0.0.0.0` to expose; the server warns if you bind publicly without an `API_TOKEN`.
431
+ - **API-token gate** — set `API_TOKEN=...` to require `Authorization: Bearer ...` on every POST.
432
+ - **CORS allow-list** — `ANALYZER_CORS_ORIGINS=https://a.com,https://b.com`.
433
+ - **No telemetry** — outbound calls go only to (a) the LLM provider you select and (b) the local Docker socket if you analyze FRR-lab containers.
434
+
435
+ ## Tested & accessible
436
+
437
+ - **294 unit + integration tests** (pytest)
438
+ - Frontend audited across 8 review rounds:
439
+ - WCAG-AA: `:focus-visible` rings, `aria-live` regions, `role=tablist/tab/tabpanel`, skip-to-main link, `prefers-reduced-motion` fallback
440
+ - Responsive ≤ 1100px, PWA-ready (`theme-color`, `mobile-web-app-capable`, SVG favicon)
441
+ - Performance: `content-visibility: auto` panel culling, `contain: layout`, deferred scripts, preconnect hint
442
+ - Keyboard: `1/2/3` to switch tabs, `⌘/Ctrl+↵` to run, semantic `<kbd>` hints throughout
443
+ - Print stylesheet for hardcopy reports
444
+
445
+ ## Roadmap
446
+
447
+ - [ ] Multi-site comparison view (delta between two sites)
448
+ - [ ] Real-time tail mode (websocket stream of new events)
449
+ - [x] Slack / generic-JSON alert webhooks per severity threshold (`AI_LOG_ANALYZER_WEBHOOK_URL` — see `.env.example`)
450
+ - [ ] More vendor adapters (Nokia SR Linux, Cisco IOS-XE, Cumulus NCLU)
451
+ - [ ] Snapshot / replay analysis runs for regression testing
452
+ - [ ] Custom rule editor in the UI
453
+
454
+ ## Contributing
455
+
456
+ PRs welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the short version. The whole stack is one `pip install -e ".[dev]" && pytest` away.
457
+
458
+ ## License
459
+
460
+ MIT — see [LICENSE](./LICENSE).
461
+
462
+ ---
463
+
464
+ Built by [@gesh75](https://github.com/gesh75) as part of a multi-vendor network automation toolkit.