add prometheus

This commit is contained in:
Stanley Dimant
2022-07-15 02:04:04 +02:00
parent c3365c524c
commit 17c69666e8
9 changed files with 139 additions and 41 deletions

View File

@@ -1,11 +1,9 @@
using System; using System;
using System.Data;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MareSynchronosServer.Data; using MareSynchronosServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -52,17 +50,18 @@ namespace MareSynchronosServer
var prevTime = DateTime.Now.Subtract(TimeSpan.FromDays(filesOlderThanDays)); var prevTime = DateTime.Now.Subtract(TimeSpan.FromDays(filesOlderThanDays));
dbContext.Database.BeginTransaction(IsolationLevel.Snapshot); var allFiles = dbContext.Files.Where(f => f.Uploaded).ToList();
var allFiles = dbContext.Files.Where(f => f.Uploaded);
foreach (var file in allFiles) foreach (var file in allFiles)
{ {
var fileName = Path.Combine(_configuration["CacheDirectory"], file.Hash); var fileName = Path.Combine(_configuration["CacheDirectory"], file.Hash);
if (!File.Exists(fileName)) var fi = new FileInfo(fileName);
if (!fi.Exists)
{ {
_logger.LogInformation("File does not exist anymore: " + fileName); _logger.LogInformation("File does not exist anymore: " + fileName);
dbContext.Files.Remove(file); dbContext.Files.Remove(file);
} else if (new FileInfo(fileName).LastAccessTime < prevTime) } else if (fi.LastAccessTime < prevTime)
{ {
MareMetrics.FilesTotalSize.Dec(fi.Length);
_logger.LogInformation("File outdated: " + fileName); _logger.LogInformation("File outdated: " + fileName);
dbContext.Files.Remove(file); dbContext.Files.Remove(file);
File.Delete(fileName); File.Delete(fileName);
@@ -72,7 +71,6 @@ namespace MareSynchronosServer
_logger.LogInformation($"Cleanup complete"); _logger.LogInformation($"Cleanup complete");
dbContext.SaveChanges(); dbContext.SaveChanges();
dbContext.Database.CommitTransaction();
} }
catch catch
{ {

View File

@@ -40,7 +40,13 @@ namespace MareSynchronosServer.Hubs
var ownFiles = await _dbContext.Files.Where(f => f.Uploaded && f.Uploader.UID == AuthenticatedUserId).ToListAsync(); var ownFiles = await _dbContext.Files.Where(f => f.Uploaded && f.Uploader.UID == AuthenticatedUserId).ToListAsync();
foreach (var file in ownFiles) foreach (var file in ownFiles)
{ {
File.Delete(Path.Combine(BasePath, file.Hash)); var fi = new FileInfo(Path.Combine(BasePath, file.Hash));
if (fi.Exists)
{
MareMetrics.FilesTotalSize.Dec(fi.Length);
MareMetrics.FilesTotal.Dec();
fi.Delete();
}
} }
_dbContext.Files.RemoveRange(ownFiles); _dbContext.Files.RemoveRange(ownFiles);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
@@ -59,7 +65,8 @@ namespace MareSynchronosServer.Hubs
int readByteCount; int readByteCount;
var buffer = new byte[chunkSize]; var buffer = new byte[chunkSize];
await using var fs = File.Open(Path.Combine(BasePath, hash), FileMode.Open, FileAccess.Read, FileShare.Read); var path = Path.Combine(BasePath, hash);
await using var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
while ((readByteCount = await fs.ReadAsync(buffer, 0, chunkSize, ct)) > 0) while ((readByteCount = await fs.ReadAsync(buffer, 0, chunkSize, ct)) > 0)
{ {
await Task.Delay(10, ct); await Task.Delay(10, ct);
@@ -67,6 +74,9 @@ namespace MareSynchronosServer.Hubs
} }
_logger.LogInformation("User " + AuthenticatedUserId + " finished downloading file: " + hash); _logger.LogInformation("User " + AuthenticatedUserId + " finished downloading file: " + hash);
MareMetrics.UserDownloadedFiles.Inc();
MareMetrics.UserDownloadedFilesSize.Inc(new FileInfo(path).Length);
} }
[Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)] [Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)]
@@ -204,6 +214,10 @@ namespace MareSynchronosServer.Hubs
await File.WriteAllBytesAsync(Path.Combine(BasePath, hash), uploadedFile.ToArray()); await File.WriteAllBytesAsync(Path.Combine(BasePath, hash), uploadedFile.ToArray());
relatedFile = _dbContext.Files.Single(f => f.Hash == hash); relatedFile = _dbContext.Files.Single(f => f.Hash == hash);
relatedFile.Uploaded = true; relatedFile.Uploaded = true;
MareMetrics.FilesTotal.Inc();
MareMetrics.FilesTotalSize.Inc(uploadedFile.Count);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
_logger.LogInformation("File " + hash + " added to DB"); _logger.LogInformation("File " + hash + " added to DB");
} }

View File

@@ -24,10 +24,15 @@ namespace MareSynchronosServer.Hubs
string userid = AuthenticatedUserId; string userid = AuthenticatedUserId;
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid); var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid);
var ownPairData = _dbContext.ClientPairs.Where(u => u.User.UID == userid); var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == userid).ToListAsync();
MareMetrics.Pairs.Dec(ownPairData.Count);
MareMetrics.PairsPaused.Dec(ownPairData.Count(c => c.IsPaused));
_dbContext.RemoveRange(ownPairData); _dbContext.RemoveRange(ownPairData);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
var otherPairData = _dbContext.ClientPairs.Include(u => u.User).Where(u => u.OtherUser.UID == userid); var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
.Where(u => u.OtherUser.UID == userid).ToListAsync();
foreach (var pair in otherPairData) foreach (var pair in otherPairData)
{ {
await Clients.User(pair.User.UID) await Clients.User(pair.User.UID)
@@ -38,6 +43,10 @@ namespace MareSynchronosServer.Hubs
}, userEntry.CharacterIdentification); }, userEntry.CharacterIdentification);
} }
MareMetrics.Pairs.Dec(otherPairData.Count());
MareMetrics.PairsPaused.Dec(otherPairData.Count(c => c.IsPaused));
MareMetrics.UsersRegistered.Dec();
_dbContext.RemoveRange(otherPairData); _dbContext.RemoveRange(otherPairData);
_dbContext.Remove(userEntry); _dbContext.Remove(userEntry);
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
@@ -94,8 +103,6 @@ namespace MareSynchronosServer.Hubs
}).ToList(); }).ToList();
} }
[Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)] [Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)]
[HubMethodName(Api.InvokeUserPushCharacterDataToVisibleClients)] [HubMethodName(Api.InvokeUserPushCharacterDataToVisibleClients)]
public async Task PushCharacterDataToVisibleClients(CharacterCacheDto characterCache, List<string> visibleCharacterIds) public async Task PushCharacterDataToVisibleClients(CharacterCacheDto characterCache, List<string> visibleCharacterIds)
@@ -119,6 +126,9 @@ namespace MareSynchronosServer.Hubs
await Clients.User(pairedUser.UID).SendAsync(Api.OnUserReceiveCharacterData, characterCache, await Clients.User(pairedUser.UID).SendAsync(Api.OnUserReceiveCharacterData, characterCache,
user.CharacterIdentification); user.CharacterIdentification);
} }
MareMetrics.UserPushData.Inc();
MareMetrics.UserPushDataTo.Inc(visibleCharacterIds.Count);
} }
[HubMethodName(Api.InvokeUserRegister)] [HubMethodName(Api.InvokeUserRegister)]
@@ -155,6 +165,8 @@ namespace MareSynchronosServer.Hubs
_logger.LogInformation("User registered: " + user.UID); _logger.LogInformation("User registered: " + user.UID);
MareMetrics.UsersRegistered.Inc();
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
return computedHash; return computedHash;
} }
@@ -212,6 +224,8 @@ namespace MareSynchronosServer.Hubs
.SendAsync(Api.OnUserAddOnlinePairedPlayer, user.CharacterIdentification); .SendAsync(Api.OnUserAddOnlinePairedPlayer, user.CharacterIdentification);
} }
} }
MareMetrics.Pairs.Inc();
} }
[Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)] [Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)]
@@ -250,6 +264,15 @@ namespace MareSynchronosServer.Hubs
IsSynced = true IsSynced = true
}, user.CharacterIdentification); }, user.CharacterIdentification);
} }
if (isPaused)
{
MareMetrics.PairsPaused.Inc();
}
else
{
MareMetrics.PairsPaused.Dec();
}
} }
[Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)] [Authorize(AuthenticationSchemes = SecretKeyAuthenticationHandler.AuthScheme)]
@@ -291,6 +314,8 @@ namespace MareSynchronosServer.Hubs
}, sender.CharacterIdentification); }, sender.CharacterIdentification);
} }
} }
MareMetrics.Pairs.Dec();
} }
private ClientPair OppositeEntry(string otherUID) => private ClientPair OppositeEntry(string otherUID) =>

View File

@@ -30,6 +30,8 @@ namespace MareSynchronosServer.Hubs
[HubMethodName(Api.InvokeHeartbeat)] [HubMethodName(Api.InvokeHeartbeat)]
public async Task<ConnectionDto> Heartbeat(string? characterIdentification) public async Task<ConnectionDto> Heartbeat(string? characterIdentification)
{ {
MareMetrics.InitializedConnections.Inc();
var userId = Context.User!.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; var userId = Context.User!.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
_logger.LogInformation("Connection from " + userId + ", CI: " + characterIdentification); _logger.LogInformation("Connection from " + userId + ", CI: " + characterIdentification);
@@ -40,6 +42,7 @@ namespace MareSynchronosServer.Hubs
if (userId != null && !isBanned && !string.IsNullOrEmpty(characterIdentification)) if (userId != null && !isBanned && !string.IsNullOrEmpty(characterIdentification))
{ {
MareMetrics.AuthorizedConnections.Inc();
_logger.LogInformation("Connection from " + userId); _logger.LogInformation("Connection from " + userId);
var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId)); var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId));
user.CharacterIdentification = characterIdentification; user.CharacterIdentification = characterIdentification;
@@ -52,6 +55,10 @@ namespace MareSynchronosServer.Hubs
IsAdmin = user.IsAdmin IsAdmin = user.IsAdmin
}; };
} }
else
{
MareMetrics.UnauthorizedConnections.Inc();
}
return new ConnectionDto() return new ConnectionDto()
{ {
@@ -70,6 +77,7 @@ namespace MareSynchronosServer.Hubs
var user = await _dbContext.Users.AsNoTracking().SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId); var user = await _dbContext.Users.AsNoTracking().SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId);
if (user != null && !string.IsNullOrEmpty(user.CharacterIdentification)) if (user != null && !string.IsNullOrEmpty(user.CharacterIdentification))
{ {
MareMetrics.AuthorizedConnections.Dec();
_logger.LogInformation("Disconnect from " + AuthenticatedUserId); _logger.LogInformation("Disconnect from " + AuthenticatedUserId);
var otherUsers = await _dbContext.ClientPairs.AsNoTracking() var otherUsers = await _dbContext.ClientPairs.AsNoTracking()
@@ -91,6 +99,10 @@ namespace MareSynchronosServer.Hubs
await Clients.All.SendAsync("UsersOnline", await Clients.All.SendAsync("UsersOnline",
await _dbContext.Users.CountAsync(u => !string.IsNullOrEmpty(u.CharacterIdentification))); await _dbContext.Users.CountAsync(u => !string.IsNullOrEmpty(u.CharacterIdentification)));
} }
else
{
MareMetrics.UnauthorizedConnections.Dec();
}
await base.OnDisconnectedAsync(exception); await base.OnDisconnectedAsync(exception);
} }

View File

@@ -0,0 +1,50 @@
using System.IO;
using System.Linq;
using MareSynchronosServer.Data;
using Microsoft.Extensions.Configuration;
using Prometheus;
namespace MareSynchronosServer
{
public class MareMetrics
{
public static readonly Counter InitializedConnections =
Metrics.CreateCounter("mare_initialized_connections", "Initialized Connections");
public static readonly Gauge UnauthorizedConnections =
Metrics.CreateGauge("mare_unauthorized_connections", "Unauthorized Connections");
public static readonly Gauge AuthorizedConnections =
Metrics.CreateGauge("mare_authorized_connections", "Authorized Connections");
public static readonly Gauge UsersRegistered = Metrics.CreateGauge("mare_users_registered", "Total Registrations");
public static readonly Gauge Pairs = Metrics.CreateGauge("mare_pairs", "Total Pairs");
public static readonly Gauge PairsPaused = Metrics.CreateGauge("mare_pairs_paused", "Total Paused Pairs");
public static readonly Gauge FilesTotal = Metrics.CreateGauge("mare_files", "Total uploaded files");
public static readonly Gauge FilesTotalSize =
Metrics.CreateGauge("mare_files_size", "Total uploaded files (bytes)");
public static readonly Counter UserPushData = Metrics.CreateCounter("mare_user_push", "Users pushing data");
public static readonly Counter UserPushDataTo =
Metrics.CreateCounter("mare_user_push_to", "Users Receiving Data");
public static readonly Counter UserDownloadedFiles = Metrics.CreateCounter("mare_user_downloaded_files", "Total Downloaded Files by Users");
public static readonly Counter UserDownloadedFilesSize = Metrics.CreateCounter("mare_user_downloaded_files_size", "Total Downloaded Files Size by Users");
public static readonly Gauge
CPUUsage = Metrics.CreateGauge("mare_cpu_usage", "Total calculated CPU usage in %");
public static readonly Gauge RAMUsage =
Metrics.CreateGauge("mare_ram_usage", "Total calculated RAM usage in bytes for Mare + MSSQL");
public static readonly Gauge NetworkOut = Metrics.CreateGauge("mare_network_out", "Network out in byte/s");
public static readonly Gauge NetworkIn = Metrics.CreateGauge("mare_network_in", "Network in in byte/s");
public static void InitializeMetrics(MareDbContext dbContext, IConfiguration configuration)
{
UsersRegistered.IncTo(dbContext.Users.Count());
Pairs.IncTo(dbContext.ClientPairs.Count());
PairsPaused.IncTo(dbContext.ClientPairs.Count(p => p.IsPaused));
FilesTotal.IncTo(dbContext.Files.Count());
FilesTotalSize.IncTo(Directory.EnumerateFiles(configuration["CacheDirectory"]).Sum(f => new FileInfo(f).Length));
}
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
@@ -20,6 +20,8 @@
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
<PackageReference Include="prometheus-net" Version="6.0.0" />
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -4,6 +4,7 @@ using Microsoft.Extensions.Hosting;
using System.Linq; using System.Linq;
using MareSynchronosServer.Data; using MareSynchronosServer.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -13,7 +14,8 @@ namespace MareSynchronosServer
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var host = CreateHostBuilder(args).Build(); var hostBuilder = CreateHostBuilder(args);
var host = hostBuilder.Build();
using (var scope = host.Services.CreateScope()) using (var scope = host.Services.CreateScope())
{ {
@@ -31,6 +33,8 @@ namespace MareSynchronosServer
var looseFiles = context.Files.Where(f => f.Uploaded == false); var looseFiles = context.Files.Where(f => f.Uploaded == false);
context.RemoveRange(looseFiles); context.RemoveRange(looseFiles);
context.SaveChanges(); context.SaveChanges();
MareMetrics.InitializeMetrics(context, services.GetRequiredService<IConfiguration>());
} }
host.Run(); host.Run();

View File

@@ -12,6 +12,7 @@ using MareSynchronosServer.Hubs;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.Connections; using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Prometheus;
using WebSocketOptions = Microsoft.AspNetCore.Builder.WebSocketOptions; using WebSocketOptions = Microsoft.AspNetCore.Builder.WebSocketOptions;
namespace MareSynchronosServer namespace MareSynchronosServer
@@ -40,6 +41,7 @@ namespace MareSynchronosServer
services.AddSingleton<SystemInfoService, SystemInfoService>(); services.AddSingleton<SystemInfoService, SystemInfoService>();
services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>(); services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>();
services.AddScoped(_ => Configuration);
services.AddDbContextPool<MareDbContext>(options => services.AddDbContextPool<MareDbContext>(options =>
{ {
@@ -62,6 +64,7 @@ namespace MareSynchronosServer
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
@@ -83,11 +86,13 @@ namespace MareSynchronosServer
KeepAliveInterval = TimeSpan.FromSeconds(10), KeepAliveInterval = TimeSpan.FromSeconds(10),
}; };
app.UseHttpMetrics();
app.UseWebSockets(webSocketOptions); app.UseWebSockets(webSocketOptions);
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
endpoints.MapHub<MareHub>(Api.Path, options => endpoints.MapHub<MareHub>(Api.Path, options =>
@@ -96,6 +101,8 @@ namespace MareSynchronosServer
options.TransportMaxBufferSize = 5242880; options.TransportMaxBufferSize = 5242880;
options.Transports = HttpTransportType.WebSockets; options.Transports = HttpTransportType.WebSockets;
}); });
endpoints.MapMetrics();
}); });
} }
} }

View File

@@ -86,44 +86,30 @@ public class SystemInfoService : IHostedService, IDisposable
var bytesSent = endNetworkOut - networkOut; var bytesSent = endNetworkOut - networkOut;
var bytesReceived = endNetworkIn - networkIn; var bytesReceived = endNetworkIn - networkIn;
using var scope = _services.CreateScope();
var dbContext = scope.ServiceProvider.GetService<MareDbContext>()!;
int uploadedFiles = 0; var usedRAM = Process.GetCurrentProcess().WorkingSet64 + Process.GetProcessesByName("sqlservr").FirstOrDefault()?.WorkingSet64 ?? 0;
var loggedInUsers = dbContext.Users.Count(u => !string.IsNullOrEmpty(u.CharacterIdentification));
var localCacheSize = Directory.EnumerateFiles(_configuration["CacheDirectory"])
.ToList().Sum(f =>
{
uploadedFiles++;
try
{
return new FileInfo(f).Length;
}
catch
{
return 0;
}
});
var cpuUsage = cpuUsageTotal * 100;
var totalNetworkOut = bytesSent / totalSPassed; var totalNetworkOut = bytesSent / totalSPassed;
var totalNetworkIn = bytesReceived / totalSPassed; var totalNetworkIn = bytesReceived / totalSPassed;
var cpuUsage = cpuUsageTotal * 100;
var usedRAM = Process.GetCurrentProcess().WorkingSet64 + Process.GetProcessesByName("sqlservr").FirstOrDefault()?.WorkingSet64 ?? 0; MareMetrics.NetworkIn.Set(totalNetworkIn);
MareMetrics.NetworkOut.Set(totalNetworkOut);
MareMetrics.CPUUsage.Set(cpuUsage);
MareMetrics.RAMUsage.Set(usedRAM);
SystemInfoDto = new SystemInfoDto() SystemInfoDto = new SystemInfoDto()
{ {
CacheUsage = localCacheSize, CacheUsage = 0,
CpuUsage = cpuUsage, CpuUsage = cpuUsage,
RAMUsage = usedRAM, RAMUsage = 0,
NetworkIn = totalNetworkIn, NetworkIn = totalNetworkIn,
NetworkOut = totalNetworkOut, NetworkOut = totalNetworkOut,
OnlineUsers = loggedInUsers, OnlineUsers = (int)MareMetrics.AuthorizedConnections.Value,
UploadedFiles = uploadedFiles UploadedFiles = 0
}; };
_hubContext.Clients.All.SendAsync(Api.OnUpdateSystemInfo, SystemInfoDto); _hubContext.Clients.All.SendAsync(Api.OnUpdateSystemInfo, SystemInfoDto);
_logger.LogInformation($"CPU:{cpuUsage:0.00}%, RAM Used:{(double)usedRAM / 1024 / 1024 / 1024:0.00}GB, Cache:{(double)localCacheSize / 1024 / 1024 / 1024:0.00}GB, Users:{loggedInUsers}, NetworkIn:{totalNetworkIn / 1024 / 1024:0.00}MB/s, NetworkOut:{totalNetworkOut / 1024 / 1024:0.00}MB/s");
} }
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)