Add monitoring on queries with sentry alert + Fix check position list in db for backtest

This commit is contained in:
2025-10-10 00:15:02 +07:00
parent ffb98fe359
commit e4c2f8b7a5
24 changed files with 3340 additions and 179 deletions

View File

@@ -1,14 +1,27 @@
using Managing.Infrastructure.Databases.PostgreSql.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace Managing.Infrastructure.Databases.PostgreSql;
public class ManagingDbContext : DbContext
{
private readonly ILogger<ManagingDbContext>? _logger;
private readonly SentrySqlMonitoringService? _sentryMonitoringService;
private readonly Dictionary<string, int> _queryExecutionCounts = new();
private readonly object _queryCountLock = new object();
public ManagingDbContext(DbContextOptions<ManagingDbContext> options) : base(options)
{
}
public ManagingDbContext(DbContextOptions<ManagingDbContext> options, ILogger<ManagingDbContext> logger, SentrySqlMonitoringService sentryMonitoringService)
: base(options)
{
_logger = logger;
_sentryMonitoringService = sentryMonitoringService;
}
public DbSet<AccountEntity> Accounts { get; set; }
public DbSet<UserEntity> Users { get; set; }
public DbSet<GeneticRequestEntity> GeneticRequests { get; set; }
@@ -607,7 +620,7 @@ public class ManagingDbContext : DbContext
{
try
{
var count = await Database.SqlQueryRaw<long>($"SELECT COUNT(*) FROM {tableName}").FirstOrDefaultAsync();
var count = await Database.SqlQueryRaw<long>($"SELECT COUNT(*) FROM \"{tableName}\"").FirstOrDefaultAsync();
stats[tableName] = count;
}
catch
@@ -638,4 +651,63 @@ public class ManagingDbContext : DbContext
// Add any additional configuration here if needed
}
/// <summary>
/// Tracks query execution for loop detection and performance monitoring
/// </summary>
/// <param name="queryPattern">Pattern or hash of the query</param>
/// <param name="executionTime">Time taken to execute the query</param>
/// <param name="repositoryName">Name of the repository executing the query</param>
/// <param name="methodName">Name of the method executing the query</param>
public void TrackQueryExecution(string queryPattern, TimeSpan executionTime, string repositoryName, string methodName)
{
if (_logger == null || _sentryMonitoringService == null) return;
// Track execution count for this query pattern
lock (_queryCountLock)
{
_queryExecutionCounts[queryPattern] = _queryExecutionCounts.GetValueOrDefault(queryPattern, 0) + 1;
}
// Check for potential loops with Sentry integration
var isLoopDetected = _sentryMonitoringService.TrackQueryExecution(repositoryName, methodName, queryPattern, executionTime);
// Log query execution details
var logLevel = executionTime.TotalMilliseconds > 1000 ? LogLevel.Warning : LogLevel.Debug;
_logger.Log(logLevel,
"[SQL-QUERY-TRACKED] {Repository}.{Method} | Pattern: {Pattern} | Time: {Time}ms | Count: {Count}",
repositoryName, methodName, queryPattern, executionTime.TotalMilliseconds,
_queryExecutionCounts[queryPattern]);
// Alert on potential loops
if (isLoopDetected)
{
_logger.LogError(
"[SQL-LOOP-ALERT] Potential infinite loop detected in {Repository}.{Method} with pattern '{Pattern}'",
repositoryName, methodName, queryPattern);
}
}
/// <summary>
/// Gets current query execution statistics
/// </summary>
public Dictionary<string, int> GetQueryExecutionCounts()
{
lock (_queryCountLock)
{
return new Dictionary<string, int>(_queryExecutionCounts);
}
}
/// <summary>
/// Clears query execution tracking data
/// </summary>
public void ClearQueryTracking()
{
lock (_queryCountLock)
{
_queryExecutionCounts.Clear();
}
_logger?.LogInformation("[SQL-TRACKING] Query execution counts cleared");
}
}