Skip to content

feat: add netflow-mixin #1452

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

Merged
merged 2 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions netflow-mixin/.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
exclusions:
target-instance-rule:
reason: "Instance based filtering does not make sense here. Using device_name as reported by ktranslate instead"
template-instance-rule:
reason: "Instance based filtering does not make sense here. Using device_name as reported by ktranslate instead"
panel-datasource-rule:
reason: "newer grafonnet versions use -- Mixed -- data sources and specify the template at the query level"
panel-title-description-rule:
reason: "no title on purpose"
entries:
- id: 2
- id: 15
- id: 17
target-job-rule:
reason: "Status panel queries require exact match and not regex match"
entries:
- panel: "Metrics"
- panel: "Latest metrics received"
- panel: "Logs"
- panel: "Latest logs received"
- panel: "Collector logs"
panel-no-targets-rule:
reason: "Fixed static value - no target required"
entries:
- panel: "Integration version"
1 change: 1 addition & 0 deletions netflow-mixin/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../Makefile_mixin
42 changes: 42 additions & 0 deletions netflow-mixin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Netflow Mixin

The Netflow mixin is a set of configurable Grafana dashboards for visualizing network flows.
It is based on the [OpenTelemetry semantic conventions for networking](https://opentelemetry.io/docs/specs/semconv/registry/attributes/network/).

The Netflow mixin contains the following dashboards:
- Netflow Overview

## Netflow Overview


![First screenshot of the overview dashboard](https://storage.googleapis.com/grafanalabs-integration-assets/ktranslate-netflow/netflow-overview.png)
![Second screenshot of the overview dashboard](https://storage.googleapis.com/grafanalabs-integration-assets/ktranslate-netflow/netflow-overview-2.png)


## Install tools

```bash
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@latest
```

For linting and formatting, you would also need and `jsonnetfmt` installed. If you
have a working Go development environment, it's easiest to run the following:

```bash
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
```

The files in `dashboards_out` need to be imported
into your Grafana server. The exact details will be depending on your environment.

## Generate dashboards

Edit `config.libsonnet` if required and then build JSON dashboard files for Grafana:

```bash
make
```

For more advanced uses of mixins, see
https://github.com/monitoring-mixins/docs.
8 changes: 8 additions & 0 deletions netflow-mixin/config.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
_config+:: {
dashboardTags: ['neflow-mixin'],
dashboardPeriod: 'now-1h',
dashboardTimezone: 'default',
dashboardRefresh: '1m',
},
}
1 change: 1 addition & 0 deletions netflow-mixin/dashboards/dashboards.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(import 'netflow-overview.libsonnet')
87 changes: 87 additions & 0 deletions netflow-mixin/dashboards/netflow-overview.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
local g = import 'github.com/grafana/grafonnet/gen/grafonnet-latest/main.libsonnet';
local var = g.dashboard.variable;

local panels = import 'panels.libsonnet';


local labelVar = function(label, title=label) var.query.new(label, 'network_io_bytes')
+ var.query.refresh.onTime()
+ var.query.generalOptions.withLabel(title)
+ var.query.queryTypes.withLabelValues(
label,
)
+ var.query.withDatasource(
type='prometheus',
uid='$prometheus_datasource',
)
+ var.query.selectionOptions.withMulti()
+ var.query.selectionOptions.withIncludeAll(customAllValue='.+');
local withPos(x, y, h, w) = { gridPos+: { x: x, y: y, h: h, w: w } };

local dashboardUid = 'netflow-overview';

{
grafanaDashboards+:: {
'netflow-overview.json':
g.dashboard.new('Netflow overview')
+ g.dashboard.withUid(dashboardUid)
+ g.dashboard.withTags($._config.dashboardTags)
+ g.dashboard.time.withFrom($._config.dashboardPeriod)
+ g.dashboard.withRefresh($._config.dashboardRefresh)
+ g.dashboard.withTimezone($._config.dashboardTimezone)
+ g.dashboard.withVariables([
var.datasource.new('prometheus_datasource', 'prometheus')
+ var.query.generalOptions.withLabel('Prometheus data source'),
var.datasource.new('loki_datasource', 'loki')
+ var.query.generalOptions.withLabel('Loki data source'),
labelVar('job', 'Job')
+ var.query.generalOptions.showOnDashboard.withNothing(),
labelVar('device_name', 'Device name'),
labelVar('network_local_address', 'Source'),
labelVar('network_peer_address', 'Destination'),
])
+ g.dashboard.withPanels([
panels.totalTraffic
+ withPos(0, 1, 5, 15),
panels.stats
+ withPos(15, 1, 5, 9),
panels.topSources
+ withPos(0, 6, 8, 12),
panels.topDestinations
+ withPos(12, 6, 8, 12),
g.panel.row.new('Conversations')
+ withPos(0, 14, 1, 24),
panels.conversationTotalBytes
+ withPos(0, 15, 15, 15),
panels.conversationTraffic
+ withPos(15, 15, 7, 9),
panels.conversationByPair
+ withPos(15, 22, 8, 9),
g.panel.row.new('Protocols')
+ withPos(0, 30, 1, 24),
panels.protocolTotalBytes
+ withPos(0, 31, 15, 15),
panels.protocolDistribution
+ withPos(15, 31, 7, 9),
panels.protocolOverTime
+ withPos(15, 38, 8, 9),
g.panel.row.new('Geographic data')
+ withPos(0, 46, 1, 24),
panels.topDestinationMap
+ withPos(0, 47, 13, 8),
panels.destinationsLegend
+ withPos(8, 47, 13, 4),
panels.topSourcesMap
+ withPos(12, 47, 13, 8),
panels.sourcesLegend
+ withPos(20, 47, 13, 4),
g.panel.row.new('Collector details')
+ withPos(0, 60, 1, 24),
panels.collectorLogs
+ withPos(0, 61, 8, 17),
panels.deviceStats
+ withPos(17, 61, 8, 7),
]),

},
}
Loading
Loading