Repository navigation
feat: add native NetFlow monitoring with Lucene search and Sankey #3347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
valerypetrov
wants to merge
11
commits into
hyperdxio:main
Choose a base branch
from
valerypetrov:agent/netflow-monitoring
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+7,629
−164
Open
Changes from 4 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
94e034f
feat: add native NetFlow monitoring and Sankey visualization
valerypetrov 7efb567
docs: add NetFlow demo feature screenshots
valerypetrov 9053fcb
fix: address NetFlow review regressions
valerypetrov dee8414
fix: complete NetFlow alerts and preserve search drafts
valerypetrov a476fa9
fix: address remaining NetFlow review findings
valerypetrov bbd3e30
fix: complete NetFlow search hydration and bucket rates
valerypetrov adc1e10
test: consolidate NetFlow regression coverage
valerypetrov 7ebbb8d
fix: preserve NetFlow source settings and filter behavior
valerypetrov d7b677c
fix: match NetFlow protocol names and drop the records eslint-disable
3b86faf
fix: keep raw protocol numbers in NetFlow bare-term search
219da28
fix: accept protocol names in the NetFlow protocol filter
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| --- | ||
| '@hyperdx/app': minor | ||
| '@hyperdx/api': minor | ||
| '@hyperdx/common-utils': minor | ||
| --- | ||
|
|
||
| Add native NetFlow sources and monitoring with configurable column mappings, | ||
| Akvorado schema detection, sampling-aware traffic charts, top talkers, exporter | ||
| and interface breakdowns, and flow details. NetFlow tables also support Search | ||
| and custom charts. | ||
|
|
||
| Support Lucene search with field autocomplete on the NetFlow page, combining | ||
| search queries with quick filters across charts and flow records. | ||
|
|
||
| Add clickable include/exclude filters to flow IPs, protocols, exporters, and | ||
| interfaces, with removable selections preserved in the URL. | ||
|
|
||
| Show table column suggestions when focusing an empty NetFlow search input. | ||
|
|
||
| Size time-chart Y axes to their formatted labels so rate units do not wrap or | ||
| get clipped. | ||
|
|
||
| Avoid sending API proxy headers when querying ClickHouse directly in local mode. | ||
|
|
||
| Add a Sankey visualization with ordered table dimensions, sampling-adjusted path | ||
| weights, average bit rates, configurable path limits, and clickable shared | ||
| filters. Include interface classifications in the local demo data. | ||
|
|
||
| Recover from invalid time ranges without crashing, clear source-specific click | ||
| filters when switching sources, and keep chart geometry aligned with automatic | ||
| axis widths. | ||
|
|
||
| Preserve NetFlow mappings through MCP source tools, ignore stale source inference, | ||
| share filter keys across visualizations, retain quoted columns, and make explicit | ||
| include/exclude actions idempotent. Format flow times using user preferences. | ||
|
|
||
| Support NetFlow saved-search alerts with default aliases, previews, and flow | ||
| samples in notifications. Keep unfinished search fields pending when applying | ||
| click filters, and display the configured record limit. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| # NetFlow monitoring | ||
|
|
||
| The NetFlow section queries a configured ClickHouse table through HyperDX's | ||
| existing connections and source mappings. An Akvorado `flows` table can be used | ||
| directly. HyperDX does not collect UDP NetFlow, IPFIX, or sFlow packets: keep | ||
| Akvorado or another collector responsible for decoding and ingestion. | ||
|
|
||
| ## Local demo | ||
|
|
||
| Use Python 3, the repository's Node/Yarn dependencies, and a local ClickHouse | ||
| server with HTTP access and browser CORS enabled. The demo uses | ||
| `http://127.0.0.1:8123`, user `default`, and an empty password. Override these | ||
| with `CLICKHOUSE_URL`, `CLICKHOUSE_USER`, and `CLICKHOUSE_PASSWORD` as needed. | ||
| Local mode sends these credentials to the browser, so use a local development | ||
| account. | ||
|
|
||
| From the repository root: | ||
|
|
||
| ```sh | ||
| yarn setup | ||
| yarn build:common-utils | ||
| python3 scripts/netflow-seed.py | ||
| python3 scripts/netflow-dev.py | ||
| ``` | ||
|
|
||
| The launcher prints the URL, normally `http://127.0.0.1:3000/netflow`, and uses | ||
| port 3001 if 3000 is occupied. It supplies the connection and native NetFlow | ||
| source through HyperDX's supported default configuration environment variables. | ||
| No MongoDB, API server, account registration, or browser storage edits are | ||
| needed for this local demo. A fresh browser session uses these defaults; | ||
| previously saved local connections and sources take precedence. | ||
|
|
||
| Choose the last two hours to see the whole fixture, including its TCP traffic | ||
| burst. Re-run the seeder to move the data to the current time. The seeder | ||
| replaces only its own `netflow_demo.flows` table, checking its ownership comment | ||
| first. It refuses remote endpoints and does not modify other databases or | ||
| tables. Refreshes do not accumulate duplicate records. A failed insert can leave | ||
| this disposable fixture table empty; re-run the seeder to restore it. | ||
|
|
||
| For a fixed, reproducible time range: | ||
|
|
||
| ```sh | ||
| python3 scripts/netflow-seed.py --end 2026-10-09T18:34:38Z | ||
| ``` | ||
|
|
||
| This produces the UTC interval `[2026-10-09 16:34:38, 2026-10-09 18:34:38)`. The | ||
| last stored timestamp is `18:34:37`; use that absolute range when inspecting | ||
| this fixed fixture after its timestamps leave the relative time window. | ||
|
|
||
| ## Data and sampling | ||
|
|
||
| The data is deterministic synthetic traffic generated locally, not a packet | ||
| capture or customer traffic. The schema follows | ||
| [Akvorado's flow schema](https://github.com/akvorado/akvorado/blob/main/common/schema/definition.go), | ||
| using documentation IP ranges and private AS numbers. The fixture includes | ||
| 14,400 records across three exporters, TCP, UDP, ICMP, ICMPv6, inbound and | ||
| outbound interfaces, IPv4-mapped IPv6 addresses, and native IPv6 addresses. | ||
| Interface classification columns (`InIfConnectivity`, `OutIfConnectivity`, | ||
| `InIfProvider`, `OutIfProvider`) contain deterministic transit, IX, and PNI | ||
| classifications with synthetic provider names tied to each exporter. As with | ||
| Akvorado's default classifier, internal interfaces leave these fields empty. The | ||
| seeder adds missing classification columns only after confirming ownership of | ||
| the demo table; existing counters and record counts stay unchanged. Interface | ||
| speeds are stored in Mbps, as in Akvorado. `ExporterAddress` uses plain `IPv6` | ||
| to work without ClickHouse's optional low-cardinality IPv6 setting. | ||
|
|
||
| `Bytes` and `Packets` hold observed counters. `SamplingRate` holds the expansion | ||
| factor (1, 100, or 1,000). Traffic estimates are `sum(Bytes * SamplingRate)` and | ||
| `sum(Packets * SamplingRate)`, matching | ||
| [Akvorado's aggregation](https://github.com/akvorado/akvorado/blob/main/console/widgets.go). | ||
| Multiply estimated bytes by eight and divide by the requested duration in | ||
| seconds for bits per second. The record count is the number of stored records, | ||
| not an estimate of distinct connections or sampling-expanded flows. | ||
|
|
||
| The seeder checks actual ClickHouse query results against generated totals: | ||
|
|
||
| | Measurement | Expected value | | ||
| | ------------------- | ----------------: | | ||
| | Records | 14,400 | | ||
| | Exporters | 3 | | ||
| | Protocols | 4 | | ||
| | Native IPv6 records | 2,572 | | ||
| | Observed bytes | 7,572,836,640 | | ||
| | Observed packets | 9,162,160 | | ||
| | Estimated bytes | 2,776,744,315,920 | | ||
| | Estimated packets | 3,359,797,180 | | ||
|
|
||
| ## Source configuration | ||
|
|
||
| The NetFlow search bar uses the same Lucene syntax, field autocomplete, query | ||
| history, and syntax reference as log Search. Focus the search bar to see table | ||
| columns; type a prefix to narrow them, then click a suggestion or use the arrow | ||
| keys and Enter/Tab. After a column and colon, matching values are suggested. | ||
| Press Enter or Run to apply the query to all charts and flow records. Queries | ||
| combine with the exporter, protocol, and address filters using AND; Clear | ||
| filters resets both the search and quick filters. The query and selected | ||
| language are saved in the URL. The shared language selector also supports SQL | ||
| WHERE expressions. | ||
|
|
||
| Click an IP address, protocol, exporter, or interface in a breakdown chart, flow | ||
| row, or flow details to **Include** or **Exclude** it. These actions apply | ||
| immediately while preserving the search query and time range. Selected values | ||
| appear as removable filters and survive URL sharing and reloads. Multiple | ||
| included values for the same field use OR; different fields and exclusions use | ||
| AND. Clear filters also removes these selections. | ||
|
|
||
| Use your table's actual field names, for example with the Akvorado schema: | ||
|
|
||
| ```text | ||
| Proto:6 AND DstPort:443 | ||
| ExporterName:edge* AND Bytes:[1000 TO 100000] | ||
| (DstPort:80 OR DstPort:443) AND NOT Proto:17 | ||
| ``` | ||
|
|
||
| In the source editor, select NetFlow, a ClickHouse connection, and the desired | ||
| database/table. Use these Akvorado mappings: | ||
|
|
||
| | Source setting | Column/expression | | ||
| | ---------------------------- | ------------------------ | | ||
| | Timestamp | `TimeReceived` | | ||
| | Bytes / packets | `Bytes` / `Packets` | | ||
| | Sampling rate | `SamplingRate` | | ||
| | Source / destination address | `SrcAddr` / `DstAddr` | | ||
| | Source / destination port | `SrcPort` / `DstPort` | | ||
| | Protocol | `Proto` | | ||
| | Exporter | `ExporterName` | | ||
| | Input / output interface | `InIfName` / `OutIfName` | | ||
|
|
||
| For already sampling-adjusted counters, omit the sampling-rate mapping to avoid | ||
| expanding the counters twice. Full deployments persist the source through the | ||
| existing authenticated source API and MongoDB model. | ||
|
|
||
| ## Sankey visualization | ||
|
|
||
| Select **Sankey** in the NetFlow visualization selector to explore traffic paths. | ||
| Choose two to five dimensions in left-to-right order from the source mappings or | ||
| scalar table columns. Akvorado tables default to `SrcAS` → `InIfConnectivity` → | ||
| `InIfProvider` → exporter when those columns are available. | ||
|
|
||
| Link widths represent sampling-adjusted bytes for the top 10, 20, or 50 paths. | ||
| The table and tooltips show transferred bytes and average bit rate over the | ||
| selected time range. Paths outside the limit are omitted from the diagram. | ||
| Click a node or table value to include or exclude it using the shared filters; | ||
| Lucene search, quick filters, and the time range also apply to this view. | ||
| The visualization, ordered dimensions, and path limit are saved in the URL. | ||
|
|
||
| ## Query verification | ||
|
|
||
| After building common-utils and seeding, run the real chart configurations | ||
| against local ClickHouse: | ||
|
|
||
| ```sh | ||
| node node_modules/tsx/dist/cli.mjs scripts/netflow-query-check.ts | ||
| ``` | ||
|
|
||
| This checks overview values, time series, breakdowns, the flow table, IPv4/IPv6 | ||
| filters, protocol filtering, and safe handling of SQL syntax in filter values. | ||
| The seeder also verifies counts and sampled totals on every run. | ||
|
|
||
| With the local app running and freshly seeded data, verify the browser workflow: | ||
|
|
||
| ```sh | ||
| yarn playwright install chromium | ||
| node scripts/netflow-browser-check.mjs | ||
| node scripts/netflow-click-browser-check.mjs | ||
| node node_modules/tsx/dist/cli.mjs scripts/netflow-click-query-check.ts | ||
| node node_modules/tsx/dist/cli.mjs scripts/netflow-sankey-query-check.ts | ||
| node scripts/netflow-sankey-browser-check.mjs | ||
| ``` | ||
|
|
||
| This checks charts, filters, sampled flow details, refresh, source creation and | ||
| persistence, and the shared Search page. Screenshots are saved under | ||
| `packages/app/test-results/netflow/`. Set `NETFLOW_APP_URL` if the app uses a | ||
| different local port. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.