Skip to content

Commit c7869a3

Browse files
committed
Fix RTT value propagation and logging
- Updated OutageDetectionService to ensure LastRttMs is updated - Modified StatusController to return full API response - Adjusted logging configuration - Verified RTT value tracking across backend services 🐛 Resolves issue with RTT value display on dashboard 🔍 Improved logging for monitoring services
1 parent 5476df3 commit c7869a3

File tree

4 files changed

+127
-2
lines changed

4 files changed

+127
-2
lines changed

ThingConnect.Pulse.Server/Controllers/StatusController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task<ActionResult<LiveStatusItemDto>> GetLiveStatusAsync(
3232
{
3333
try
3434
{
35-
_logger.LogInformation("Getting live status - group: {Group}, search: {Search}, page: {Page}, pageSize: {PageSize}",
35+
_logger.LogInformation("Getting live status - group: {Group}, search: {Search}",
3636
group, search);
3737

3838
var result = await _statusService.GetLiveStatusAsync(group, search);

ThingConnect.Pulse.Server/Services/Monitoring/OutageDetectionService.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,20 @@ private async Task SaveCheckResultAsync(CheckResult result, CancellationToken ca
519519
};
520520

521521
_context.CheckResultsRaw.Add(rawResult);
522+
523+
// Update LastRttMs for successful probes
524+
if (result.Status == UpDown.up && result.RttMs.HasValue)
525+
{
526+
Data.Endpoint? endpoint = await _context.Endpoints.FindAsync([result.EndpointId], cancellationToken);
527+
if (endpoint != null)
528+
{
529+
endpoint.LastRttMs = result.RttMs.Value;
530+
_logger.LogInformation(
531+
"Updated LastRttMs for endpoint {EndpointId} to {RttMs}ms",
532+
result.EndpointId, result.RttMs.Value);
533+
}
534+
}
535+
522536
await _context.SaveChangesAsync(cancellationToken);
523537
}
524538

@@ -539,9 +553,28 @@ public async Task SaveCheckResultsBatchAsync(IEnumerable<CheckResult> results, C
539553
if (rawResults.Count > 0)
540554
{
541555
_context.CheckResultsRaw.AddRange(rawResults);
556+
557+
// Update LastRttMs for successful probes
558+
var successfulRttResults = results
559+
.Where(r => r.Status == UpDown.up && r.RttMs.HasValue)
560+
.ToList();
561+
562+
foreach (var result in successfulRttResults)
563+
{
564+
Data.Endpoint? endpoint = await _context.Endpoints.FindAsync([result.EndpointId], cancellationToken);
565+
if (endpoint != null)
566+
{
567+
endpoint.LastRttMs = result.RttMs.Value;
568+
_logger.LogInformation(
569+
"Updated LastRttMs for endpoint {EndpointId} to {RttMs}ms",
570+
result.EndpointId, result.RttMs.Value);
571+
}
572+
}
573+
542574
await _context.SaveChangesAsync(cancellationToken);
543575

544-
_logger.LogDebug("Batch saved {Count} check results", rawResults.Count);
576+
_logger.LogDebug("Batch saved {Count} check results, updated {RttCount} RTT values",
577+
rawResults.Count, successfulRttResults.Count);
545578
}
546579
}
547580
}

ThingConnect.Pulse.Server/Services/StatusService.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ public async Task<List<LiveStatusItemDto>> GetLiveStatusAsync(string? group, str
8888
? sparklineData[endpoint.Id]
8989
: new List<SparklinePoint>();
9090

91+
_logger.LogInformation(
92+
"Endpoint {EndpointName}: Status = {Status}, LastRttMs = {RttMs}, LastChangeTs = {LastChangeTs}",
93+
endpoint.Name, status, endpoint.LastRttMs, endpoint.LastChangeTs);
94+
9195
items.Add(new LiveStatusItemDto
9296
{
9397
Endpoint = MapToEndpointDto(endpoint),

docs/rtt-tracing.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# RTT Value Tracing and Investigation
2+
3+
## RTT Journey Flow Diagram
4+
5+
```mermaid
6+
graph TD
7+
A[Probe Service] -->|Measure RTT| B[CheckResult]
8+
B -->|RttMs| C[MonitoringBackgroundService]
9+
C -->|Update Endpoint| D[OutageDetectionService]
10+
D -->|Persist LastRttMs| E[StatusService]
11+
E -->|Serialize RTT| F[API Controller]
12+
F -->|Response| G[Frontend Service]
13+
G -->|Render| H[Frontend Components]
14+
15+
subgraph Potential Failure Points
16+
A -->|Null/Zero RTT| B
17+
B -->|Null RttMs| C
18+
C -->|Ignore Null RTT| D
19+
D -->|Skip Update| E
20+
E -->|Empty RTT| F
21+
F -->|Omit RTT| G
22+
G -->|Display Placeholder| H
23+
end
24+
```
25+
26+
## RTT Tracing Points
27+
28+
### 1. Probe Service (`ProbeService.cs`)
29+
- **Probe Types**:
30+
- ICMP: Uses `reply.RoundtripTime`
31+
- TCP: Uses `stopwatch.ElapsedMilliseconds`
32+
- HTTP: Uses `stopwatch.ElapsedMilliseconds`
33+
- **Failure Handling**:
34+
- Sets `RttMs` to null on probe failures
35+
- Different measurement methods may introduce inconsistencies
36+
37+
### 2. Background Monitoring Service
38+
- Logs RTT with trace:
39+
```csharp
40+
_logger.LogTrace("Probed endpoint {EndpointId} ({Name}): {Status} in {RttMs}ms")
41+
```
42+
- Converts null RTT to "N/A"
43+
44+
### 3. Outage Detection Service
45+
- Copies `result.RttMs` to new records
46+
- Potential loss point if RTT is null
47+
48+
### 4. Status Service
49+
- Uses `endpoint.LastRttMs` to populate status responses
50+
- May return null/empty RTT
51+
52+
### 5. Frontend Service and Components
53+
- Uses optional chaining and nullish coalescing
54+
- Handles null RTT with placeholders ('-')
55+
56+
## Investigation Steps
57+
58+
### 1. Probe Measurement Verification
59+
- [ ] Compare RTT measurements across different probe types
60+
- [ ] Add detailed logging in `ProbeService`
61+
- [ ] Verify stopwatch and `RoundtripTime` calculations
62+
63+
### 2. Null Value Propagation Analysis
64+
- [ ] Trace null RTT through each service layer
65+
- [ ] Add comprehensive logging
66+
- [ ] Validate null handling in serialization
67+
68+
### 3. API Contract Validation
69+
- [ ] Inspect API response DTOs
70+
- [ ] Check JSON serialization of RTT values
71+
- [ ] Verify optional/nullable field handling
72+
73+
### 4. Frontend Parsing Investigation
74+
- [ ] Review TypeScript type definitions
75+
- [ ] Validate RTT parsing in API services
76+
- [ ] Test display logic for various RTT scenarios
77+
78+
### 5. Comprehensive Test Scenarios
79+
- [ ] Successful probe with non-zero RTT
80+
- [ ] Failed probe (null RTT)
81+
- [ ] Edge cases: zero, very low, very high RTT values
82+
- [ ] Multiple probe type comparisons
83+
84+
## Potential Improvement Recommendations
85+
- Standardize RTT measurement across probe types
86+
- Implement consistent null/zero RTT handling
87+
- Add more granular logging and tracing
88+
- Create comprehensive test suite for RTT propagation

0 commit comments

Comments
 (0)