Skip to content

Commit

Permalink
Add event type filter on node events page (#187)
Browse files Browse the repository at this point in the history
* Add event type filter on node events page

Fixes #183

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

* Address coderabbit feedback

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

* Fix form

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

---------

Signed-off-by: Dave Thaler <[email protected]>
  • Loading branch information
dthaler authored Nov 5, 2024
1 parent 1ad2744 commit b2352a8
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 28 deletions.
13 changes: 7 additions & 6 deletions OrcanodeMonitor/Core/Fetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -798,13 +798,14 @@ public static List<OrcanodeEvent> GetEvents(OrcanodeMonitorContext context, int
/// <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, ILogger logger)
public static List<OrcanodeEvent>? GetRecentEventsForNode(OrcanodeMonitorContext context, string id, DateTime since, string eventType, ILogger logger)
{
try
{
List<OrcanodeEvent> events = context.OrcanodeEvents.Where(e => e.OrcanodeId == id).OrderByDescending(e => e.DateTimeUtc).ToList();
List<OrcanodeEvent> events = context.OrcanodeEvents.Where(e => e.OrcanodeId == id && (eventType.IsNullOrEmpty() || eventType == e.Type)).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)
Expand All @@ -828,25 +829,25 @@ public static void AddOrcanodeEvent(OrcanodeMonitorContext context, Orcanode nod
private static void AddDataplicityConnectionStatusEvent(OrcanodeMonitorContext context, Orcanode node)
{
string value = node.DataplicityConnectionStatus.ToString();
AddOrcanodeEvent(context, node, "dataplicity connection", value);
AddOrcanodeEvent(context, node, OrcanodeEventTypes.DataplicityConnection, value);
}

private static void AddDataplicityAgentUpgradeStatusChangeEvent(OrcanodeMonitorContext context, Orcanode node)
{
string value = node.DataplicityUpgradeStatus.ToString();
AddOrcanodeEvent(context, node, "agent upgrade status", value);
AddOrcanodeEvent(context, node, OrcanodeEventTypes.AgentUpgradeStatus, value);
}

private static void AddDiskCapacityChangeEvent(OrcanodeMonitorContext context, Orcanode node)
{
string value = string.Format("{0}G", node.DiskCapacityInGigs);
AddOrcanodeEvent(context, node, "SD card size", value);
AddOrcanodeEvent(context, node, OrcanodeEventTypes.SDCardSize, value);
}

private static void AddHydrophoneStreamStatusEvent(OrcanodeMonitorContext context, Orcanode node)
{
string value = node.OrcasoundOnlineStatusString;
AddOrcanodeEvent(context, node, "hydrophone stream", value);
AddOrcanodeEvent(context, node, OrcanodeEventTypes.HydrophoneStream, value);
}

/// <summary>
Expand Down
16 changes: 8 additions & 8 deletions OrcanodeMonitor/Core/MezmoFetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ private static int MezmoLogSeconds
/// Fetch string content from a Mezmo URL.
/// </summary>
/// <param name="url">URL to get content from</param>
/// <param name="logger"></param>
/// <returns>String content. An empty string may mean empty content or an HTTP error.</returns>
public async static Task<string?> GetMezmoDataAsync(string url)
public async static Task<string?> GetMezmoDataAsync(string url, ILogger logger)
{
try
{
string? service_key = Environment.GetEnvironmentVariable("MEZMO_SERVICE_KEY");
if (string.IsNullOrEmpty(service_key))
{
Console.Error.WriteLine($"MEZMO_SERVICE_KEY not configured");
logger.LogError($"MEZMO_SERVICE_KEY not configured");
return null;
}

Expand All @@ -58,8 +59,7 @@ private static int MezmoLogSeconds
}
catch (Exception ex)
{
string msg = ex.ToString();
Console.Error.WriteLine($"Exception in GetMezmoDataAsync: {msg}");
logger.LogError(ex, "Exception in GetMezmoDataAsync");
return null;
}
}
Expand All @@ -82,7 +82,7 @@ private static int MezmoLogSeconds
}
int from = to - MezmoLogSeconds;
string url = $"{_mezmoLogUrl}?from={from}&to={to}&hosts={node.S3NodeName}";
string? jsonString = await GetMezmoDataAsync(url);
string? jsonString = await GetMezmoDataAsync(url, logger);
if (jsonString == null)
{
logger.LogDebug($"Failed to fetch Mezmo logs for {node.S3NodeName} between {from} and {to}");
Expand Down Expand Up @@ -126,7 +126,7 @@ public async static Task UpdateMezmoHostsAsync(OrcanodeMonitorContext context, I
{
try
{
string? jsonArray = await GetMezmoDataAsync(_mezmoHostsUrl);
string? jsonArray = await GetMezmoDataAsync(_mezmoHostsUrl, logger);
if (jsonArray == null)
{
// Error so do nothing.
Expand Down Expand Up @@ -236,7 +236,7 @@ public async static Task UpdateMezmoViewsAsync(OrcanodeMonitorContext context, I
{
try
{
string? jsonArray = await GetMezmoDataAsync(_mezmoViewsUrl);
string? jsonArray = await GetMezmoDataAsync(_mezmoViewsUrl, logger);
if (jsonArray == null)
{
// Error so do nothing.
Expand Down Expand Up @@ -344,7 +344,7 @@ public async static Task UpdateMezmoDataAsync(OrcanodeMonitorContext context, IL
private static void AddMezmoStatusEvent(OrcanodeMonitorContext context, Orcanode node)
{
string value = node.MezmoStatus.ToString();
Fetcher.AddOrcanodeEvent(context, node, "Mezmo logging", value);
Fetcher.AddOrcanodeEvent(context, node, OrcanodeEventTypes.MezmoLogging, value);
}
}
}
10 changes: 10 additions & 0 deletions OrcanodeMonitor/Models/OrcanodeEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,14 @@ public override string ToString()

#endregion methods
}

public static class OrcanodeEventTypes
{
public const string All = "all";
public const string HydrophoneStream = "hydrophone stream";
public const string MezmoLogging = "Mezmo logging";
public const string DataplicityConnection = "dataplicity connection";
public const string AgentUpgradeStatus = "agent upgrade status";
public const string SDCardSize = "SD card size";
}
}
43 changes: 36 additions & 7 deletions OrcanodeMonitor/Pages/NodeEvents.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,49 @@
<h1 class="display-4">Node Events</h1>
<form method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="eventType" value="@Model.EventType" />
<input type="hidden" name="Id" value="@Model.Id" />
<div role="group" aria-label="Time period selection">
<button type="submit" name="Selected" value="week"
class="btn @(Model.Selected == "week" ? "selected" : "unselected")"
aria-pressed="@(Model.Selected == "week" ? "true" : "false")" >
<button type="submit" name="timePeriod" value="week"
class="btn @(Model.TimePeriod == "week" ? "selected" : "unselected")"
aria-pressed="@(Model.TimePeriod == "week" ? "true" : "false")" >
Past Week
</button>
<button type="submit" name="Selected" value="month"
class="btn @(Model.Selected == "month" ? "selected" : "unselected")"
aria-pressed="@(Model.Selected == "month" ? "true" : "false")">
<button type="submit" name="timePeriod" value="month"
class="btn @(Model.TimePeriod == "month" ? "selected" : "unselected")"
aria-pressed="@(Model.TimePeriod == "month" ? "true" : "false")">
Past Month
</button>
</div>
</form>
</form>
<p/>
<form method="post">
@Html.AntiForgeryToken()
<input type="hidden" name="timePeriod" value="@Model.TimePeriod" />
<input type="hidden" name="Id" value="@Model.Id" />
<div role="group" aria-label="Event type selection">
<button type="submit" name="eventType" value="all"
class="btn @(Model.EventType == "all" ? "selected" : "unselected")"
aria-pressed="@(Model.EventType == "all" ? "true" : "false")">
All
</button>
<button type="submit" name="eventType" value="hydrophone stream"
class="btn @(Model.EventType == "hydrophone stream" ? "selected" : "unselected")"
aria-pressed="@(Model.EventType == "hydrophone stream" ? "true" : "false")">
Hydrophone Stream
</button>
<button type="submit" name="eventType" value="dataplicity connection"
class="btn @(Model.EventType == "dataplicity connection" ? "selected" : "unselected")"
aria-pressed="@(Model.EventType == "dataplicity connection" ? "true" : "false")">
Dataplicity Connection
</button>
<button type="submit" name="eventType" value="Mezmo logging"
class="btn @(Model.EventType == "Mezmo logging" ? "selected" : "unselected")"
aria-pressed="@(Model.EventType == "Mezmo logging" ? "true" : "false")">
Mezmo Logging
</button>
</div>
</form>
<p>
Uptime percentage: @Model.UptimePercentage%
</p>
Expand Down
34 changes: 27 additions & 7 deletions OrcanodeMonitor/Pages/NodeEvents.cshtml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.IdentityModel.Tokens;
using OrcanodeMonitor.Core;
using OrcanodeMonitor.Data;
using OrcanodeMonitor.Models;
Expand All @@ -14,9 +15,13 @@ public class NodeEventsModel : PageModel
private readonly ILogger<NodeEventsModel> _logger;
private string _nodeId;
public string Id => _nodeId;

[BindProperty]
public string TimePeriod { get; set; } = "week"; // Default to 'week'
[BindProperty]
public string Selected { get; set; } = "week"; // Default to 'week'
private DateTime SinceTime => (Selected == "week") ? DateTime.UtcNow.AddDays(-7) : DateTime.UtcNow.AddMonths(-1);
public string EventType { get; set; } = "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);
Expand All @@ -31,7 +36,8 @@ public NodeEventsModel(OrcanodeMonitorContext context, ILogger<NodeEventsModel>

private void FetchEvents(ILogger logger)
{
_events = Fetcher.GetRecentEventsForNode(_databaseContext, _nodeId, SinceTime, logger) ?? new List<OrcanodeEvent>();
string eventType = (EventType == "all") ? string.Empty : EventType;
_events = Fetcher.GetRecentEventsForNode(_databaseContext, _nodeId, SinceTime, eventType, logger) ?? new List<OrcanodeEvent>();
}

public void OnGet(string id)
Expand All @@ -40,19 +46,33 @@ public void OnGet(string id)
FetchEvents(_logger);
}

public IActionResult OnPost(string selected, string id)
public IActionResult OnPost(string timePeriod, string eventType, string id)
{
if (string.IsNullOrEmpty(id))
{
_logger.LogError("Node ID cannot be empty");
return BadRequest("Invalid node ID");
}
if (selected != "week" && selected != "month")
if (timePeriod.IsNullOrEmpty())
{
timePeriod = TimePeriod;
}
if (eventType.IsNullOrEmpty())
{
_logger.LogWarning("Invalid time range selected: {selected}", selected);
eventType = EventType;
}
if (timePeriod != "week" && timePeriod != "month")
{
_logger.LogWarning($"Invalid time range selected: {timePeriod}");
return BadRequest("Invalid time range");
}
Selected = selected;
if (eventType != "all" && eventType != OrcanodeEventTypes.HydrophoneStream && eventType != OrcanodeEventTypes.MezmoLogging && eventType != OrcanodeEventTypes.DataplicityConnection)
{
_logger.LogWarning($"Invalid event type selected: {eventType}");
return BadRequest("Invalid event type");
}
TimePeriod = timePeriod;
EventType = eventType;
_nodeId = id;
FetchEvents(_logger);
return Page();
Expand Down

0 comments on commit b2352a8

Please sign in to comment.