CV.Log Module¶
Overview¶
The cv.log module is a comprehensive server-side logging system for the CasualV FiveM roleplay framework. It provides unified logging to console, Discord webhooks, and the database, enabling centralized monitoring and auditing of all server events.
Features¶
- Multi-Channel Logging: Route logs to different Discord channels based on event type
- Database Persistence: All logs are saved to the
system_logstable for long-term storage and querying - Discord Integration: Real-time notifications via Discord embeds with color-coded event types
- Player Context: Track logs with character and user information for better accountability
- Type Classification: 10 different log types with unique colors and Discord icons
- Metadata Storage: JSON-based metadata storage for complex log data
Log Types¶
Each log type has a unique color and Discord emoji icon for easy visual identification:
| Type | Color | Icon | Use Case |
|---|---|---|---|
info |
Blue (#3447003) | :information_source: | General information |
success |
Green (#65280) | :white_check_mark: | Successful operations |
warning |
Yellow (#16776960) | :warning: | Warning messages |
error |
Red (#16711680) | :x: | Error messages |
admin |
Orange (#16753920) | :shield: | Admin actions |
player |
Light Blue (#9936031) | :bust_in_silhouette: | Player events |
server |
Gray (#8359053) | :gear: | Server operations |
security |
Purple (#10181046) | :lock: | Security events |
economy |
Gold (#15844367) | :moneybag: | Transaction/economy logs |
chat |
Teal (#5793266) | :speech_balloon: | Chat/communication logs |
Configuration¶
Configure the cv.log module in resources/[base]/cv_framework/config.lua:
Config.Log = {
botName = "[CasualV] SystemBot", -- Discord bot name
botAvatar = "https://img.casualv.de/assets/...", -- Discord bot avatar URL
generalWebhook = "https://discord.com/api/...", -- Default webhook for unmapped channels
channels = {
["general"] = "https://discord.com/api/webhooks/...",
["player-join-leave"] = "https://discord.com/api/webhooks/...",
["transactions"] = "https://discord.com/api/webhooks/...",
["inventory"] = "https://discord.com/api/webhooks/...",
["commands"] = "https://discord.com/api/webhooks/...",
["errors"] = "https://discord.com/api/webhooks/...",
["anticheat"] = "https://discord.com/api/webhooks/...",
}
}
Channel Configuration¶
Each channel can have its own webhook URL. If a channel is not defined, the generalWebhook is used as a fallback.
Usage¶
Basic Logging¶
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | Yes | Log title/header |
description |
string | Yes | Detailed log description |
logType |
string | No | Log type (default: "info") - see Log Types table |
channel |
string | No | Channel name for webhook routing (default: "general") |
fields |
table | No | Array of Discord embed fields for additional data |
playerData |
table | No | Player context - see Player Data table |
Player Data Structure¶
playerData = {
charId = 123, -- Character ID (from database)
citizenId = "ABC12345", -- Character citizenship ID
userId = "license:...", -- Steam account ID
name = "John Doe" -- Player display name
}
Examples¶
Simple Information Log¶
Player Join Event¶
local player = CVPlayer.GetPlayer(source)
cv.log(
"Player Joined",
string.format("Player %s (Char: %s) connected to server", player.name, player.citizenid),
"player",
"player-join-leave",
{},
{
charId = player.charId,
citizenId = player.citizenid,
userId = player.userId,
name = player.name
}
)
Transaction Log with Extra Fields¶
cv.log(
"Money Transfer",
string.format("Player transferred $%d to another player", amount),
"economy",
"transactions",
{
{
name = "Amount",
value = "$" .. amount,
inline = true
},
{
name = "From",
value = fromPlayerName,
inline = true
},
{
name = "To",
value = toPlayerName,
inline = true
}
},
{
charId = player.charId,
citizenId = player.citizenid,
userId = player.userId,
name = player.name
}
)
Error Logging¶
cv.log(
"Database Error",
"Failed to execute query: [Error details here]",
"error",
"errors",
{
{
name = "Error Code",
value = "DB_001",
inline = true
},
{
name = "Query",
value = "```sql\nSELECT * FROM...\n```",
inline = false
}
}
)
Admin Action Log¶
cv.log(
"Player Kicked",
string.format("Admin kicked player %s for: %s", playerName, reason),
"admin",
"commands",
{
{
name = "Admin",
value = adminName,
inline = true
},
{
name = "Reason",
value = reason,
inline = true
}
}
)
Database Schema¶
Logs are stored in the system_logs table with the following structure:
CREATE TABLE `system_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`log_type` varchar(50) NOT NULL, -- Log type (info, error, etc.)
`channel` varchar(50) NOT NULL, -- Discord channel identifier
`title` varchar(255) NOT NULL, -- Log title
`description` text, -- Full description
`char_id` int(11) DEFAULT NULL, -- Character ID (if applicable)
`citizen_id` varchar(50) DEFAULT NULL, -- Character citizenship ID
`user_id` varchar(100) DEFAULT NULL, -- User Steam ID
`player_name` varchar(100) DEFAULT NULL, -- Player display name
`metadata` JSON, -- Additional fields as JSON
`created_at` timestamp DEFAULT current_timestamp(), -- Creation timestamp
PRIMARY KEY (`id`),
KEY `log_type` (`log_type`),
KEY `channel` (`channel`),
KEY `char_id` (`char_id`),
KEY `citizen_id` (`citizen_id`),
KEY `user_id` (`user_id`),
KEY `created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Querying Logs¶
-- Get all error logs from the last 24 hours
SELECT * FROM system_logs
WHERE log_type = 'error'
AND created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY)
ORDER BY created_at DESC;
-- Get all actions by a specific character
SELECT * FROM system_logs
WHERE char_id = 123
ORDER BY created_at DESC;
-- Get all transaction logs for a specific player
SELECT * FROM system_logs
WHERE citizen_id = 'ABC12345'
AND log_type IN ('economy', 'transactions')
ORDER BY created_at DESC;
-- Count logs by type in the last week
SELECT log_type, COUNT(*) as count
FROM system_logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY log_type;
Discord Integration¶
Features¶
- Real-Time Notifications: Logs are sent to Discord immediately
- Embed Formatting: Each log is formatted as a rich Discord embed with:
- Title with type icon
- Description
- Color-coded by log type
- Optional fields for additional data
- Server name in footer
- Timestamp of event
- Bot avatar
Webhook Setup¶
- Create Discord channels for each log category
- Create webhooks for each channel
- Add webhook URLs to
Config.Log.channelsin config.lua - Use the channel name in
cv.log()calls to route logs appropriately
Example Discord Embed¶
`
Icon [ADMIN] Player Kicked
├─ Description: Admin kicked player John for: Spam
├─ Fields:
│ ├─ Admin: AdminName
│ ├─ Reason: Spam
├─ Footer: CasualV Default Server
└─ Timestamp: 2026-02-07T14:30:45Z