Examples
Server Administration
Ban system, logging, and server monitoring examples
These examples are AI-generated and has not been reviewed for accuracy. Use them as a starting point and verify correctness before deploying in production.
Server Administration
Examples for server administration using MongoDB.
Ban System
--[[
Ban System
Manage player bans with expiration and history
]]
local BanSystem = {}
function BanSystem.Initialize(db)
BanSystem.db = db
BanSystem.bans = db:Collection("bans")
BanSystem.banHistory = db:Collection("ban_history")
-- Indexes
BanSystem.bans:CreateIndex({ steamid = 1 }, true, "steamid_unique")
BanSystem.bans:CreateIndex({ expires_at = 1 }, false, "expiry_index")
BanSystem.banHistory:CreateIndex({ steamid = 1, banned_at = -1 }, false, "player_history")
end
-- Ban a player
function BanSystem.Ban(steamid, reason, duration, adminSteamid, callback)
local ban = {
steamid = steamid,
reason = reason,
banned_at = os.time(),
expires_at = duration and (os.time() + duration) or nil,
permanent = duration == nil,
admin_steamid = adminSteamid
}
-- Add to active bans
BanSystem.bans:UpdateOneAsync(
{ steamid = steamid },
{ ["$set"] = ban },
function(err)
if err then
if callback then callback(false, err) end
return
end
-- Add to history
BanSystem.banHistory:InsertOneAsync({
steamid = steamid,
reason = reason,
duration = duration,
permanent = duration == nil,
banned_at = os.time(),
admin_steamid = adminSteamid
}, function()
if callback then callback(true) end
end)
end
)
end
-- Unban a player
function BanSystem.Unban(steamid, adminSteamid, callback)
BanSystem.bans:DeleteOneAsync(
{ steamid = steamid },
function(err, deleted)
if deleted > 0 then
-- Log the unban
BanSystem.banHistory:InsertOneAsync({
steamid = steamid,
action = "unban",
unbanned_at = os.time(),
admin_steamid = adminSteamid
})
end
if callback then callback(deleted > 0) end
end
)
end
-- Check if player is banned
function BanSystem.IsBanned(steamid, callback)
BanSystem.bans:FindOneAsync({ steamid = steamid }, function(err, ban)
if not ban then
callback(false, nil)
return
end
-- Check if expired
if ban.expires_at and ban.expires_at < os.time() then
-- Remove expired ban
BanSystem.bans:DeleteOneAsync({ steamid = steamid })
callback(false, nil)
return
end
callback(true, ban)
end)
end
-- Get player's ban history
function BanSystem.GetHistory(steamid, callback)
BanSystem.banHistory:FindAsync(
{ steamid = steamid },
100,
function(err, history)
callback(history or {})
end
)
end
-- Get all active bans
function BanSystem.GetAllBans(callback)
BanSystem.bans:FindAsync({}, nil, function(err, bans)
callback(bans or {})
end)
end
-- Cleanup expired bans
function BanSystem.CleanupExpired(callback)
BanSystem.bans:DeleteManyAsync(
{
permanent = false,
expires_at = { ["$lt"] = os.time() }
},
function(err, deleted)
if callback then callback(deleted) end
end
)
end
-- Get ban statistics
function BanSystem.GetStats(callback)
BanSystem.bans:AggregateAsync({
{
["$group"] = {
_id = nil,
total = { ["$sum"] = 1 },
permanent = {
["$sum"] = {
["$cond"] = { ["if"] = "$permanent", ["then"] = 1, ["else"] = 0 }
}
},
temporary = {
["$sum"] = {
["$cond"] = { ["if"] = "$permanent", ["then"] = 0, ["else"] = 1 }
}
}
}
}
}, function(err, results)
if results and #results > 0 then
callback(results[1])
else
callback({ total = 0, permanent = 0, temporary = 0 })
end
end)
end
return BanSystem
Logging System
--[[
Logging System
Server event logging and analytics
]]
local Logger = {}
Logger.Levels = {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3
}
Logger.Categories = {
"player",
"economy",
"combat",
"admin",
"system",
"chat"
}
function Logger.Initialize(db)
Logger.db = db
Logger.logs = db:Collection("logs")
-- Indexes for efficient querying
Logger.logs:CreateIndex({ timestamp = -1 }, false, "time_desc")
Logger.logs:CreateIndex({ category = 1, timestamp = -1 }, false, "category_time")
Logger.logs:CreateIndex({ steamid = 1, timestamp = -1 }, false, "player_time")
Logger.logs:CreateIndex({ level = 1 }, false, "level_index")
end
-- Log an event
function Logger.Log(level, category, message, data)
local entry = {
level = level,
category = category,
message = message,
data = data or {},
timestamp = os.time(),
server_id = GetHostName and GetHostName() or "unknown"
}
-- Fire and forget - don't block for logging
Logger.logs:InsertOneAsync(entry, function(err)
if err then
print("[Logger] Failed to log:", err)
end
end)
end
-- Convenience methods
function Logger.Debug(category, message, data)
Logger.Log(Logger.Levels.DEBUG, category, message, data)
end
function Logger.Info(category, message, data)
Logger.Log(Logger.Levels.INFO, category, message, data)
end
function Logger.Warn(category, message, data)
Logger.Log(Logger.Levels.WARN, category, message, data)
end
function Logger.Error(category, message, data)
Logger.Log(Logger.Levels.ERROR, category, message, data)
end
-- Query logs
function Logger.Query(filter, limit, callback)
limit = limit or 100
Logger.logs:AggregateAsync({
{ ["$match"] = filter },
{ ["$sort"] = { timestamp = -1 } },
{ ["$limit"] = limit }
}, function(err, results)
callback(results or {})
end)
end
-- Get logs by category
function Logger.GetByCategory(category, limit, callback)
Logger.Query({ category = category }, limit, callback)
end
-- Get logs by player
function Logger.GetByPlayer(steamid, limit, callback)
Logger.Query({ ["data.steamid"] = steamid }, limit, callback)
end
-- Get logs by time range
function Logger.GetByTimeRange(startTime, endTime, callback)
Logger.Query({
timestamp = {
["$gte"] = startTime,
["$lte"] = endTime
}
}, 1000, callback)
end
-- Get error logs
function Logger.GetErrors(limit, callback)
Logger.Query({ level = Logger.Levels.ERROR }, limit, callback)
end
-- Get log statistics
function Logger.GetStats(hours, callback)
hours = hours or 24
local since = os.time() - (hours * 3600)
Logger.logs:AggregateAsync({
{
["$match"] = { timestamp = { ["$gte"] = since } }
},
{
["$group"] = {
_id = "$category",
count = { ["$sum"] = 1 },
errors = {
["$sum"] = {
["$cond"] = {
["if"] = { ["$eq"] = { "$level", Logger.Levels.ERROR } },
["then"] = 1,
["else"] = 0
}
}
}
}
},
{ ["$sort"] = { count = -1 } }
}, function(err, results)
callback(results or {})
end)
end
-- Cleanup old logs
function Logger.Cleanup(daysToKeep, callback)
local cutoff = os.time() - (daysToKeep * 24 * 3600)
Logger.logs:DeleteManyAsync(
{ timestamp = { ["$lt"] = cutoff } },
function(err, deleted)
if callback then callback(deleted) end
end
)
end
return Logger
Server Monitor
--[[
Server Monitor
Track server performance and player activity
]]
local Monitor = {}
function Monitor.Initialize(db)
Monitor.db = db
Monitor.snapshots = db:Collection("server_snapshots")
Monitor.playerSessions = db:Collection("player_sessions")
-- Indexes
Monitor.snapshots:CreateIndex({ timestamp = -1 }, false, "time_desc")
Monitor.playerSessions:CreateIndex({ steamid = 1, joined_at = -1 }, false, "player_sessions")
end
-- Record server snapshot
function Monitor.RecordSnapshot()
local snapshot = {
timestamp = os.time(),
player_count = player and #player.GetAll() or 0,
map = game and game.GetMap() or "unknown",
hostname = GetHostName and GetHostName() or "unknown",
tick_rate = 1 / engine.TickInterval(),
-- Add more metrics as needed
}
Monitor.snapshots:InsertOneAsync(snapshot, function() end)
end
-- Get server statistics
function Monitor.GetStats(hours, callback)
hours = hours or 24
local since = os.time() - (hours * 3600)
Monitor.snapshots:AggregateAsync({
{
["$match"] = { timestamp = { ["$gte"] = since } }
},
{
["$group"] = {
_id = nil,
avg_players = { ["$avg"] = "$player_count" },
max_players = { ["$max"] = "$player_count" },
min_players = { ["$min"] = "$player_count" },
snapshots = { ["$sum"] = 1 }
}
}
}, function(err, results)
if results and #results > 0 then
callback(results[1])
else
callback({ avg_players = 0, max_players = 0, min_players = 0, snapshots = 0 })
end
end)
end
-- Track player session
function Monitor.PlayerJoined(steamid, username)
Monitor.playerSessions:InsertOneAsync({
steamid = steamid,
username = username,
joined_at = os.time(),
left_at = nil,
duration = nil
})
end
function Monitor.PlayerLeft(steamid)
Monitor.playerSessions:UpdateOneAsync(
{ steamid = steamid, left_at = nil },
{
["$set"] = { left_at = os.time() }
}
)
end
-- Get player activity
function Monitor.GetPlayerActivity(steamid, days, callback)
days = days or 30
local since = os.time() - (days * 24 * 3600)
Monitor.playerSessions:AggregateAsync({
{
["$match"] = {
steamid = steamid,
joined_at = { ["$gte"] = since }
}
},
{
["$group"] = {
_id = nil,
sessions = { ["$sum"] = 1 },
total_time = {
["$sum"] = {
["$subtract"] = {
{ ["$ifNull"] = { "$left_at", os.time() } },
"$joined_at"
}
}
},
first_seen = { ["$min"] = "$joined_at" },
last_seen = { ["$max"] = "$joined_at" }
}
}
}, function(err, results)
if results and #results > 0 then
callback(results[1])
else
callback({ sessions = 0, total_time = 0 })
end
end)
end
-- Get peak hours
function Monitor.GetPeakHours(days, callback)
days = days or 7
local since = os.time() - (days * 24 * 3600)
Monitor.snapshots:AggregateAsync({
{
["$match"] = { timestamp = { ["$gte"] = since } }
},
{
["$project"] = {
hour = { ["$mod"] = {
{ ["$floor"] = { ["$divide"] = { "$timestamp", 3600 } } },
24
}},
player_count = 1
}
},
{
["$group"] = {
_id = "$hour",
avg_players = { ["$avg"] = "$player_count" }
}
},
{ ["$sort"] = { avg_players = -1 } }
}, function(err, results)
callback(results or {})
end)
end
return Monitor
GMod Integration
--[[
Admin System Integration for Garry's Mod
]]
require("mongo")
local client = MongoDB.Client("mongodb://localhost:27017")
local db = client:Database("gmod_server")
-- Initialize systems
BanSystem.Initialize(db)
Logger.Initialize(db)
Monitor.Initialize(db)
-- Check bans on connect
hook.Add("CheckPassword", "CheckBan", function(steamid, ip, svPassword, clPassword, name)
-- Note: CheckPassword is synchronous, so we need a cached ban list
-- or use a different approach
end)
-- Track player activity
hook.Add("PlayerInitialSpawn", "TrackJoin", function(ply)
Monitor.PlayerJoined(ply:SteamID(), ply:Nick())
Logger.Info("player", "Player joined", {
steamid = ply:SteamID(),
name = ply:Nick(),
ip = ply:IPAddress()
})
end)
hook.Add("PlayerDisconnected", "TrackLeave", function(ply)
Monitor.PlayerLeft(ply:SteamID())
Logger.Info("player", "Player left", {
steamid = ply:SteamID(),
name = ply:Nick()
})
end)
-- Log chat messages
hook.Add("PlayerSay", "LogChat", function(ply, text)
Logger.Info("chat", "Chat message", {
steamid = ply:SteamID(),
name = ply:Nick(),
message = text
})
end)
-- Record server snapshots every minute
timer.Create("ServerSnapshot", 60, 0, function()
Monitor.RecordSnapshot()
end)
-- Cleanup old data daily
timer.Create("DailyCleanup", 24 * 3600, 0, function()
Logger.Cleanup(30) -- Keep 30 days
BanSystem.CleanupExpired()
print("[Server] Daily cleanup complete")
end)
-- Admin commands
concommand.Add("ban", function(ply, cmd, args)
if not ply:IsAdmin() then return end
local target = args[1]
local duration = tonumber(args[2]) or nil -- nil = permanent
local reason = table.concat(args, " ", 3) or "No reason"
BanSystem.Ban(target, reason, duration and duration * 60 or nil, ply:SteamID(), function(success)
if success then
ply:ChatPrint("Player banned successfully")
else
ply:ChatPrint("Failed to ban player")
end
end)
end)
concommand.Add("unban", function(ply, cmd, args)
if not ply:IsAdmin() then return end
local target = args[1]
BanSystem.Unban(target, ply:SteamID(), function(success)
if success then
ply:ChatPrint("Player unbanned")
else
ply:ChatPrint("Player was not banned")
end
end)
end)
concommand.Add("serverstats", function(ply)
Monitor.GetStats(24, function(stats)
ply:ChatPrint("=== Server Stats (24h) ===")
ply:ChatPrint("Avg Players: " .. string.format("%.1f", stats.avg_players))
ply:ChatPrint("Peak: " .. stats.max_players)
end)
end)
Next Steps
- API Reference - Complete method documentation
- Getting Started - Setup guide