Files
natsdotnet/gaps/monitoring.md
Joseph Doherty c30e67a69d Fix E2E test gaps and add comprehensive E2E + parity test suites
- Fix pull consumer fetch: send original stream subject in HMSG (not inbox)
  so NATS client distinguishes data messages from control messages
- Fix MaxAge expiry: add background timer in StreamManager for periodic pruning
- Fix JetStream wire format: Go-compatible anonymous objects with string enums,
  proper offset-based pagination for stream/consumer list APIs
- Add 42 E2E black-box tests (core messaging, auth, TLS, accounts, JetStream)
- Add ~1000 parity tests across all subsystems (gaps closure)
- Update gap inventory docs to reflect implementation status
2026-03-12 14:09:23 -04:00

317 lines
34 KiB
Markdown

# Monitoring — Gap Analysis
> This file tracks what has and hasn't been ported from Go to .NET for the **Monitoring** module.
> See [stillmissing.md](stillmissing.md) for the full LOC comparison across all modules.
## LLM Instructions: How to Analyze This Category
### Step 1: Read the Go Reference Files
Read each Go source file listed below. For every file:
1. Extract all **exported types** (structs, interfaces, type aliases)
2. Extract all **exported methods** on those types (receiver functions)
3. Extract all **exported standalone functions**
4. Note **key constants, enums, and protocol states**
5. Note **important unexported helpers** that implement core logic (functions >20 lines)
6. Pay attention to **concurrency patterns** (goroutines, mutexes, channels) — these map to different .NET patterns
### Step 2: Read the .NET Implementation Files
Read all `.cs` files in the .NET directories listed below. For each Go symbol found in Step 1:
1. Search for a matching type, method, or function in .NET
2. If found, compare the behavior: does it handle the same edge cases? Same error paths?
3. If partially implemented, note what's missing
4. If not found, note it as MISSING
### Step 3: Cross-Reference Tests
Compare Go test functions against .NET test methods:
1. For each Go `Test*` function, check if a corresponding .NET `[Fact]` or `[Theory]` exists
2. Note which test scenarios are covered and which are missing
3. Check the parity DB (`docs/test_parity.db`) for existing mappings:
```bash
sqlite3 docs/test_parity.db "SELECT go_test, dotnet_test, confidence FROM test_mappings tm JOIN go_tests gt ON tm.go_test_id=gt.rowid JOIN dotnet_tests dt ON tm.dotnet_test_id=dt.rowid WHERE gt.go_file LIKE '%PATTERN%'"
```
### Step 4: Classify Each Item
Use these status values:
| Status | Meaning |
|--------|---------|
| **PORTED** | Equivalent exists in .NET with matching behavior |
| **PARTIAL** | .NET implementation exists but is incomplete (missing edge cases, error handling, or features) |
| **MISSING** | No .NET equivalent found — needs to be ported |
| **NOT_APPLICABLE** | Go-specific pattern that doesn't apply to .NET (build tags, platform-specific goroutine tricks, etc.) |
| **DEFERRED** | Intentionally skipped for now (document why) |
### Step 5: Fill In the Gap Inventory
Add rows to the Gap Inventory table below. Group by Go source file. Include the Go file and line number so a porting LLM can jump directly to the reference implementation.
### Key Porting Notes for Monitoring
- The monitoring JSON response shapes must match the Go server for tooling compatibility (nats-top, Prometheus exporters, etc.).
- Each endpoint has query parameters for filtering and sorting (e.g., `/connz?sort=bytes_to&limit=10`).
- `/healthz` is used for Kubernetes liveness probes and has JetStream-aware health checks.
- Port 8222 by default.
---
## Go Reference Files (Source)
- `golang/nats-server/server/monitor.go` — HTTP monitoring endpoints (~4,200 lines): `/varz`, `/connz`, `/routez`, `/gatewayz`, `/leafz`, `/subsz`, `/jsz`, `/healthz`, `/accountz`
- `golang/nats-server/server/monitor_sort_opts.go` — Sort options for monitoring endpoints
## Go Reference Files (Tests)
- `golang/nats-server/server/monitor_test.go`
- `golang/nats-server/test/monitor_test.go` (integration)
## .NET Implementation Files (Source)
- `src/NATS.Server/Monitoring/MonitorServer.cs`
- `src/NATS.Server/Monitoring/Varz.cs`
- `src/NATS.Server/Monitoring/Subsz.cs`
- `src/NATS.Server/Monitoring/VarzHandler.cs`
- `src/NATS.Server/Monitoring/SubszHandler.cs`
- `src/NATS.Server/Monitoring/JszHandler.cs`
- `src/NATS.Server/Monitoring/AccountzHandler.cs`
- `src/NATS.Server/Monitoring/GatewayzHandler.cs`
- `src/NATS.Server/Monitoring/LeafzHandler.cs`
- `src/NATS.Server/Monitoring/RoutezHandler.cs`
- `src/NATS.Server/Monitoring/PprofHandler.cs`
- `src/NATS.Server/Monitoring/ClosedClient.cs`
- All other files in `src/NATS.Server/Monitoring/`
## .NET Implementation Files (Tests)
- `tests/NATS.Server.Tests/Monitoring/`
---
## Gap Inventory
<!-- After analysis, fill in this table. Group rows by Go source file. -->
### monitor_sort_opts.go
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|-----------|:-------------|--------|:----------------|-------|
| `ConnInfos` (type alias `[]*ConnInfo`) | golang/nats-server/server/monitor_sort_opts.go:21 | PORTED | src/NATS.Server/Monitoring/Connz.cs:30 | .NET uses `ConnInfo[]` arrays instead |
| `ConnInfos.Len()` | golang/nats-server/server/monitor_sort_opts.go:25 | NOT_APPLICABLE | — | Go sort.Interface boilerplate; .NET LINQ handles sorting natively |
| `ConnInfos.Swap()` | golang/nats-server/server/monitor_sort_opts.go:28 | NOT_APPLICABLE | — | Go sort.Interface boilerplate; .NET LINQ handles sorting natively |
| `SortOpt` (string type) | golang/nats-server/server/monitor_sort_opts.go:31 | PORTED | src/NATS.Server/Monitoring/Connz.cs:595 | .NET has both `SortOpt` enum (internal) and `ConnzSortOption` enum (public API) |
| `ByCid` constant | golang/nats-server/server/monitor_sort_opts.go:35 | PORTED | src/NATS.Server/Monitoring/Connz.cs:597 | `SortOpt.ByCid` |
| `ByStart` constant | golang/nats-server/server/monitor_sort_opts.go:36 | PORTED | src/NATS.Server/Monitoring/Connz.cs:598 | `SortOpt.ByStart` |
| `BySubs` constant | golang/nats-server/server/monitor_sort_opts.go:37 | PORTED | src/NATS.Server/Monitoring/Connz.cs:599 | `SortOpt.BySubs` |
| `ByPending` constant | golang/nats-server/server/monitor_sort_opts.go:38 | PORTED | src/NATS.Server/Monitoring/Connz.cs:600 | `SortOpt.ByPending` |
| `ByOutMsgs` constant | golang/nats-server/server/monitor_sort_opts.go:39 | PORTED | src/NATS.Server/Monitoring/Connz.cs:601 | `SortOpt.ByMsgsTo` |
| `ByInMsgs` constant | golang/nats-server/server/monitor_sort_opts.go:40 | PORTED | src/NATS.Server/Monitoring/Connz.cs:602 | `SortOpt.ByMsgsFrom` |
| `ByOutBytes` constant | golang/nats-server/server/monitor_sort_opts.go:41 | PORTED | src/NATS.Server/Monitoring/Connz.cs:603 | `SortOpt.ByBytesTo` |
| `ByInBytes` constant | golang/nats-server/server/monitor_sort_opts.go:42 | PORTED | src/NATS.Server/Monitoring/Connz.cs:604 | `SortOpt.ByBytesFrom` |
| `ByLast` constant | golang/nats-server/server/monitor_sort_opts.go:43 | PORTED | src/NATS.Server/Monitoring/Connz.cs:605 | `SortOpt.ByLast` |
| `ByIdle` constant | golang/nats-server/server/monitor_sort_opts.go:44 | PORTED | src/NATS.Server/Monitoring/Connz.cs:606 | `SortOpt.ByIdle` |
| `ByUptime` constant | golang/nats-server/server/monitor_sort_opts.go:45 | PORTED | src/NATS.Server/Monitoring/Connz.cs:607 | `SortOpt.ByUptime` |
| `ByStop` constant | golang/nats-server/server/monitor_sort_opts.go:46 | PORTED | src/NATS.Server/Monitoring/Connz.cs:608 | `SortOpt.ByStop` |
| `ByReason` constant | golang/nats-server/server/monitor_sort_opts.go:47 | PORTED | src/NATS.Server/Monitoring/Connz.cs:609 | `SortOpt.ByReason` |
| `ByRTT` constant | golang/nats-server/server/monitor_sort_opts.go:48 | PORTED | src/NATS.Server/Monitoring/Connz.cs:610 | `SortOpt.ByRtt` |
| `SortByCid` | golang/nats-server/server/monitor_sort_opts.go:53 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:59 | Implemented as LINQ OrderBy in the sort switch |
| `SortBySubs` | golang/nats-server/server/monitor_sort_opts.go:58 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:61 | LINQ OrderByDescending |
| `SortByPending` | golang/nats-server/server/monitor_sort_opts.go:63 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:62 | LINQ OrderByDescending |
| `SortByOutMsgs` | golang/nats-server/server/monitor_sort_opts.go:68 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:63 | LINQ OrderByDescending |
| `SortByInMsgs` | golang/nats-server/server/monitor_sort_opts.go:73 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:64 | LINQ OrderByDescending |
| `SortByOutBytes` | golang/nats-server/server/monitor_sort_opts.go:78 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:65 | LINQ OrderByDescending |
| `SortByInBytes` | golang/nats-server/server/monitor_sort_opts.go:83 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:66 | LINQ OrderByDescending |
| `SortByLast` | golang/nats-server/server/monitor_sort_opts.go:88 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:67 | LINQ OrderByDescending |
| `SortByIdle` | golang/nats-server/server/monitor_sort_opts.go:95 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:68 | LINQ OrderByDescending with now capture |
| `SortByUptime` | golang/nats-server/server/monitor_sort_opts.go:105 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:69 | LINQ OrderByDescending |
| `SortByStop` | golang/nats-server/server/monitor_sort_opts.go:128 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:70 | LINQ OrderByDescending |
| `SortByReason` | golang/nats-server/server/monitor_sort_opts.go:137 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:71 | LINQ OrderBy |
| `SortByRTT` | golang/nats-server/server/monitor_sort_opts.go:144 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:72 | LINQ OrderBy |
| `SortOpt.IsValid()` | golang/nats-server/server/monitor_sort_opts.go:149 | PORTED | src/NATS.Server/Monitoring/Connz.cs:618 | Added explicit `SortOptExtensions.IsValid()` parity helper and wired query parsing to validate parsed sort keys |
---
### monitor.go — Types and Structs
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|-----------|:-------------|--------|:----------------|-------|
| `Connz` struct | golang/nats-server/server/monitor.go:48 | PORTED | src/NATS.Server/Monitoring/Connz.cs:8 | All JSON fields match |
| `ConnzOptions` struct | golang/nats-server/server/monitor.go:59 | PORTED | src/NATS.Server/Monitoring/Connz.cs:628 | All options ported |
| `ConnState` type | golang/nats-server/server/monitor.go:102 | PORTED | src/NATS.Server/Monitoring/Connz.cs:617 | `ConnState` enum with Open/Closed/All |
| `ConnOpen` constant | golang/nats-server/server/monitor.go:105 | PORTED | src/NATS.Server/Monitoring/Connz.cs:619 | `ConnState.Open` |
| `ConnClosed` constant | golang/nats-server/server/monitor.go:107 | PORTED | src/NATS.Server/Monitoring/Connz.cs:620 | `ConnState.Closed` |
| `ConnAll` constant | golang/nats-server/server/monitor.go:109 | PORTED | src/NATS.Server/Monitoring/Connz.cs:621 | `ConnState.All` |
| `ConnInfo` struct | golang/nats-server/server/monitor.go:114 | PARTIAL | src/NATS.Server/Monitoring/Connz.cs:36 | Added `stalls`, `jwt`, `issuer_key`, `name_tag`, `tags`, and structured `proxy` fields with open/closed snapshot mapping in `ConnzHandler`. Remaining parity gap: `stalls` is currently reported as `0` and `name_tag` is currently empty (no account name-tag source wired). |
| `ProxyInfo` struct | golang/nats-server/server/monitor.go:157 | PORTED | src/NATS.Server/Monitoring/Connz.cs:154 | Added `ProxyInfo` model with `key` field and wired `ConnInfo.proxy` as an object in connz output. |
| `TLSPeerCert` struct | golang/nats-server/server/monitor.go:163 | PORTED | src/NATS.Server/Monitoring/Connz.cs:144 | Added `TLSPeerCert` with `subject`, `subject_pk_sha256`, and `cert_sha256` fields; wired into `ConnInfo.tls_peer_certs` |
| `DefaultConnListSize` constant | golang/nats-server/server/monitor.go:169 | PORTED | src/NATS.Server/Monitoring/Connz.cs:660 | Default 1024 on `ConnzOptions.Limit` |
| `DefaultSubListSize` constant | golang/nats-server/server/monitor.go:172 | PORTED | src/NATS.Server/Monitoring/Subsz.cs:41 | Default 1024 on `SubszOptions.Limit` |
| `Routez` struct | golang/nats-server/server/monitor.go:782 | PARTIAL | src/NATS.Server/Monitoring/RoutezHandler.cs:12 | Go has full Routez struct with ID, Name, Now, Import, Export, NumRoutes, Routes; .NET returns anonymous object with only `routes` and `num_routes` counts |
| `RoutezOptions` struct | golang/nats-server/server/monitor.go:793 | MISSING | — | No options struct; handler accepts no query params |
| `RouteInfo` struct | golang/nats-server/server/monitor.go:801 | MISSING | — | Go has full per-route details (Rid, RemoteID, RTT, etc.); .NET returns just route count |
| `Subsz` struct | golang/nats-server/server/monitor.go:928 | PARTIAL | src/NATS.Server/Monitoring/Subsz.cs:8 | Missing `SublistStats` embedded fields; .NET has `NumSubs` and `NumCache` instead of the full `SublistStats` type |
| `SubszOptions` struct | golang/nats-server/server/monitor.go:940 | PORTED | src/NATS.Server/Monitoring/Subsz.cs:38 | All options present |
| `SubDetail` struct | golang/nats-server/server/monitor.go:961 | PARTIAL | src/NATS.Server/Monitoring/Connz.cs:142 | Missing `AccountTag` field; present fields match |
| `Varz` struct | golang/nats-server/server/monitor.go:1211 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:8 | Missing: `ConfigDigest`, `TrustedOperatorsJwt`, `TrustedOperatorsClaim`, `PinnedAccountFail` (present), `OCSPResponseCache`, `StaleConnectionStats` (present), `Proxies`, `WriteTimeout` string field; `StalledClients` field missing; `Metadata` field missing |
| `JetStreamVarz` struct | golang/nats-server/server/monitor.go:1286 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:403 | Missing `Meta *MetaClusterInfo` and `Limits *JSLimitOpts` fields |
| `ClusterOptsVarz` struct | golang/nats-server/server/monitor.go:1294 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:251 | Missing `WriteDeadline`, `WriteTimeout`, `TLSCertNotAfter` fields |
| `GatewayOptsVarz` struct | golang/nats-server/server/monitor.go:1310 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:285 | Missing `Gateways []RemoteGatewayOptsVarz`, `WriteDeadline`, `WriteTimeout`, `TLSCertNotAfter` fields |
| `RemoteGatewayOptsVarz` struct | golang/nats-server/server/monitor.go:1328 | MISSING | — | No .NET equivalent |
| `LeafNodeOptsVarz` struct | golang/nats-server/server/monitor.go:1335 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:322 | Missing `Remotes []RemoteLeafOptsVarz`, `WriteDeadline`, `WriteTimeout`, `TLSCertNotAfter` fields |
| `DenyRules` struct | golang/nats-server/server/monitor.go:1350 | MISSING | — | No .NET equivalent |
| `RemoteLeafOptsVarz` struct | golang/nats-server/server/monitor.go:1356 | MISSING | — | No .NET equivalent |
| `MQTTOptsVarz` struct | golang/nats-server/server/monitor.go:1365 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:350 | Missing `TLSOCSPPeerVerify`, `TLSCertNotAfter` fields |
| `WebsocketOptsVarz` struct | golang/nats-server/server/monitor.go:1381 | PARTIAL | src/NATS.Server/Monitoring/Varz.cs:387 | Go has many more fields (Advertise, NoAuthUser, JWTCookie, HandshakeTimeout, AuthTimeout, NoTLS, TLSMap, TLSPinnedCerts, SameOrigin, AllowedOrigins, Compression, TLSOCSPPeerVerify, TLSCertNotAfter); .NET only has Host, Port, TlsTimeout |
| `OCSPResponseCacheVarz` struct | golang/nats-server/server/monitor.go:1399 | MISSING | — | No .NET equivalent; OCSP cache monitoring not ported |
| `ProxiesOptsVarz` struct | golang/nats-server/server/monitor.go:1411 | MISSING | — | No .NET equivalent |
| `ProxyOptsVarz` struct | golang/nats-server/server/monitor.go:1416 | MISSING | — | No .NET equivalent |
| `VarzOptions` struct | golang/nats-server/server/monitor.go:1422 | PORTED | — | Empty struct, not needed in .NET since handler takes no options |
| `SlowConsumersStats` struct | golang/nats-server/server/monitor.go:1424 | PORTED | src/NATS.Server/Monitoring/Varz.cs:213 | All four fields present |
| `StaleConnectionStats` struct | golang/nats-server/server/monitor.go:1432 | PORTED | src/NATS.Server/Monitoring/Varz.cs:232 | All four fields present |
| `GatewayzOptions` struct | golang/nats-server/server/monitor.go:2004 | MISSING | — | .NET GatewayzHandler has no options; returns only counts |
| `Gatewayz` struct | golang/nats-server/server/monitor.go:2024 | PARTIAL | src/NATS.Server/Monitoring/GatewayzHandler.cs:12 | Go has full struct with OutboundGateways/InboundGateways maps; .NET returns anonymous count object |
| `RemoteGatewayz` struct | golang/nats-server/server/monitor.go:2036 | MISSING | — | No .NET equivalent |
| `AccountGatewayz` struct | golang/nats-server/server/monitor.go:2043 | MISSING | — | No .NET equivalent |
| `Leafz` struct | golang/nats-server/server/monitor.go:2348 | PARTIAL | src/NATS.Server/Monitoring/LeafzHandler.cs:12 | Go has full struct with NumLeafs and Leafs array; .NET returns anonymous count object |
| `LeafzOptions` struct | golang/nats-server/server/monitor.go:2356 | MISSING | — | No options struct; handler accepts no query params |
| `LeafInfo` struct | golang/nats-server/server/monitor.go:2364 | MISSING | — | No .NET equivalent for per-leafnode detail |
| `AccountStatz` struct | golang/nats-server/server/monitor.go:2471 | PARTIAL | src/NATS.Server/Monitoring/AccountzHandler.cs:27 | Go has `ID`, `Now`, `Accounts []*AccountStat`; .NET returns anonymous object with total counts |
| `AccountStatzOptions` struct | golang/nats-server/server/monitor.go:2478 | MISSING | — | No .NET equivalent; `?unused` query param not parsed |
| `AccountzOptions` struct | golang/nats-server/server/monitor.go:2646 | MISSING | — | `?acc=` query param not parsed for account detail |
| `ExtImport` struct | golang/nats-server/server/monitor.go:2662 | MISSING | — | JWT import monitoring detail not ported |
| `ExtExport` struct | golang/nats-server/server/monitor.go:2672 | MISSING | — | JWT export monitoring detail not ported |
| `ExtVrIssues` struct | golang/nats-server/server/monitor.go:2678 | MISSING | — | JWT validation result reporting not ported |
| `ExtMap` type | golang/nats-server/server/monitor.go:2684 | MISSING | — | Account subject mapping detail not ported |
| `AccountInfo` struct | golang/nats-server/server/monitor.go:2686 | MISSING | — | Detailed per-account monitoring not ported |
| `Accountz` struct | golang/nats-server/server/monitor.go:2710 | PARTIAL | src/NATS.Server/Monitoring/AccountzHandler.cs:14 | Go has ID, Now, SystemAccount, Accounts list, and Account detail; .NET returns simplified anonymous object |
| `JSzOptions` struct | golang/nats-server/server/monitor.go:2928 | PARTIAL | — | Most options not parsed from query string; handler builds static JSZ response |
| `HealthzOptions` struct | golang/nats-server/server/monitor.go:2943 | MISSING | — | .NET /healthz endpoint does not parse any options; returns static "ok" |
| `ProfilezOptions` struct | golang/nats-server/server/monitor.go:2956 | PARTIAL | src/NATS.Server/Monitoring/PprofHandler.cs:24 | Only `seconds` duration from CPU profile path; no `name` or `debug` level routing |
| `IpqueueszOptions` struct | golang/nats-server/server/monitor.go:2963 | MISSING | — | /ipqueuesz endpoint not implemented |
| `RaftzOptions` struct | golang/nats-server/server/monitor.go:2969 | MISSING | — | /raftz endpoint not implemented |
| `StreamDetail` struct | golang/nats-server/server/monitor.go:2975 | MISSING | — | JSZ stream detail not ported |
| `RaftGroupDetail` struct | golang/nats-server/server/monitor.go:2991 | MISSING | — | RAFT group detail not ported |
| `AccountDetail` struct | golang/nats-server/server/monitor.go:2996 | MISSING | — | JSZ per-account detail not ported |
| `MetaSnapshotStats` struct | golang/nats-server/server/monitor.go:3003 | MISSING | — | RAFT meta snapshot stats not ported |
| `MetaClusterInfo` struct | golang/nats-server/server/monitor.go:3011 | MISSING | — | RAFT meta cluster info not ported (referenced in JetStreamVarz.Meta) |
| `JSInfo` struct | golang/nats-server/server/monitor.go:3023 | PARTIAL | src/NATS.Server/Monitoring/JszHandler.cs:39 | Go JSInfo has JetStreamStats embedded, ID, Now, Disabled, Config, Limits, Streams, StreamsLeader, Consumers, ConsumersLeader, Messages, Bytes, Meta, AccountDetails, Total; .NET JszResponse has simplified fields with different JSON names (`api_total`/`api_errors` instead of nested `api`) |
| `HealthStatus` struct | golang/nats-server/server/monitor.go:3408 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:9 | Added structured health DTO with Go-style JSON fields (`status`, `status_code`, `error`, `errors`) and updated `/healthz` to return this shape |
| `HealthzError` struct | golang/nats-server/server/monitor.go:3415 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:30 | Added per-check error DTO with `type` and `error` fields |
| `HealthZErrorType` type | golang/nats-server/server/monitor.go:3423 | PORTED | src/NATS.Server/Monitoring/Healthz.cs:44 | Added health error classification enum with JSON string serialization |
| `ExpvarzStatus` struct | golang/nats-server/server/monitor.go:4019 | MISSING | — | /expvarz endpoint not implemented |
| `ProfilezStatus` struct | golang/nats-server/server/monitor.go:4043 | MISSING | — | No structured response; CPU profile endpoint returns raw bytes |
| `RaftzGroup` struct | golang/nats-server/server/monitor.go:4086 | MISSING | — | /raftz endpoint not implemented |
| `RaftzGroupPeer` struct | golang/nats-server/server/monitor.go:4114 | MISSING | — | /raftz endpoint not implemented |
| `RaftzStatus` type | golang/nats-server/server/monitor.go:4121 | MISSING | — | /raftz endpoint not implemented |
| `IpqueueszStatusIPQ` struct | golang/nats-server/server/monitor.go:1162 | MISSING | — | /ipqueuesz endpoint not implemented |
| `IpqueueszStatus` type | golang/nats-server/server/monitor.go:1167 | MISSING | — | /ipqueuesz endpoint not implemented |
---
### monitor.go — Methods and Functions
| Go Symbol | Go File:Line | Status | .NET Equivalent | Notes |
|-----------|:-------------|--------|:----------------|-------|
| `newSubsDetailList()` | golang/nats-server/server/monitor.go:176 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:189 | Implemented inline in BuildConnInfo |
| `newSubsList()` | golang/nats-server/server/monitor.go:184 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:180 | Implemented inline in BuildConnInfo |
| `Server.Connz()` | golang/nats-server/server/monitor.go:193 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:12 | `ConnzHandler.HandleConnz()` |
| `ConnInfo.fill()` | golang/nats-server/server/monitor.go:556 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:144 | `BuildConnInfo()` static method |
| `createProxyInfo()` | golang/nats-server/server/monitor.go:609 | PARTIAL | src/NATS.Server/Monitoring/ConnzHandler.cs:378 | .NET now emits structured `ProxyInfo` (`proxy.key`) and snapshots it for closed clients, but key derivation is currently based on `proxy:` username prefix rather than Go's internal `client.proxyKey` source. |
| `makePeerCerts()` | golang/nats-server/server/monitor.go:616 | PORTED | src/NATS.Server/Monitoring/TlsPeerCertMapper.cs:8 | Added peer-cert mapping helper computing subject + SHA256 hashes and wired for both open and closed connz snapshots |
| `client.getRTT()` | golang/nats-server/server/monitor.go:629 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:321 | `FormatRtt()` formats from stored `client.Rtt` |
| `decodeBool()` | golang/nats-server/server/monitor.go:647 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:267 | Inline query param parsing in ParseQueryParams |
| `decodeUint64()` | golang/nats-server/server/monitor.go:661 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:291 | Inline query param parsing |
| `decodeInt()` | golang/nats-server/server/monitor.go:675 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:285 | Inline query param parsing |
| `decodeState()` | golang/nats-server/server/monitor.go:689 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:275 | State parsing in ParseQueryParams |
| `decodeSubs()` | golang/nats-server/server/monitor.go:709 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:266 | Subs + subs-detail parsing |
| `Server.HandleConnz()` | golang/nats-server/server/monitor.go:718 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs:70 | Mapped at `/connz` route |
| `Server.Routez()` | golang/nats-server/server/monitor.go:830 | PARTIAL | src/NATS.Server/Monitoring/RoutezHandler.cs:13 | Go returns full Routez struct with per-route RouteInfo; .NET returns only count |
| `Server.HandleRoutez()` | golang/nats-server/server/monitor.go:904 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:76 | Endpoint mapped, but subs/subscriptions_detail query params not parsed |
| `newSubDetail()` | golang/nats-server/server/monitor.go:973 | PORTED | src/NATS.Server/Monitoring/SubszHandler.cs:51 | Implemented inline |
| `newClientSubDetail()` | golang/nats-server/server/monitor.go:981 | PORTED | src/NATS.Server/Monitoring/ConnzHandler.cs:189 | Implemented inline |
| `Server.Subsz()` | golang/nats-server/server/monitor.go:992 | PORTED | src/NATS.Server/Monitoring/SubszHandler.cs:12 | `SubszHandler.HandleSubsz()` |
| `Server.HandleSubsz()` | golang/nats-server/server/monitor.go:1095 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs:91 | Mapped at `/subz` and `/subscriptionsz` |
| `Server.HandleStacksz()` | golang/nats-server/server/monitor.go:1142 | MISSING | — | No .NET /stacksz endpoint |
| `Server.Ipqueuesz()` | golang/nats-server/server/monitor.go:1169 | MISSING | — | No .NET /ipqueuesz endpoint |
| `Server.HandleIPQueuesz()` | golang/nats-server/server/monitor.go:1194 | MISSING | — | No .NET /ipqueuesz endpoint |
| `Server.updateJszVarz()` | golang/nats-server/server/monitor.go:1555 | PARTIAL | src/NATS.Server/Monitoring/VarzHandler.cs:125 | Partially in VarzHandler; missing Meta/Limits/Config update logic |
| `Server.Varz()` | golang/nats-server/server/monitor.go:1580 | PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:30 | `VarzHandler.HandleVarzAsync()` |
| `Server.createVarz()` | golang/nats-server/server/monitor.go:1603 | PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:67 | Logic inline in HandleVarzAsync |
| `urlsToStrings()` | golang/nats-server/server/monitor.go:1756 | NOT_APPLICABLE | — | Helper for URL slice conversion; .NET uses LINQ Select |
| `Server.updateVarzConfigReloadableFields()` | golang/nats-server/server/monitor.go:1768 | PARTIAL | src/NATS.Server/Monitoring/VarzHandler.cs:67 | Config fields set at construction; no reload tracking; missing TLSCertNotAfter for cluster/gateway/leafnode/mqtt/websocket |
| `Server.updateVarzRuntimeFields()` | golang/nats-server/server/monitor.go:1840 | PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:67 | Runtime fields computed each request |
| `getPinnedCertsAsSlice()` | golang/nats-server/server/monitor.go:1825 | PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:173 | Present for MQTT; no websocket equivalent |
| `Server.HandleVarz()` | golang/nats-server/server/monitor.go:1946 | PORTED | src/NATS.Server/Monitoring/MonitorServer.cs:64 | Mapped at `/varz` |
| `Server.HandleRoot()` | golang/nats-server/server/monitor.go:1480 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:47 | .NET returns JSON array of endpoint names; Go returns HTML page with links and NATS logo |
| `myUptime()` | golang/nats-server/server/monitor.go:1440 | PORTED | src/NATS.Server/Monitoring/VarzHandler.cs:183 | `FormatUptime()` and `FormatDuration()` — same format logic |
| `tlsCertNotAfter()` | golang/nats-server/server/monitor.go:1463 | PARTIAL | src/NATS.Server/Monitoring/VarzHandler.cs:53 | .NET only reads cert for client TLS; Go reads for all subsystem TLS configs |
| `Server.Gatewayz()` | golang/nats-server/server/monitor.go:2054 | PARTIAL | src/NATS.Server/Monitoring/GatewayzHandler.cs:13 | Go returns full outbound/inbound gateway maps; .NET returns only counts |
| `getMonitorGWOptions()` | golang/nats-server/server/monitor.go:2090 | MISSING | — | No options parsing in .NET GatewayzHandler |
| `Server.createOutboundsRemoteGatewayz()` | golang/nats-server/server/monitor.go:2108 | MISSING | — | No outbound gateway detail |
| `createOutboundRemoteGatewayz()` | golang/nats-server/server/monitor.go:2138 | MISSING | — | No outbound gateway detail |
| `createOutboundAccountsGatewayz()` | golang/nats-server/server/monitor.go:2163 | MISSING | — | No gateway account interest detail |
| `createAccountOutboundGatewayz()` | golang/nats-server/server/monitor.go:2192 | MISSING | — | No gateway account interest detail |
| `Server.createInboundsRemoteGatewayz()` | golang/nats-server/server/monitor.go:2233 | MISSING | — | No inbound gateway detail |
| `createInboundAccountsGatewayz()` | golang/nats-server/server/monitor.go:2265 | MISSING | — | No gateway account interest detail |
| `createInboundAccountGatewayz()` | golang/nats-server/server/monitor.go:2292 | MISSING | — | No gateway account interest detail |
| `Server.HandleGatewayz()` | golang/nats-server/server/monitor.go:2306 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:81 | Endpoint mapped; query params (gw_name, accs, acc_name, subs) not parsed |
| `Server.Leafz()` | golang/nats-server/server/monitor.go:2384 | PARTIAL | src/NATS.Server/Monitoring/LeafzHandler.cs:13 | Go returns full LeafInfo per leafnode; .NET returns only count |
| `Server.HandleLeafz()` | golang/nats-server/server/monitor.go:2445 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:86 | Endpoint mapped; `subs` and `acc` query params not parsed |
| `Server.AccountStatz()` | golang/nats-server/server/monitor.go:2484 | PARTIAL | src/NATS.Server/Monitoring/AccountzHandler.cs:27 | .NET BuildStats() returns totals; no per-account `AccountStat` detail or `accounts` / `include_unused` filter |
| `Server.HandleAccountStatz()` | golang/nats-server/server/monitor.go:2516 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:106 | Endpoint mapped at `/accstatz`; `unused` query param not parsed |
| `ResponseHandler()` | golang/nats-server/server/monitor.go:2542 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:47 | .NET uses ASP.NET Core Results.Ok(); no JSONP callback support |
| `handleResponse()` | golang/nats-server/server/monitor.go:2548 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:47 | No custom status code support from handler level; no JSONP support |
| `ClosedState.String()` | golang/nats-server/server/monitor.go:2565 | PORTED | src/NATS.Server/Monitoring/Connz.cs:511 | `ClosedReasonHelper.ToReasonString()` |
| `Server.HandleAccountz()` | golang/nats-server/server/monitor.go:2718 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:101 | Endpoint mapped; `acc` query param for account detail not parsed |
| `Server.Accountz()` | golang/nats-server/server/monitor.go:2735 | PARTIAL | src/NATS.Server/Monitoring/AccountzHandler.cs:14 | Go returns full Accountz with optional AccountInfo detail; .NET returns simplified list |
| `newExtServiceLatency()` | golang/nats-server/server/monitor.go:2652 | MISSING | — | JWT service latency detail not ported |
| `newExtImport()` | golang/nats-server/server/monitor.go:2759 | MISSING | — | JWT import detail not ported |
| `Server.accountInfo()` | golang/nats-server/server/monitor.go:2786 | MISSING | — | Full account info with exports/imports/mappings/JWT not ported |
| `Server.JszAccount()` | golang/nats-server/server/monitor.go:3142 | MISSING | — | Per-account JSZ detail not ported |
| `Server.raftNodeToClusterInfo()` | golang/nats-server/server/monitor.go:3162 | MISSING | — | RAFT cluster info helper not ported |
| `Server.Jsz()` | golang/nats-server/server/monitor.go:3180 | PARTIAL | src/NATS.Server/Monitoring/JszHandler.cs:16 | Go Jsz() has full JSInfo with accounts/streams/consumers/meta; .NET JszHandler.Build() returns simplified flat fields |
| `Server.accountDetail()` | golang/nats-server/server/monitor.go:3041 | MISSING | — | Per-account stream/consumer detail not ported |
| `Server.HandleJsz()` | golang/nats-server/server/monitor.go:3334 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:111 | Endpoint mapped; all query params (accounts, streams, consumers, config, offset, limit, leader-only, raft, stream-leader-only) not parsed |
| `Server.HandleHealthz()` | golang/nats-server/server/monitor.go:3478 | PARTIAL | src/NATS.Server/Monitoring/MonitorServer.cs:59 | Endpoint mapped and now returns structured `HealthStatus`; Go JetStream-aware/dependency checks are still missing |
| `Server.healthz()` | golang/nats-server/server/monitor.go:3537 | MISSING | — | Full healthz logic with JS stream/consumer recovery checks not ported |
| `Server.Healthz()` | golang/nats-server/server/monitor.go:4014 | MISSING | — | Public Healthz() method not ported |
| `Server.expvarz()` | golang/nats-server/server/monitor.go:4024 | MISSING | — | /expvarz endpoint not implemented |
| `Server.profilez()` | golang/nats-server/server/monitor.go:4048 | PARTIAL | src/NATS.Server/Monitoring/PprofHandler.cs:24 | .NET CaptureCpuProfile() captures process metrics as JSON; Go uses pprof binary format |
| `Server.HandleRaftz()` | golang/nats-server/server/monitor.go:4123 | MISSING | — | /raftz endpoint not implemented |
| `Server.Raftz()` | golang/nats-server/server/monitor.go:4145 | MISSING | — | RAFT node status reporting not ported |
---
## Keeping This File Updated
After porting work is completed:
1. **Update status**: Change `MISSING → PORTED` or `PARTIAL → PORTED` for each item completed
2. **Add .NET path**: Fill in the ".NET Equivalent" column with the actual file:line
3. **Re-count LOC**: Update the LOC numbers in `stillmissing.md`:
```bash
# Re-count .NET source LOC for this module
find src/NATS.Server/Monitoring/ -name '*.cs' -type f -exec cat {} + | wc -l
# Re-count .NET test LOC for this module
find tests/NATS.Server.Tests/Monitoring/ -name '*.cs' -type f -exec cat {} + | wc -l
```
4. **Add a changelog entry** below with date and summary of what was ported
5. **Update the parity DB** if new test mappings were created:
```bash
sqlite3 docs/test_parity.db "INSERT INTO test_mappings (go_test_id, dotnet_test_id, confidence, notes) VALUES (?, ?, 'manual', 'ported in YYYY-MM-DD session')"
```
## Change Log
| Date | Change | By |
|------|--------|----|
| 2026-02-26 | Improved connz parity for `ConnInfo`/`ProxyInfo`: added Go-style `stalls`, `jwt`, `issuer_key`, `name_tag`, `tags`, and structured `proxy` output; wired JWT/tag decode and closed-conn snapshot fields; added focused monitoring parity tests. | codex |
| 2026-02-25 | Ported monitoring TLS peer-cert parity slice: added `TLSPeerCert` model and `tls_peer_certs` JSON output with SHA256 fields, wired open/closed conn snapshots via `TlsPeerCertMapper`, and added focused tests (`TlsPeerCertParityTests`). | codex |
| 2026-02-25 | File created with LLM analysis instructions | auto |
| 2026-02-25 | Full gap inventory populated: 63 PORTED, 42 PARTIAL, 61 MISSING, 3 NOT_APPLICABLE, 0 DEFERRED (169 total rows) | claude-sonnet-4-6 |