From 0da1ef518af0fcdaeb67dd0090523489f5a05f70 Mon Sep 17 00:00:00 2001 From: Flaminel Date: Tue, 27 May 2025 03:03:06 +0300 Subject: [PATCH] events #5 --- code/Data/DataContext.cs | 17 --- code/Data/Enums/EventSeverity.cs | 10 ++ code/Data/Enums/EventType.cs | 11 ++ .../20250526234610_Initial.Designer.cs | 65 ++++++++++ .../Data/Migrations/20250526234610_Initial.cs | 60 +++++++++ .../Migrations/DataContextModelSnapshot.cs | 62 +++++++++ code/Data/Models/Events/AppEvent.cs | 20 +-- .../Controllers/EventsController.cs | 63 ++++----- code/Executable/DependencyInjection/ApiDI.cs | 19 ++- code/Infrastructure/Events/EventPublisher.cs | 58 +-------- .../Events/NotificationEventWrapper.cs | 120 ------------------ .../Logging/LoggingInitializer.cs | 6 +- .../Verticals/ItemStriker/Striker.cs | 5 +- code/UI/src/app/core/models/event.models.ts | 4 +- .../events-viewer.component.html | 47 +++---- .../events-viewer/events-viewer.component.ts | 59 ++++----- 16 files changed, 306 insertions(+), 320 deletions(-) create mode 100644 code/Data/Enums/EventSeverity.cs create mode 100644 code/Data/Enums/EventType.cs create mode 100644 code/Data/Migrations/20250526234610_Initial.Designer.cs create mode 100644 code/Data/Migrations/20250526234610_Initial.cs create mode 100644 code/Data/Migrations/DataContextModelSnapshot.cs delete mode 100644 code/Infrastructure/Events/NotificationEventWrapper.cs diff --git a/code/Data/DataContext.cs b/code/Data/DataContext.cs index 1dad7534..f45884ab 100644 --- a/code/Data/DataContext.cs +++ b/code/Data/DataContext.cs @@ -19,21 +19,4 @@ public class DataContext : DbContext optionsBuilder.UseSqlite($"Data Source={dbPath}"); } } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - // Additional configuration if needed - modelBuilder.Entity(entity => - { - entity.HasKey(e => e.Id); - entity.Property(e => e.Timestamp).IsRequired(); - entity.Property(e => e.EventType).IsRequired().HasMaxLength(100); - entity.Property(e => e.Source).IsRequired().HasMaxLength(100); - entity.Property(e => e.Message).IsRequired().HasMaxLength(1000); - entity.Property(e => e.Severity).IsRequired().HasMaxLength(20); - entity.Property(e => e.CorrelationId).HasMaxLength(50); - }); - } } \ No newline at end of file diff --git a/code/Data/Enums/EventSeverity.cs b/code/Data/Enums/EventSeverity.cs new file mode 100644 index 00000000..a9d75071 --- /dev/null +++ b/code/Data/Enums/EventSeverity.cs @@ -0,0 +1,10 @@ +namespace Data.Enums; + +public enum EventSeverity +{ + Test, + Information, + Warning, + Important, + Error, +} \ No newline at end of file diff --git a/code/Data/Enums/EventType.cs b/code/Data/Enums/EventType.cs new file mode 100644 index 00000000..eed7e0dc --- /dev/null +++ b/code/Data/Enums/EventType.cs @@ -0,0 +1,11 @@ +namespace Data.Enums; + +public enum EventType +{ + FailedImportStrike, + StalledStrike, + SlowStrike, + QueueItemDeleted, + DownloadCleaned, + CategoryChanged +} \ No newline at end of file diff --git a/code/Data/Migrations/20250526234610_Initial.Designer.cs b/code/Data/Migrations/20250526234610_Initial.Designer.cs new file mode 100644 index 00000000..984081a2 --- /dev/null +++ b/code/Data/Migrations/20250526234610_Initial.Designer.cs @@ -0,0 +1,65 @@ +// +using System; +using Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20250526234610_Initial")] + partial class Initial + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.5"); + + modelBuilder.Entity("Data.Models.Events.AppEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("EventType") + .HasColumnType("INTEGER"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Severity") + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("TrackingId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventType"); + + b.HasIndex("Message"); + + b.HasIndex("Severity"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("Events"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/code/Data/Migrations/20250526234610_Initial.cs b/code/Data/Migrations/20250526234610_Initial.cs new file mode 100644 index 00000000..66ad01c5 --- /dev/null +++ b/code/Data/Migrations/20250526234610_Initial.cs @@ -0,0 +1,60 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Data.Migrations +{ + /// + public partial class Initial : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Events", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Timestamp = table.Column(type: "TEXT", nullable: false), + EventType = table.Column(type: "INTEGER", nullable: false), + Message = table.Column(type: "TEXT", maxLength: 1000, nullable: false), + Data = table.Column(type: "TEXT", nullable: true), + Severity = table.Column(type: "INTEGER", nullable: false), + TrackingId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Events", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Events_EventType", + table: "Events", + column: "EventType"); + + migrationBuilder.CreateIndex( + name: "IX_Events_Message", + table: "Events", + column: "Message"); + + migrationBuilder.CreateIndex( + name: "IX_Events_Severity", + table: "Events", + column: "Severity"); + + migrationBuilder.CreateIndex( + name: "IX_Events_Timestamp", + table: "Events", + column: "Timestamp", + descending: new bool[0]); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Events"); + } + } +} diff --git a/code/Data/Migrations/DataContextModelSnapshot.cs b/code/Data/Migrations/DataContextModelSnapshot.cs new file mode 100644 index 00000000..47a59dcf --- /dev/null +++ b/code/Data/Migrations/DataContextModelSnapshot.cs @@ -0,0 +1,62 @@ +// +using System; +using Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Data.Migrations +{ + [DbContext(typeof(DataContext))] + partial class DataContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.5"); + + modelBuilder.Entity("Data.Models.Events.AppEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("EventType") + .HasColumnType("INTEGER"); + + b.Property("Message") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("TEXT"); + + b.Property("Severity") + .HasColumnType("INTEGER"); + + b.Property("Timestamp") + .HasColumnType("TEXT"); + + b.Property("TrackingId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("EventType"); + + b.HasIndex("Message"); + + b.HasIndex("Severity"); + + b.HasIndex("Timestamp") + .IsDescending(); + + b.ToTable("Events"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/code/Data/Models/Events/AppEvent.cs b/code/Data/Models/Events/AppEvent.cs index e0aba6b2..2a01ffd1 100644 --- a/code/Data/Models/Events/AppEvent.cs +++ b/code/Data/Models/Events/AppEvent.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using Data.Enums; using Microsoft.EntityFrameworkCore; namespace Data.Models.Events; @@ -6,25 +7,20 @@ namespace Data.Models.Events; /// /// Represents an event in the system /// -[Index(nameof(Timestamp), IsDescending = new[] { true })] +[Index(nameof(Timestamp), IsDescending = [true])] [Index(nameof(EventType))] [Index(nameof(Severity))] -[Index(nameof(Source))] +[Index(nameof(Message))] public class AppEvent { [Key] - public string Id { get; set; } = Guid.NewGuid().ToString(); + public Guid Id { get; set; } = Guid.CreateVersion7(); [Required] public DateTime Timestamp { get; set; } = DateTime.UtcNow; [Required] - [MaxLength(100)] - public string EventType { get; set; } = string.Empty; - - [Required] - [MaxLength(100)] - public string Source { get; set; } = string.Empty; + public EventType EventType { get; set; } [Required] [MaxLength(1000)] @@ -36,12 +32,10 @@ public class AppEvent public string? Data { get; set; } [Required] - [MaxLength(20)] - public string Severity { get; set; } = "Info"; // Info, Warning, Error, Critical + public required EventSeverity Severity { get; set; } /// /// Optional correlation ID to link related events /// - [MaxLength(50)] - public string? CorrelationId { get; set; } + public Guid? TrackingId { get; set; } } \ No newline at end of file diff --git a/code/Executable/Controllers/EventsController.cs b/code/Executable/Controllers/EventsController.cs index ef34ed3a..75befda4 100644 --- a/code/Executable/Controllers/EventsController.cs +++ b/code/Executable/Controllers/EventsController.cs @@ -1,5 +1,6 @@ using Data; using Data.Models.Events; +using Data.Enums; using Infrastructure.Events; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -24,20 +25,22 @@ public class EventsController : ControllerBase public async Task>> GetEvents( [FromQuery] int count = 100, [FromQuery] string? severity = null, - [FromQuery] string? eventType = null, - [FromQuery] string? source = null) + [FromQuery] string? eventType = null) { var query = _context.Events.AsQueryable(); // Apply filters if (!string.IsNullOrWhiteSpace(severity)) - query = query.Where(e => e.Severity == severity); + { + if (Enum.TryParse(severity, true, out var severityEnum)) + query = query.Where(e => e.Severity == severityEnum); + } if (!string.IsNullOrWhiteSpace(eventType)) - query = query.Where(e => e.EventType == eventType); - - if (!string.IsNullOrWhiteSpace(source)) - query = query.Where(e => e.Source.Contains(source)); + { + if (Enum.TryParse(eventType, true, out var eventTypeEnum)) + query = query.Where(e => e.EventType == eventTypeEnum); + } // Order and limit var events = await query @@ -52,7 +55,7 @@ public class EventsController : ControllerBase /// Gets a specific event by ID /// [HttpGet("{id}")] - public async Task> GetEvent(string id) + public async Task> GetEvent(Guid id) { var eventEntity = await _context.Events.FindAsync(id); @@ -63,13 +66,13 @@ public class EventsController : ControllerBase } /// - /// Gets events by correlation ID + /// Gets events by tracking ID /// - [HttpGet("correlation/{correlationId}")] - public async Task>> GetEventsByCorrelation(string correlationId) + [HttpGet("tracking/{trackingId}")] + public async Task>> GetEventsByTracking(Guid trackingId) { var events = await _context.Events - .Where(e => e.CorrelationId == correlationId) + .Where(e => e.TrackingId == trackingId) .OrderBy(e => e.Timestamp) .ToListAsync(); @@ -87,11 +90,11 @@ public class EventsController : ControllerBase TotalEvents = await _context.Events.CountAsync(), EventsBySeverity = await _context.Events .GroupBy(e => e.Severity) - .Select(g => new { Severity = g.Key, Count = g.Count() }) + .Select(g => new { Severity = g.Key.ToString(), Count = g.Count() }) .ToListAsync(), EventsByType = await _context.Events .GroupBy(e => e.EventType) - .Select(g => new { EventType = g.Key, Count = g.Count() }) + .Select(g => new { EventType = g.Key.ToString(), Count = g.Count() }) .OrderByDescending(x => x.Count) .Take(10) .ToListAsync(), @@ -118,33 +121,23 @@ public class EventsController : ControllerBase return Ok(); } - /// - /// Gets unique event sources - /// - [HttpGet("sources")] - public async Task>> GetEventSources() - { - var sources = await _context.Events - .Select(e => e.Source) - .Distinct() - .OrderBy(s => s) - .ToListAsync(); - - return Ok(sources); - } - /// /// Gets unique event types /// [HttpGet("types")] public async Task>> GetEventTypes() { - var types = await _context.Events - .Select(e => e.EventType) - .Distinct() - .OrderBy(t => t) - .ToListAsync(); - + var types = Enum.GetNames(typeof(EventType)).ToList(); return Ok(types); } + + /// + /// Gets unique severities + /// + [HttpGet("severities")] + public async Task>> GetSeverities() + { + var severities = Enum.GetNames(typeof(EventSeverity)).ToList(); + return Ok(severities); + } } \ No newline at end of file diff --git a/code/Executable/DependencyInjection/ApiDI.cs b/code/Executable/DependencyInjection/ApiDI.cs index ed744cf8..896d17ac 100644 --- a/code/Executable/DependencyInjection/ApiDI.cs +++ b/code/Executable/DependencyInjection/ApiDI.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using Infrastructure.Health; using Infrastructure.Logging; using Infrastructure.Events; @@ -10,11 +11,21 @@ public static class ApiDI public static IServiceCollection AddApiServices(this IServiceCollection services) { // Add API-specific services - services.AddControllers(); + services + .AddControllers() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); services.AddEndpointsApiExplorer(); // Add SignalR for real-time updates - services.AddSignalR(); + services + .AddSignalR() + .AddJsonProtocol(options => + { + options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + });; // Add health status broadcaster services.AddHostedService(); @@ -26,12 +37,12 @@ public static class ApiDI { options.SwaggerDoc("v1", new OpenApiInfo { - Title = "Cleanuperr API", + Title = "Cleanuparr API", Version = "v1", Description = "API for managing media downloads and cleanups", Contact = new OpenApiContact { - Name = "Cleanuperr Team" + Name = "Cleanuparr Team" } }); }); diff --git a/code/Infrastructure/Events/EventPublisher.cs b/code/Infrastructure/Events/EventPublisher.cs index 238ceaf8..af4c41e4 100644 --- a/code/Infrastructure/Events/EventPublisher.cs +++ b/code/Infrastructure/Events/EventPublisher.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using System.Text.Json; using Data; +using Data.Enums; using Data.Models.Events; namespace Infrastructure.Events; @@ -28,16 +29,15 @@ public class EventPublisher /// /// Publishes an event to database and SignalR clients /// - public async Task PublishAsync(string eventType, string source, string message, string severity = "Info", object? data = null, string? correlationId = null) + public async Task PublishAsync(EventType eventType, string message, EventSeverity severity, object? data = null, Guid? trackingId = null) { var eventEntity = new AppEvent { EventType = eventType, - Source = source, Message = message, Severity = severity, Data = data != null ? JsonSerializer.Serialize(data) : null, - CorrelationId = correlationId + TrackingId = trackingId }; // Save to database @@ -47,55 +47,7 @@ public class EventPublisher // Send to SignalR clients await NotifyClientsAsync(eventEntity); - _logger.LogTrace("Published event: {eventType} from {source}", eventType, source); - } - - /// - /// Publishes an info event - /// - public async Task PublishInfoAsync(string source, string message, object? data = null, string? correlationId = null) - { - await PublishAsync("Information", source, message, "Info", data, correlationId); - } - - /// - /// Publishes a warning event - /// - public async Task PublishWarningAsync(string source, string message, object? data = null, string? correlationId = null) - { - await PublishAsync("Warning", source, message, "Warning", data, correlationId); - } - - /// - /// Publishes an error event - /// - public async Task PublishErrorAsync(string source, string message, object? data = null, string? correlationId = null) - { - await PublishAsync("Error", source, message, "Error", data, correlationId); - } - - /// - /// Publishes a notification-related event (for HTTP notifications to Notifiarr/Apprise) - /// - public async Task PublishNotificationEventAsync(string provider, string message, bool success, object? data = null, string? correlationId = null) - { - var eventType = success ? "NotificationSent" : "NotificationFailed"; - var severity = success ? "Info" : "Warning"; - - await PublishAsync(eventType, $"NotificationService.{provider}", message, severity, data, correlationId); - } - - /// - /// Publishes an HTTP call event (for external API calls) - /// - public async Task PublishHttpCallEventAsync(string endpoint, string method, int statusCode, TimeSpan duration, object? data = null, string? correlationId = null) - { - var success = statusCode >= 200 && statusCode < 300; - var eventType = success ? "HttpCallSuccess" : "HttpCallFailed"; - var severity = success ? "Info" : "Warning"; - var message = $"{method} {endpoint} - {statusCode} ({duration.TotalMilliseconds}ms)"; - - await PublishAsync(eventType, "HttpClient", message, severity, data, correlationId); + _logger.LogTrace("Published event: {eventType}", eventType); } private async Task NotifyClientsAsync(AppEvent appEventEntity) @@ -104,8 +56,6 @@ public class EventPublisher { // Send to all connected clients (self-hosted app with single client) await _hubContext.Clients.All.SendAsync("EventReceived", appEventEntity); - - _logger.LogTrace("Sent event {eventId} to SignalR clients", appEventEntity.Id); } catch (Exception ex) { diff --git a/code/Infrastructure/Events/NotificationEventWrapper.cs b/code/Infrastructure/Events/NotificationEventWrapper.cs deleted file mode 100644 index fe729803..00000000 --- a/code/Infrastructure/Events/NotificationEventWrapper.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Infrastructure.Verticals.Notifications; -using Infrastructure.Verticals.Notifications.Models; -using Microsoft.Extensions.Logging; -using System.Diagnostics; - -namespace Infrastructure.Events; - -/// -/// Wrapper around NotificationService that publishes events for all notification calls -/// -public class NotificationEventWrapper -{ - private readonly NotificationService _notificationService; - private readonly EventPublisher _eventPublisher; - private readonly ILogger _logger; - - public NotificationEventWrapper( - NotificationService notificationService, - EventPublisher eventPublisher, - ILogger logger) - { - _notificationService = notificationService; - _eventPublisher = eventPublisher; - _logger = logger; - } - - public async Task Notify(FailedImportStrikeNotification notification) - { - await NotifyWithEventLogging("FailedImportStrike", notification, - async () => await _notificationService.Notify(notification)); - } - - public async Task Notify(StalledStrikeNotification notification) - { - await NotifyWithEventLogging("StalledStrike", notification, - async () => await _notificationService.Notify(notification)); - } - - public async Task Notify(SlowStrikeNotification notification) - { - await NotifyWithEventLogging("SlowStrike", notification, - async () => await _notificationService.Notify(notification)); - } - - public async Task Notify(QueueItemDeletedNotification notification) - { - await NotifyWithEventLogging("QueueItemDeleted", notification, - async () => await _notificationService.Notify(notification)); - } - - public async Task Notify(DownloadCleanedNotification notification) - { - await NotifyWithEventLogging("DownloadCleaned", notification, - async () => await _notificationService.Notify(notification)); - } - - public async Task Notify(CategoryChangedNotification notification) - { - await NotifyWithEventLogging("CategoryChanged", notification, - async () => await _notificationService.Notify(notification)); - } - - private async Task NotifyWithEventLogging(string notificationType, T notification, Func notifyAction) - where T : class - { - var correlationId = Guid.NewGuid().ToString("N")[..8]; - var stopwatch = Stopwatch.StartNew(); - - try - { - // Log notification attempt - await _eventPublisher.PublishInfoAsync( - source: "NotificationService", - message: $"Sending {notificationType} notification", - data: new { NotificationType = notificationType, Notification = notification }, - correlationId: correlationId); - - // Execute the notification - await notifyAction(); - - stopwatch.Stop(); - - // Log successful notification - await _eventPublisher.PublishInfoAsync( - source: "NotificationService", - message: $"{notificationType} notification sent successfully", - data: new { - NotificationType = notificationType, - Duration = stopwatch.ElapsedMilliseconds, - Success = true - }, - correlationId: correlationId); - - _logger.LogInformation("Successfully sent {notificationType} notification in {duration}ms", - notificationType, stopwatch.ElapsedMilliseconds); - } - catch (Exception ex) - { - stopwatch.Stop(); - - // Log failed notification - await _eventPublisher.PublishErrorAsync( - source: "NotificationService", - message: $"Failed to send {notificationType} notification: {ex.Message}", - data: new { - NotificationType = notificationType, - Duration = stopwatch.ElapsedMilliseconds, - Success = false, - Error = ex.Message, - StackTrace = ex.StackTrace - }, - correlationId: correlationId); - - _logger.LogError(ex, "Failed to send {notificationType} notification after {duration}ms", - notificationType, stopwatch.ElapsedMilliseconds); - - throw; // Re-throw to maintain original behavior - } - } -} \ No newline at end of file diff --git a/code/Infrastructure/Logging/LoggingInitializer.cs b/code/Infrastructure/Logging/LoggingInitializer.cs index 002247c4..084bf230 100644 --- a/code/Infrastructure/Logging/LoggingInitializer.cs +++ b/code/Infrastructure/Logging/LoggingInitializer.cs @@ -1,3 +1,4 @@ +using Data.Enums; using Infrastructure.Events; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -23,10 +24,9 @@ public class LoggingInitializer : BackgroundService try { await _eventPublisher.PublishAsync( - "strike", + EventType.SlowStrike, "test", - "Item '{item}' has been struck {1} times for reason '{stalled}'", - severity: "Warning", + EventSeverity.Important, data: new { Hash = "hash", Name = "name", StrikeCount = "1", Type = "stalled" }); throw new Exception("test exception"); } diff --git a/code/Infrastructure/Verticals/ItemStriker/Striker.cs b/code/Infrastructure/Verticals/ItemStriker/Striker.cs index 3458602f..b3068b8e 100644 --- a/code/Infrastructure/Verticals/ItemStriker/Striker.cs +++ b/code/Infrastructure/Verticals/ItemStriker/Striker.cs @@ -50,10 +50,9 @@ public sealed class Striker : IStriker await _notifier.NotifyStrike(strikeType, strikeCount); await _eventPublisher.PublishAsync( - "strike", - nameof(Striker), + EventType.SlowStrike, // TODO $"Item '{itemName}' has been struck {strikeCount} times for reason '{strikeType}'", - severity: "Warning", + EventSeverity.Important, data: new { hash, itemName, strikeCount, strikeType }); _cache.Set(key, strikeCount, _cacheOptions); diff --git a/code/UI/src/app/core/models/event.models.ts b/code/UI/src/app/core/models/event.models.ts index b0b3f5ae..da424ab5 100644 --- a/code/UI/src/app/core/models/event.models.ts +++ b/code/UI/src/app/core/models/event.models.ts @@ -2,11 +2,10 @@ export interface Event { id: string; timestamp: string; eventType: string; - source: string; message: string; data?: string; severity: string; - correlationId?: string; + trackingId?: string; } export interface EventStats { @@ -19,7 +18,6 @@ export interface EventStats { export interface EventFilter { severity?: string; eventType?: string; - source?: string; search?: string; count?: number; } \ No newline at end of file diff --git a/code/UI/src/app/events/events-viewer/events-viewer.component.html b/code/UI/src/app/events/events-viewer/events-viewer.component.html index c4efbf0d..ba08a42d 100644 --- a/code/UI/src/app/events/events-viewer/events-viewer.component.html +++ b/code/UI/src/app/events/events-viewer/events-viewer.component.html @@ -88,18 +88,6 @@ [disabled]="!isConnected()" > - - - - @@ -117,7 +105,7 @@ label="Clear Filters" class="p-button-outlined ml-2 clear-filters-btn" (click)="clearFilters()" - [disabled]="!isConnected() || (!severityFilter() && !eventTypeFilter() && !sourceFilter() && !searchFilter())" + [disabled]="!isConnected() || (!severityFilter() && !eventTypeFilter() && !searchFilter())" > @@ -135,12 +123,12 @@ [ngClass]="getSeverityClass(event.severity)" [id]="'event-' + i" > - +
@@ -170,29 +158,24 @@ {{ event.eventType }}
- -
- {{ event.source }} -
-
{{ event.message }}
- -
+ +
- -
+ +
- - diff --git a/code/UI/src/app/events/events-viewer/events-viewer.component.ts b/code/UI/src/app/events/events-viewer/events-viewer.component.ts index a24eac48..fd3fa3a3 100644 --- a/code/UI/src/app/events/events-viewer/events-viewer.component.ts +++ b/code/UI/src/app/events/events-viewer/events-viewer.component.ts @@ -65,7 +65,6 @@ export class EventsViewerComponent implements OnInit, OnDestroy { // Filter state severityFilter = signal(null); eventTypeFilter = signal(null); - sourceFilter = signal(null); searchFilter = signal(''); // Export menu items @@ -87,18 +86,13 @@ export class EventsViewerComponent implements OnInit, OnDestroy { filtered = filtered.filter(event => event.eventType === this.eventTypeFilter()); } - if (this.sourceFilter()) { - filtered = filtered.filter(event => event.source.includes(this.sourceFilter()!)); - } - if (this.searchFilter()) { const search = this.searchFilter().toLowerCase(); filtered = filtered.filter(event => event.message.toLowerCase().includes(search) || - event.source.toLowerCase().includes(search) || event.eventType.toLowerCase().includes(search) || (event.data && event.data.toLowerCase().includes(search)) || - (event.correlationId && event.correlationId.toLowerCase().includes(search))); + (event.trackingId && event.trackingId.toLowerCase().includes(search))); } return filtered; @@ -114,11 +108,6 @@ export class EventsViewerComponent implements OnInit, OnDestroy { return uniqueTypes.map(type => ({ label: type, value: type })); }); - sources = computed(() => { - const uniqueSources = [...new Set(this.events().map(event => event.source))]; - return uniqueSources.map(source => ({ label: source, value: source })); - }); - constructor() {} ngOnInit(): void { @@ -174,10 +163,6 @@ export class EventsViewerComponent implements OnInit, OnDestroy { this.eventTypeFilter.set(eventType); } - onSourceFilterChange(source: string): void { - this.sourceFilter.set(source); - } - onSearchChange(event: Event): void { const searchText = (event.target as HTMLInputElement).value; this.search$.next(searchText); @@ -186,7 +171,6 @@ export class EventsViewerComponent implements OnInit, OnDestroy { clearFilters(): void { this.severityFilter.set(null); this.eventTypeFilter.set(null); - this.sourceFilter.set(null); this.searchFilter.set(''); } @@ -195,13 +179,15 @@ export class EventsViewerComponent implements OnInit, OnDestroy { switch (normalizedSeverity) { case 'error': - case 'critical': return 'danger'; case 'warning': return 'warn'; - case 'info': case 'information': return 'info'; + case 'important': + return 'warn'; + case 'test': + return 'secondary'; default: return 'secondary'; } @@ -215,8 +201,8 @@ export class EventsViewerComponent implements OnInit, OnDestroy { return this.events().some(event => event.data); } - hasCorrelationInfo(): boolean { - return this.events().some(event => event.correlationId); + hasTrackingInfo(): boolean { + return this.events().some(event => event.trackingId); } /** @@ -227,13 +213,15 @@ export class EventsViewerComponent implements OnInit, OnDestroy { switch (normalizedSeverity) { case 'error': - case 'critical': return 'severity-error'; case 'warning': return 'severity-warning'; - case 'info': case 'information': return 'severity-info'; + case 'important': + return 'severity-warning'; + case 'test': + return 'severity-default'; default: return 'severity-default'; } @@ -256,10 +244,10 @@ export class EventsViewerComponent implements OnInit, OnDestroy { domEvent.stopPropagation(); const timestamp = new Date(event.timestamp).toISOString(); - let content = `[${timestamp}] [${event.severity}] [${event.eventType}] [${event.source}] ${event.message}`; + let content = `[${timestamp}] [${event.severity}] [${event.eventType}] ${event.message}`; - if (event.correlationId) { - content += `\nCorrelation ID: ${event.correlationId}`; + if (event.trackingId) { + content += `\nTracking ID: ${event.trackingId}`; } if (event.data) { @@ -278,10 +266,10 @@ export class EventsViewerComponent implements OnInit, OnDestroy { const content = events.map(event => { const timestamp = new Date(event.timestamp).toISOString(); - let entry = `[${timestamp}] [${event.severity}] [${event.eventType}] [${event.source}] ${event.message}`; + let entry = `[${timestamp}] [${event.severity}] [${event.eventType}] ${event.message}`; - if (event.correlationId) { - entry += `\nCorrelation ID: ${event.correlationId}`; + if (event.trackingId) { + entry += `\nTracking ID: ${event.trackingId}`; } if (event.data) { @@ -322,19 +310,18 @@ export class EventsViewerComponent implements OnInit, OnDestroy { if (events.length === 0) return; // CSV header - let csv = 'Timestamp,Severity,EventType,Source,Message,Data,CorrelationId\n'; + let csv = 'Timestamp,Severity,EventType,Message,Data,TrackingId\n'; // CSV rows events.forEach(event => { const timestamp = new Date(event.timestamp).toISOString(); const severity = event.severity || ''; const eventType = event.eventType ? `"${event.eventType.replace(/"/g, '""')}"` : ''; - const source = event.source ? `"${event.source.replace(/"/g, '""')}"` : ''; const message = event.message ? `"${event.message.replace(/"/g, '""')}"` : ''; const data = event.data ? `"${event.data.replace(/"/g, '""').replace(/\n/g, ' ')}"` : ''; - const correlationId = event.correlationId ? `"${event.correlationId.replace(/"/g, '""')}"` : ''; + const trackingId = event.trackingId ? `"${event.trackingId.replace(/"/g, '""')}"` : ''; - csv += `${timestamp},${severity},${eventType},${source},${message},${data},${correlationId}\n`; + csv += `${timestamp},${severity},${eventType},${message},${data},${trackingId}\n`; }); this.downloadFile(csv, 'text/csv', 'events.csv'); @@ -349,10 +336,10 @@ export class EventsViewerComponent implements OnInit, OnDestroy { const content = events.map(event => { const timestamp = new Date(event.timestamp).toISOString(); - let entry = `[${timestamp}] [${event.severity}] [${event.eventType}] [${event.source}] ${event.message}`; + let entry = `[${timestamp}] [${event.severity}] [${event.eventType}] ${event.message}`; - if (event.correlationId) { - entry += `\nCorrelation ID: ${event.correlationId}`; + if (event.trackingId) { + entry += `\nTracking ID: ${event.trackingId}`; } if (event.data) {