Skip to content

Commit

Permalink
Fix uptime percentage per event type on node events page (#188)
Browse files Browse the repository at this point in the history
* Fix uptime percentage per event type on node events page

Addresses more of #181

Signed-off-by: Dave Thaler <[email protected]>

* Address coderabbit feedback

Signed-off-by: Dave Thaler <[email protected]>

---------

Signed-off-by: Dave Thaler <[email protected]>
  • Loading branch information
dthaler authored Nov 6, 2024
1 parent b2352a8 commit 3e30082
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 21 deletions.
30 changes: 22 additions & 8 deletions OrcanodeMonitor/Core/Fetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Newtonsoft.Json.Linq;
using System.Threading.Channels;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.Extensions.Logging;

namespace OrcanodeMonitor.Core
{
Expand Down Expand Up @@ -792,26 +793,39 @@ public static List<OrcanodeEvent> GetEvents(OrcanodeMonitorContext context, int
return orcanodeEvents;
}

private static List<OrcanodeEvent> AddOlderEvent(List<OrcanodeEvent> orcanodeEvents, List<OrcanodeEvent> events, DateTime since, string type)
{
OrcanodeEvent? olderEvent = events.Where(e => (e.DateTimeUtc < since) && (e.Type == type)).FirstOrDefault();
if (olderEvent == null)
{
return orcanodeEvents;
}
else
{
return orcanodeEvents.Append(olderEvent).OrderByDescending(e => e.DateTimeUtc).ToList();
}
}

/// <summary>
/// Get recent events for a node
/// </summary>
/// <param name="context"></param>
/// <param name="id">ID of node to get events for</param>
/// <param name="since">Time to get events since</param>
/// <param name="eventType">Type of events to get, or empty string for all</param>
/// <param name="logger"></param>
/// <returns>null on error, or list of events on success</returns>
public static List<OrcanodeEvent>? GetRecentEventsForNode(OrcanodeMonitorContext context, string id, DateTime since, string eventType, ILogger logger)
public static List<OrcanodeEvent>? GetRecentEventsForNode(OrcanodeMonitorContext context, string id, DateTime since, ILogger logger)
{
try
{
List<OrcanodeEvent> events = context.OrcanodeEvents.Where(e => e.OrcanodeId == id && (eventType.IsNullOrEmpty() || eventType == e.Type)).OrderByDescending(e => e.DateTimeUtc).ToList();
List<OrcanodeEvent> events = context.OrcanodeEvents.Where(e => e.OrcanodeId == id).OrderByDescending(e => e.DateTimeUtc).ToList();
List<OrcanodeEvent> orcanodeEvents = events.Where(e => e.DateTimeUtc >= since).ToList();
OrcanodeEvent? olderEvent = events.Where(e => (e.DateTimeUtc < since)).FirstOrDefault();
if (olderEvent != null)
{
return orcanodeEvents.Append(olderEvent).ToList();
}

// Add one older event per type we can filter on.
orcanodeEvents = AddOlderEvent(orcanodeEvents, events, since, OrcanodeEventTypes.HydrophoneStream);
orcanodeEvents = AddOlderEvent(orcanodeEvents, events, since, OrcanodeEventTypes.DataplicityConnection);
orcanodeEvents = AddOlderEvent(orcanodeEvents, events, since, OrcanodeEventTypes.MezmoLogging);

return orcanodeEvents;
} catch (Exception ex)
{
Expand Down
15 changes: 9 additions & 6 deletions OrcanodeMonitor/Models/Orcanode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,17 +393,20 @@ public string OrcasoundOnlineStatusString {

public OrcanodeIftttDTO ToIftttDTO() => new OrcanodeIftttDTO(ID, DisplayName);

private static bool IsStateOnline(string state) => (state == "up" || state == "Online");

/// <summary>
/// Calculates the uptime percentage for a node based on its events since a specified date.
/// Only events of type "hydrophone stream" are considered when calculating uptime.
/// These events indicate the actual streaming status of the node's hydrophone.
/// Only events matching the specified type are considered when calculating uptime.
/// The uptime is calculated based on the online/offline state indicated by these events.
/// </summary>
/// <param name="orcanodeId">The ID of the node to calculate uptime for</param>
/// <param name="events">List of node events</param>
/// <param name="since">The start date for uptime calculation</param>
/// <param name="type">The specific event type to calculate uptime for (e.g., "hydrophone stream")</param>
/// <returns>Uptime percentage as an integer between 0 and 100</returns>
/// <exception cref="ArgumentException">Thrown when orcanodeId is null or empty</exception>
public static int GetUptimePercentage(string orcanodeId, List<OrcanodeEvent> events, DateTime since)
public static int GetUptimePercentage(string orcanodeId, List<OrcanodeEvent> events, DateTime since, string type)
{
if (string.IsNullOrEmpty(orcanodeId))
{
Expand All @@ -425,7 +428,7 @@ public static int GetUptimePercentage(string orcanodeId, List<OrcanodeEvent> eve

// Get events sorted by date to ensure correct chronological processing.
var nodeEvents = events
.Where(e => e.OrcanodeId == orcanodeId && e.Type == "hydrophone stream")
.Where(e => e.OrcanodeId == orcanodeId && e.Type == type)
.OrderBy(e => e.DateTimeUtc)
.ToList();

Expand All @@ -439,7 +442,7 @@ public static int GetUptimePercentage(string orcanodeId, List<OrcanodeEvent> eve
continue;
}
DateTime current = e.DateTimeUtc;
if (lastValue == OnlineString)
if (IsStateOnline(lastValue))
{
up += (current - start);
}
Expand All @@ -453,7 +456,7 @@ public static int GetUptimePercentage(string orcanodeId, List<OrcanodeEvent> eve

// Account for the reminder of the time until now.
DateTime now = DateTime.UtcNow;
if (lastValue == OnlineString)
if (IsStateOnline(lastValue))
{
up += now - start;
}
Expand Down
4 changes: 2 additions & 2 deletions OrcanodeMonitor/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private string GetTextColor(OrcanodeOnlineStatus status)

private DateTime SinceTime => DateTime.UtcNow.AddDays(-7);

public int GetUptimePercentage(Orcanode node) => Orcanode.GetUptimePercentage(node.ID, _events, SinceTime);
public int GetUptimePercentage(Orcanode node) => Orcanode.GetUptimePercentage(node.ID, _events, SinceTime, OrcanodeEventTypes.HydrophoneStream);

public string NodeUptimePercentageBackgroundColor(Orcanode node)
{
Expand Down Expand Up @@ -146,7 +146,7 @@ public async Task OnGetAsync()

// Fetch events for uptime computation.
var events = await _databaseContext.OrcanodeEvents.ToListAsync();
_events = events.Where(e => e.Type == "hydrophone stream").ToList();
_events = events.Where(e => e.Type == OrcanodeEventTypes.HydrophoneStream).ToList();
}
}
}
9 changes: 4 additions & 5 deletions OrcanodeMonitor/Pages/NodeEvents.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public class NodeEventsModel : PageModel
[BindProperty]
public string TimePeriod { get; set; } = "week"; // Default to 'week'
[BindProperty]
public string EventType { get; set; } = "all"; // Default to 'all'
public string EventType { get; set; } = OrcanodeEventTypes.All; // Default to 'all'

private DateTime SinceTime => (TimePeriod == "week") ? DateTime.UtcNow.AddDays(-7) : DateTime.UtcNow.AddMonths(-1);
private List<OrcanodeEvent> _events;
public List<OrcanodeEvent> RecentEvents => _events;
public int UptimePercentage => Orcanode.GetUptimePercentage(_nodeId, _events, SinceTime);
public int UptimePercentage => Orcanode.GetUptimePercentage(_nodeId, _events, SinceTime, (EventType == OrcanodeEventTypes.All) ? OrcanodeEventTypes.HydrophoneStream : EventType);

public NodeEventsModel(OrcanodeMonitorContext context, ILogger<NodeEventsModel> logger)
{
Expand All @@ -36,8 +36,7 @@ public NodeEventsModel(OrcanodeMonitorContext context, ILogger<NodeEventsModel>

private void FetchEvents(ILogger logger)
{
string eventType = (EventType == "all") ? string.Empty : EventType;
_events = Fetcher.GetRecentEventsForNode(_databaseContext, _nodeId, SinceTime, eventType, logger) ?? new List<OrcanodeEvent>();
_events = Fetcher.GetRecentEventsForNode(_databaseContext, _nodeId, SinceTime, logger).Where(e => e.Type == EventType || EventType == OrcanodeEventTypes.All).ToList() ?? new List<OrcanodeEvent>();

Check warning on line 39 in OrcanodeMonitor/Pages/NodeEvents.cshtml.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'source' in 'IEnumerable<OrcanodeEvent> Enumerable.Where<OrcanodeEvent>(IEnumerable<OrcanodeEvent> source, Func<OrcanodeEvent, bool> predicate)'.

Check warning on line 39 in OrcanodeMonitor/Pages/NodeEvents.cshtml.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'source' in 'IEnumerable<OrcanodeEvent> Enumerable.Where<OrcanodeEvent>(IEnumerable<OrcanodeEvent> source, Func<OrcanodeEvent, bool> predicate)'.

Check warning on line 39 in OrcanodeMonitor/Pages/NodeEvents.cshtml.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'source' in 'IEnumerable<OrcanodeEvent> Enumerable.Where<OrcanodeEvent>(IEnumerable<OrcanodeEvent> source, Func<OrcanodeEvent, bool> predicate)'.
}

public void OnGet(string id)
Expand Down Expand Up @@ -66,7 +65,7 @@ public IActionResult OnPost(string timePeriod, string eventType, string id)
_logger.LogWarning($"Invalid time range selected: {timePeriod}");
return BadRequest("Invalid time range");
}
if (eventType != "all" && eventType != OrcanodeEventTypes.HydrophoneStream && eventType != OrcanodeEventTypes.MezmoLogging && eventType != OrcanodeEventTypes.DataplicityConnection)
if (eventType != OrcanodeEventTypes.All && eventType != OrcanodeEventTypes.HydrophoneStream && eventType != OrcanodeEventTypes.MezmoLogging && eventType != OrcanodeEventTypes.DataplicityConnection)
{
_logger.LogWarning($"Invalid event type selected: {eventType}");
return BadRequest("Invalid event type");
Expand Down

0 comments on commit 3e30082

Please sign in to comment.