Skip to content

Add read-only network metrics API#2003

Open
liameast43345 wants to merge 2 commits into
unraid:mainfrom
liameast43345:bounty/network-metrics-1602
Open

Add read-only network metrics API#2003
liameast43345 wants to merge 2 commits into
unraid:mainfrom
liameast43345:bounty/network-metrics-1602

Conversation

@liameast43345
Copy link
Copy Markdown

@liameast43345 liameast43345 commented May 12, 2026

Summary

  • expands read-only network interface data with link details and address arrays
  • adds metrics.network plus systemMetricsNetwork polling at the existing 2s metrics interval
  • maps systeminformation network stats to GraphQL-friendly fields and reads Linux packet counters from /sys/class/net when available

Fixes #1602

Testing

  • pnpm --dir api exec vitest run src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts src/unraid-api/graph/resolvers/metrics/metrics.resolver.spec.ts src/unraid-api/graph/resolvers/metrics/metrics.resolver.integration.spec.ts src/unraid-api/graph/resolvers/metrics/temperature/temperature.resolver.integration.spec.ts
  • pnpm --dir api lint
  • pnpm --dir api type-check

Notes

A broader pnpm --dir api test run executed 1,976 passing tests and failed only src/test/core/utils/pm2/unraid-api-running.integration.test.ts, where the PM2 process detection returned false in this local environment.

Summary by CodeRabbit

  • New Features
    • Richer network interface info (MTU, speed, duplex, VLAN, operstate, virtual/internal flags, IPv4/IPv6 address lists).
    • Per-interface network metrics (bytes, packets, errors, drops, RX/TX rates, utilization, last-updated).
    • New query for network interfaces and real-time subscription for system network metrics.
  • Tests
    • Added unit and integration tests covering network metrics, polling, and pub/sub behavior.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Walkthrough

Adds GraphQL types and a root query for static network interfaces, implements NetworkMetrics collection (polling + pubsub), exposes metrics in metrics.network and systemMetricsNetwork subscription, and updates services, modules, and tests to map systeminformation and /sys counters into GraphQL models.

Changes

Network Metrics and Interface Exposure

Layer / File(s) Summary
Network Interface Schema and Types
api/generated-schema.graphql, api/src/unraid-api/graph/resolvers/info/network/network.model.ts
GraphQL schema introduces InfoNetworkIpv4Address and InfoNetworkIpv6Address types with address and netmask/prefixLength fields, extends InfoNetworkInterface with MTU, speed, duplex, virtual/internal flags, operstate, type, VLAN ID, and arrays of structured IPv4/IPv6 addresses, and exposes networkInterfaces query on the root Query type.
Network Interface Query Implementation
api/src/unraid-api/graph/resolvers/info/network/network.resolver.ts, api/src/unraid-api/graph/resolvers/info/network/network.service.ts
networkInterfaces() is converted to a top-level query with a permissions guard (AuthAction.READ_ANY, Resource.INFO), and a new @ResolveField method populates the networkInterfaces field on Info. Service layer extends interface mapping to include MTU, speed, duplex, operational state, virtual/internal flags, VLAN ID, and structures IPv4/IPv6 addresses with netmask/prefix-length parsing.
Network Metrics Schema and Model
api/generated-schema.graphql, api/src/unraid-api/graph/resolvers/metrics/network/network.model.ts
GraphQL schema introduces NetworkMetrics type with fields for interface name, operational state, byte/packet counters (received/sent), error and drop counters, RX/TX throughput rates, optional utilization percentage, and last-updated timestamp. Metrics type gains network: [NetworkMetrics!]! field.
Network Metrics Collection Service
api/src/unraid-api/graph/resolvers/metrics/network/network.service.ts
NetworkMetricsService fetches interface statistics from systeminformation.networkStats() and augments them with packet counters from /sys/class/net/<iface>/statistics/ (rx_packets, tx_packets). Computes utilizationPercent from combined RX/TX rates and interface speed; gracefully returns zero counters and undefined utilization when speed is unavailable or files are unreadable.
Metrics Query and Network Subscription
api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.ts, api/src/unraid-api/graph/resolvers/metrics/metrics.model.ts
MetricsResolver injects NetworkMetricsService and adds network() resolve field. During onModuleInit, registers PUBSUB_CHANNEL.NETWORK_UTILIZATION polling topic (2000ms) to fetch and publish metrics. Implements systemMetricsNetwork subscription that streams updates through the pubsub channel with READ_ANY / INFO permission guard. GraphQL schema exposes systemMetricsNetwork: [NetworkMetrics!]! on Subscription type.
Module Integration and PubSub Setup
api/src/unraid-api/graph/resolvers/metrics/metrics.module.ts, packages/unraid-shared/src/pubsub/graphql.pubsub.ts
MetricsModule imports NetworkMetricsService and registers it as a provider. GRAPHQL_PUBSUB_CHANNEL enum gains NETWORK_UTILIZATION constant to support network metrics streaming.
Unit and Integration Test Coverage
api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts, api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.spec.ts, api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.integration.spec.ts, api/src/unraid-api/graph/resolvers/metrics/temperature/temperature.resolver.integration.spec.ts
Adds Vitest suite for NetworkMetricsService covering normal metric mapping and fallback behavior when speed is unavailable. Extends MetricsResolver specs with network() query tests and subscription/polling lifecycle assertions. Registers NetworkMetricsService in all affected test modules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #1602 — Implements the "Network Interfaces & Metrics" feature: exposes networkInterfaces, metrics.network, and systemMetricsNetwork subscription with per-interface counters, rates, utilization, and 2s polling.
  • #1559 — Changes align with previously reported request for per-interface monitoring and schema exposure (interfaces, IPs, MTU/speed/duplex, VLAN, realtime metrics).

Poem

🐰 I hopped through nets and counters bright,

IPv4 and IPv6 now in sight.
Metrics pulse and streams alight,
Per-interface tales in flight. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add read-only network metrics API' clearly and concisely summarizes the main change, which is adding read-only network metrics functionality to the API.
Linked Issues check ✅ Passed The PR successfully implements all primary objectives from issue #1602: networkInterfaces query, metrics.network query, systemMetricsNetwork subscription with 2s polling, throughput/utilization calculations, and GraphQL-friendly schema following systeminformation conventions.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the linked issue scope: network interface information, metrics queries/subscriptions, GraphQL model definitions, and service implementations for data collection. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 920977ff70

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@Injectable()
export class NetworkMetricsService {
async getNetworkMetrics(): Promise<NetworkMetrics[]> {
const [stats, interfaces] = await Promise.all([networkStats(), networkInterfaces()]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return stats for all interfaces

On hosts with more than one interface, networkStats() without an argument only returns the first/default external interface; the systeminformation docs state to pass '*' for all interfaces (https://systeminformation.io/network.html). Since this API is exposed as metrics.network / systemMetricsNetwork for all interfaces and the service already builds speeds for every interface, Unraid interfaces such as br0, bond0, VLANs, or secondary NICs are silently omitted. Use networkStats('*') or pass the collected interface names here.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/unraid-api/graph/resolvers/info/network/network.service.ts (1)

53-53: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace as with satisfies for structural type validation.

Lines 53 and 100 use as InfoNetworkInterface which bypasses TypeScript's type checking. Use satisfies InfoNetworkInterface instead to enforce structural compatibility while preserving inferred types, providing stricter guardrails and better alignment with the coding guideline to avoid casting.

Suggested change
-            } as InfoNetworkInterface;
+            } satisfies InfoNetworkInterface;
...
-        } as InfoNetworkInterface;
+        } satisfies InfoNetworkInterface;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/unraid-api/graph/resolvers/info/network/network.service.ts` at line
53, Replace the two non-type-safe casts that use "as InfoNetworkInterface" with
the TypeScript "satisfies InfoNetworkInterface" operator so the objects are
structurally validated while keeping inferred types; update the object
expressions that currently end with "as InfoNetworkInterface" (occurrences
around the object returned in the network service — the expression at the line
shown and the second occurrence near line 100) to use "satisfies
InfoNetworkInterface" instead, ensuring your tsconfig/TS version supports the
satisfies operator.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/unraid-api/graph/resolvers/info/network/network.service.ts`:
- Around line 111-113: The parseIpv6PrefixLength function currently converts
subnet strings via Number(subnet) which treats empty string as 0; update
parseIpv6PrefixLength to first guard against empty or non-numeric subnet (e.g.,
check subnet == null or subnet.trim() === '' or use a /^\d+$/ test) before
calling Number/parseInt, and only return a numeric prefix when the input is a
valid integer in the expected range (0–128); reference function name
parseIpv6PrefixLength and parameter subnet when making this change.

---

Outside diff comments:
In `@api/src/unraid-api/graph/resolvers/info/network/network.service.ts`:
- Line 53: Replace the two non-type-safe casts that use "as
InfoNetworkInterface" with the TypeScript "satisfies InfoNetworkInterface"
operator so the objects are structurally validated while keeping inferred types;
update the object expressions that currently end with "as InfoNetworkInterface"
(occurrences around the object returned in the network service — the expression
at the line shown and the second occurrence near line 100) to use "satisfies
InfoNetworkInterface" instead, ensuring your tsconfig/TS version supports the
satisfies operator.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e3f927f4-c9be-475b-b5d5-8c88456925fe

📥 Commits

Reviewing files that changed from the base of the PR and between a2d4843 and 920977f.

📒 Files selected for processing (14)
  • api/generated-schema.graphql
  • api/src/unraid-api/graph/resolvers/info/network/network.model.ts
  • api/src/unraid-api/graph/resolvers/info/network/network.resolver.ts
  • api/src/unraid-api/graph/resolvers/info/network/network.service.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.model.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.module.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.integration.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.model.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.service.ts
  • api/src/unraid-api/graph/resolvers/metrics/temperature/temperature.resolver.integration.spec.ts
  • packages/unraid-shared/src/pubsub/graphql.pubsub.ts

Comment thread api/src/unraid-api/graph/resolvers/info/network/network.service.ts Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

❌ Patch coverage is 52.81385% with 109 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.68%. Comparing base (eb60d4d) to head (3949520).

Files with missing lines Patch % Lines
...pi/graph/resolvers/info/network/network.service.ts 3.70% 52 Missing ⚠️
...-api/graph/resolvers/info/network/network.model.ts 29.41% 24 Missing ⚠️
...i/graph/resolvers/metrics/network/network.model.ts 50.00% 17 Missing ⚠️
...i/graph/resolvers/info/network/network.resolver.ts 22.22% 7 Missing ⚠️
...id-api/graph/resolvers/metrics/metrics.resolver.ts 68.18% 7 Missing ⚠️
...nraid-api/graph/resolvers/metrics/metrics.model.ts 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2003      +/-   ##
==========================================
- Coverage   52.69%   52.68%   -0.01%     
==========================================
  Files        1033     1035       +2     
  Lines       71688    71917     +229     
  Branches     8205     8235      +30     
==========================================
+ Hits        37773    37891     +118     
- Misses      33789    33900     +111     
  Partials      126      126              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nofuturekid
Copy link
Copy Markdown

Downstream consumer here — building an open-source Android client (nofuturekid/nova) that consumes the public Unraid GraphQL API. This PR would close one of the two real gaps we hit (the other is plugin-update status, tracked separately in #2012). Just wanted to surface that there's at least one external project ready to integrate metrics.network + systemMetricsNetwork the moment they ship in a release.

FYI as a cross-reference for the field-shape discussion: jandrop/u-manager-companion is a Python hot-patch plugin that exposes a similar surface today (info.devices.network with rxBytesPerSec / txBytesPerSec + systemMetricsNetwork subscription, sampling /proc/net/dev twice 1 second apart). Field names differ slightly from this PR but the underlying data path is the same — possibly useful if questions about sampling cadence or per-second-vs-cumulative come up.

Thanks for taking on the bounty — looking forward to the merge.

@elibosley elibosley force-pushed the bounty/network-metrics-1602 branch from 3fde249 to 3949520 Compare May 20, 2026 19:51
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts (1)

41-46: ⚡ Quick win

Replace as casts in mocked networkInterfaces fixtures with typed fixtures.

These casts bypass compile-time checks and can hide interface-shape drift in tests. Prefer a typed fixture factory (returning Systeminformation.NetworkInterfacesData) so mockResolvedValue stays fully type-safe without assertions.

As per coding guidelines, **/*.{ts,tsx}: "Avoid using casting whenever possible, prefer proper typing from the start."

Also applies to: 88-93

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts`
around lines 41 - 46, The test currently uses an `as` cast when calling
`vi.mocked(networkInterfaces).mockResolvedValue([... ] as
Systeminformation.NetworkInterfacesData[])`; replace this cast by creating a
typed fixture factory that returns Systeminformation.NetworkInterfacesData
objects (e.g., a helper like `makeNetworkInterfaceFixture():
Systeminformation.NetworkInterfacesData`) and use its return value in
`mockResolvedValue` so the mock stays fully type-safe; update both occurrences
(the one at lines ~41-46 and the one at ~88-93) to call the fixture factory
instead of using `as` casts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts`:
- Around line 41-46: The test currently uses an `as` cast when calling
`vi.mocked(networkInterfaces).mockResolvedValue([... ] as
Systeminformation.NetworkInterfacesData[])`; replace this cast by creating a
typed fixture factory that returns Systeminformation.NetworkInterfacesData
objects (e.g., a helper like `makeNetworkInterfaceFixture():
Systeminformation.NetworkInterfacesData`) and use its return value in
`mockResolvedValue` so the mock stays fully type-safe; update both occurrences
(the one at lines ~41-46 and the one at ~88-93) to call the fixture factory
instead of using `as` casts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c0b56819-ef1e-46aa-96e6-a77c0b59ed91

📥 Commits

Reviewing files that changed from the base of the PR and between 3fde249 and 3949520.

📒 Files selected for processing (14)
  • api/generated-schema.graphql
  • api/src/unraid-api/graph/resolvers/info/network/network.model.ts
  • api/src/unraid-api/graph/resolvers/info/network/network.resolver.ts
  • api/src/unraid-api/graph/resolvers/info/network/network.service.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.model.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.module.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.integration.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/metrics.resolver.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.model.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.service.spec.ts
  • api/src/unraid-api/graph/resolvers/metrics/network/network.service.ts
  • api/src/unraid-api/graph/resolvers/metrics/temperature/temperature.resolver.integration.spec.ts
  • packages/unraid-shared/src/pubsub/graphql.pubsub.ts
✅ Files skipped from review due to trivial changes (1)
  • api/generated-schema.graphql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Bounty] Network Metrics

3 participants