DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/RequestTrackerService.cs
2024-08-19 10:01:07 +05:00

131 lines
4.4 KiB
C#

using AsbCloudApp.Data;
using AsbCloudApp.Services;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services;
public class RequestTrackerService : IRequerstTrackerService
{
const int fastRequestsCount = 1000;
const int slowRequestsCount = 1000;
const int errorRequestsCount = 1000;
const int span = 100;
const int fastLimitMs = 500;
static readonly char[] stackTraceSeparators = "\r\n".ToCharArray();
private readonly ConcurrentQueue<RequestLogDto> fastRequests = new ();
private readonly ConcurrentQueue<RequestLogDto> slowRequests = new ();
private readonly ConcurrentQueue<RequestLogDto> errorRequests = new ();
private readonly ConcurrentDictionary<string, RequestLogUserDto> users = new ConcurrentDictionary<string, RequestLogUserDto>();
private static IEnumerable<RequestLogDto> Get(IEnumerable<RequestLogDto> list, int? take)
{
IEnumerable<RequestLogDto> orderedlist = list.OrderByDescending(r => r.Date);
if (take > 0)
orderedlist = orderedlist.Take(take.Value);
return orderedlist;
}
public IEnumerable<RequestLogUserDto> GetUsersStat(int? take)
{
IEnumerable<RequestLogUserDto> result = users.Values.OrderByDescending(u => u.LastDate);
if (take > 0)
result = result.Take(take.Value);
return result;
}
public IEnumerable<RequestLogDto> GetAll(int? take)
{
var result = fastRequests
.Union(slowRequests)
.Union(errorRequests);
return Get(result, take);
}
public IEnumerable<RequestLogDto> GetFast(int? take)
=> Get(fastRequests, take);
public IEnumerable<RequestLogDto> GetSlow(int? take)
=> Get(slowRequests, take);
public IEnumerable<RequestLogDto> GetError(int? take)
=> Get(errorRequests, take);
public void RegisterRequest(RequestLogDto requestLog)
{
if (requestLog.Status < 200)
return;
requestLog.Date = DateTime.Now;
if (requestLog.ElapsedMilliseconds > fastLimitMs)
RegisterSlowRequest(requestLog);
else
RegisterFastRequest(requestLog);
UpdateUserStat(requestLog);
}
private void RegisterFastRequest(RequestLogDto requestLog)
{
fastRequests.Enqueue(requestLog);
if (fastRequests.Count > fastRequestsCount + span)
while (fastRequests.Count > fastRequestsCount)
fastRequests.TryDequeue(out _);
}
private void RegisterSlowRequest(RequestLogDto requestLog)
{
slowRequests.Enqueue(requestLog);
if (slowRequests.Count > slowRequestsCount + span)
while (slowRequests.Count > slowRequestsCount)
slowRequests.TryDequeue(out _);
}
public void RegisterRequestError(RequestLogDto requestLog, Exception ex)
{
requestLog.Date = DateTime.Now;
requestLog.ExceptionMessage = ex.InnerException?.InnerException?.Message
?? ex.InnerException?.Message
?? ex.Message;
requestLog.ExceptionStack = ex.StackTrace?.Split(stackTraceSeparators)[0];
errorRequests.Enqueue(requestLog);
if (errorRequests.Count > errorRequestsCount + span)
while (errorRequests.Count > errorRequestsCount)
errorRequests.TryDequeue(out _);
UpdateUserStat(requestLog);
}
private void UpdateUserStat(RequestLogDto requestLog)
{
if (!string.IsNullOrEmpty(requestLog.UserLogin))
{
var key = $"{requestLog.UserId}>{requestLog.UserIp}";
if (!users.ContainsKey(key))
users[key] = new RequestLogUserDto
{
UserId = requestLog.UserId,
Ip = requestLog.UserIp,
Login = requestLog.UserLogin,
};
users[key].ElapsedMs += requestLog.ElapsedMilliseconds;
users[key].LastDate = requestLog.Date;
users[key].Requests++;
if (!string.IsNullOrEmpty(requestLog.ExceptionMessage))
users[key].Errors++;
if (users.Count > 1000)
{
var count = 900 - users.Count;
var toRemove = users.OrderBy(kv => kv.Value.LastDate).Take(count);
foreach (var kv in toRemove)
users.TryRemove(kv);
}
}
}
}