Admin logs (#5419)

* Add admin logging, models, migrations

* Add logging damage changes

* Add Log admin flag, LogFilter, Logs admin menu tab, message
Refactor admin logging API

* Change admin log get method names

* Fix the name again

* Minute amount of reorganization

* Reset Postgres db snapshot

* Reset Sqlite db snapshot

* Make AdminLog have a composite primary key of round, id

* Minute cleanup

* Change admin system to do a type check instead of index check

* Make admin logs use C# 10 interpolated string handlers

* Implement UI on its own window
Custom controls
Searching
Add admin log converters

* Implement limits into the query

* Change logs to be put into an OutputPanel instead for text wrapping

* Add log <-> player m2m relationship back

* UI improvements, make text wrap, add separators

* Remove entity prefix from damaged log

* Add explicit m2m model, fix any players filter

* Add debug command to test bulk adding logs

* Admin logs now just kinda go

* Add histogram for database update time

* Make admin log system update run every 5 seconds

* Add a cap to the log queue and a metric for how many times it has been reached

* Add metric for logs sent in a round

* Make cvars out of admin logs queue send delay and cap

* Merge fixes

* Reset some changes

* Add test for adding and getting a single log

* Add tests for bulk adding logs

* Add test for querying logs

* Add CallerArgumentExpression to LogStringHandler methods and test

* Improve UI, fix SQLite, add searching by round

* Add entities to admin logs

* Move distinct after orderby

* Add migrations

* ef core eat my ass

* Add cvar for client logs batch size

* Sort logs from newest to oldest by default

* Merge fixes

* Reorganize tests and add one for date ordering

* Add note to log types to not change their numeric values

* Add impacts to logs, better UI filtering

* Make log add callable from shared for convenience

* Get current round id directly from game ticker

* Revert namespace change for DamageableSystem
This commit is contained in:
Javier Guardia Fernández
2021-11-22 18:49:26 +01:00
committed by GitHub
parent 0f7e81b564
commit 319aec109d
65 changed files with 7021 additions and 236 deletions

View File

@@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Preferences;
using Microsoft.Data.Sqlite;
@@ -17,17 +19,17 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Logger = Robust.Shared.Log.Logger;
using LogLevel = Robust.Shared.Log.LogLevel;
using MSLogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace Content.Server.Database
{
public interface IServerDbManager
{
void Init();
// Preferences
#region Preferences
Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile);
Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index);
@@ -38,12 +40,15 @@ namespace Content.Server.Database
// Single method for two operations for transaction.
Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot);
Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId);
#endregion
#region User Ids
// Username assignment (for guest accounts, so they persist GUID)
Task AssignUserIdAsync(string name, NetUserId userId);
Task<NetUserId?> GetAssignedUserIdAsync(string name);
#endregion
// Ban stuff
#region Bans
/// <summary>
/// Looks up a ban by id.
/// This will return a pardoned ban as well.
@@ -82,8 +87,9 @@ namespace Content.Server.Database
Task AddServerBanAsync(ServerBanDef serverBan);
Task AddServerUnbanAsync(ServerUnbanDef serverBan);
#endregion
// Player records
#region Player Records
Task UpdatePlayerRecordAsync(
NetUserId userId,
string userName,
@@ -91,15 +97,17 @@ namespace Content.Server.Database
ImmutableArray<byte> hwId);
Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel = default);
Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel = default);
#endregion
// Connection log
#region Connection Logs
Task AddConnectionLogAsync(
NetUserId userId,
string userName,
IPAddress address,
ImmutableArray<byte> hwId);
#endregion
// Admins
#region Admin Ranks
Task<Admin?> GetAdminDataForAsync(NetUserId userId, CancellationToken cancel = default);
Task<AdminRank?> GetAdminRankAsync(int id, CancellationToken cancel = default);
@@ -113,6 +121,24 @@ namespace Content.Server.Database
Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default);
Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
#endregion
#region Rounds
Task<int> AddNewRound(params Guid[] playerIds);
Task<Round> GetRound(int id);
Task AddRoundPlayers(int id, params Guid[] playerIds);
#endregion
#region Admin Logs
Task AddAdminLogs(List<QueuedLog> logs);
IAsyncEnumerable<string> GetAdminLogMessages(LogFilter? filter = null);
IAsyncEnumerable<LogRecord> GetAdminLogs(LogFilter? filter = null);
IAsyncEnumerable<JsonDocument> GetAdminLogsJson(LogFilter? filter = null);
#endregion
}
public sealed class ServerDbManager : IServerDbManager
@@ -290,11 +316,46 @@ namespace Content.Server.Database
return _db.AddAdminRankAsync(rank, cancel);
}
public Task<int> AddNewRound(params Guid[] playerIds)
{
return _db.AddNewRound(playerIds);
}
public Task<Round> GetRound(int id)
{
return _db.GetRound(id);
}
public Task AddRoundPlayers(int id, params Guid[] playerIds)
{
return _db.AddRoundPlayers(id, playerIds);
}
public Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default)
{
return _db.UpdateAdminRankAsync(rank, cancel);
}
public Task AddAdminLogs(List<QueuedLog> logs)
{
return _db.AddAdminLogs(logs);
}
public IAsyncEnumerable<string> GetAdminLogMessages(LogFilter? filter = null)
{
return _db.GetAdminLogMessages(filter);
}
public IAsyncEnumerable<LogRecord> GetAdminLogs(LogFilter? filter = null)
{
return _db.GetAdminLogs(filter);
}
public IAsyncEnumerable<JsonDocument> GetAdminLogsJson(LogFilter? filter = null)
{
return _db.GetAdminLogsJson(filter);
}
private DbContextOptions<ServerDbContext> CreatePostgresOptions()
{
var host = _cfg.GetCVar(CCVars.DatabasePgHost);