@page "/serilogs/database" @using Indotalent.Data.Entities @using Indotalent.Infrastructure.Database @using Indotalent.Shared.Consts @using Microsoft.AspNetCore.Components.Web @using Microsoft.EntityFrameworkCore @using Microsoft.JSInterop @using MudBlazor @using Features.Root.Shared @using Indotalent.Features.Serilogs.Database @using Indotalent.Shared.Models @using ClosedXML.Excel @using System.IO @inject SerilogsService SerilogsService @inject IDialogService DialogService @inject ISnackbar Snackbar @inject IJSRuntime JSRuntime
Database Logs Monitor application events, errors, and system activities stored in MSSQL Server.
/ Serilogs / Database
Search
@if (_isExporting) { Processing... } else { Excel } @if (_isRefreshing) { Refreshing... } else { Refresh } @if (_isClearing) { } else { Clear All } @if (_selectedLog != null) { View Delete }
Timestamp Level Message Exception @context.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss") @context.Level @context.Message @if (!string.IsNullOrEmpty(context.Exception)) { Has Error } else { - }
Rows per page: Showing @(_totalCount == 0 ? 0 : _skip + 1)-@Math.Min(_skip + _top, _totalCount) of @_totalCount
@{ var totalPages = _totalPage == 0 ? 1 : _totalPage; var maxVisible = 5; var startPage = Math.Max(1, _currentPage - maxVisible / 2); var endPage = Math.Min(totalPages, startPage + maxVisible - 1); if (endPage - startPage < maxVisible - 1) { startPage = Math.Max(1, endPage - maxVisible + 1); } } @for (int i = startPage; i <= endPage; i++) { var pageNum = i; var isActive = pageNum == _currentPage; @pageNum }
@code { private GetSerilogLogsPagedListResponse? _selectedLog = null; private List _pagedItems = new(); private int _skip = 0; private int _top = 5; private int _totalCount = 0; private int _totalPage = 0; private int _currentPage => (_skip / _top) + 1; private string _searchString = ""; private bool _isRefreshing = false; private bool _isClearing = false; private bool _isExporting = false; protected override async Task OnInitializedAsync() => await LoadData(); private async Task LoadData() { _isRefreshing = true; StateHasChanged(); var response = await SerilogsService.GetSerilogLogsODataAsync(_skip, _top, _searchString); await Task.Delay(500); if (response != null) { _pagedItems = response.Value ?? new(); _totalCount = response.Count; _totalPage = (int)Math.Ceiling((double)_totalCount / _top); } else { _pagedItems = new(); _totalCount = 0; _totalPage = 0; } _isRefreshing = false; StateHasChanged(); } private async Task HandleRefresh() { _skip = 0; _selectedLog = null; await LoadData(); } private void HandleRowClick(TableRowClickEventArgs args) { _selectedLog = (_selectedLog?.Id == args.Item.Id) ? null : args.Item; } private async Task OnSearchClick() { _skip = 0; _selectedLog = null; await LoadData(); } private async Task HandleSearchKeyDown(KeyboardEventArgs e) { if (e.Key == "Enter") await OnSearchClick(); } private async Task OnPageChanged(int page) { if (page >= 1 && page <= _totalPage) { _skip = (page - 1) * _top; _selectedLog = null; await LoadData(); } } private async Task OnPageSizeChanged(int size) { _top = size; _skip = 0; _selectedLog = null; await LoadData(); } private async Task ExportToExcel() { _isExporting = true; StateHasChanged(); try { await Task.Delay(1000); var response = await SerilogsService.GetSerilogLogsODataAsync(0, GlobalConsts.ODataMaxTop, _searchString); var dataToExport = response?.Value ?? new List(); using (var workbook = new XLWorkbook()) { var worksheet = workbook.Worksheets.Add("DatabaseLogs"); var currentRow = 1; worksheet.Cell(currentRow, 1).Value = "Timestamp"; worksheet.Cell(currentRow, 2).Value = "Level"; worksheet.Cell(currentRow, 3).Value = "Message"; worksheet.Cell(currentRow, 4).Value = "Exception"; var headerRange = worksheet.Range(1, 1, 1, 4); headerRange.Style.Font.Bold = true; headerRange.Style.Fill.BackgroundColor = XLColor.FromHtml("#0D47A1"); headerRange.Style.Font.FontColor = XLColor.White; foreach (var item in dataToExport) { currentRow++; worksheet.Cell(currentRow, 1).Value = item.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss"); worksheet.Cell(currentRow, 2).Value = item.Level; worksheet.Cell(currentRow, 3).Value = item.Message; worksheet.Cell(currentRow, 4).Value = item.Exception; } worksheet.Columns().AdjustToContents(); using (var stream = new MemoryStream()) { workbook.SaveAs(stream); var content = Convert.ToBase64String(stream.ToArray()); await JSRuntime.InvokeVoidAsync("downloadFile", "Database_Logs.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", content); Snackbar.Add("Exported successfully", Severity.Success); } } } catch (Exception ex) { Snackbar.Add($"Export failed: {ex.Message}", Severity.Error); } finally { _isExporting = false; StateHasChanged(); } } private async Task OnDeleteAll() { var parameters = new DialogParameters<_DeleteConfirmation> { { x => x.ContentText, "ALL database logs" } }; var dialog = await DialogService.ShowAsync<_DeleteConfirmation>("Confirmation", parameters); var result = await dialog.Result; if (result != null && !result.Canceled) { _isClearing = true; StateHasChanged(); if (await SerilogsService.DeleteSerilogLogsAllAsync()) { Snackbar.Add("All logs cleared.", Severity.Success); _selectedLog = null; _skip = 0; await LoadData(); } _isClearing = false; StateHasChanged(); } } private async Task OnDeleteSingle() { if (_selectedLog == null) return; var parameters = new DialogParameters<_DeleteConfirmation> { { x => x.ContentText, $"Log ID {_selectedLog.Id}" } }; var dialog = await DialogService.ShowAsync<_DeleteConfirmation>("Confirmation", parameters); var result = await dialog.Result; if (result != null && !result.Canceled) { if (await SerilogsService.DeleteSerilogLogsByIdAsync(_selectedLog.Id)) { Snackbar.Add("Log deleted.", Severity.Success); _selectedLog = null; await LoadData(); } } } private async Task OnViewDetail() { if (_selectedLog == null) return; var detail = await SerilogsService.GetSerilogLogsByIdAsync(_selectedLog.Id); if (detail != null) { var parameters = new DialogParameters<_SerilogDetailDialog> { { x => x.Log, detail } }; await DialogService.ShowAsync<_SerilogDetailDialog>("Log Details", parameters, new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true }); } } private Color GetLevelColor(string? level) => level switch { "Information" or "Info" => Color.Info, "Warning" => Color.Warning, "Error" or "Fatal" => Color.Error, _ => Color.Default }; }