Instrument a FiveM resource with fmsdk structured cloud logging — use when adding logging, telemetry, or audit trails to a FiveM Lua resource using the Fivemanage SDK.
Instrument a FiveM resource with structured cloud logging using the Fivemanage SDK (fmsdk). This skill covers logging only — not images, video, or audio.
fmsdk is a standalone FiveM resource that exposes server-side log exports. All logging is server-side only — never add log calls in client-side scripts.
Full signature:
exports.fmsdk:Log(datasetId, level, message, metadata)
Shorthand exports (preferred when level is fixed):
exports.fmsdk:Info(datasetId, message, metadata)
exports.fmsdk:Warn(datasetId, message, metadata)
exports.fmsdk:Error(datasetId, message, metadata)
datasetId: string name of the dataset in the Fivemanage dashboard (e.g. "default", "bank", "inventory")level: "debug", "info", "warn", "error", "fatal"message: a short, static, human-readable description — no string concatenation or string.formatmetadata: Lua table of key-value pairs; playerSource and targetSource are special — they trigger automatic identifier appendingExamples:
-- Player action with context
exports.fmsdk:Info("inventory", "Item added to inventory", {
playerSource = source,
item = itemName,
count = amount
})
-- Two-player interaction
exports.fmsdk:Info("bank", "Player transferred money", {
playerSource = source,
targetSource = targetId,
amount = transferAmount,
account = "savings"
})
-- Error with no player involved
exports.fmsdk:Error("default", "Database save failed", {
error = err,
table = "player_data"
})
-- Fatal event
exports.fmsdk:Log("default", "fatal", "Server data corruption detected", {
details = corruptionDetails
})
The message argument must always be a short, static, human-readable label. Never use .. string concatenation or string.format inside the message.
Bad:
exports.fmsdk:Info("default", "Player " .. GetPlayerName(source) .. " bought " .. itemName .. " x" .. count)
Good:
exports.fmsdk:Info("shop", "Player purchased item", {
playerSource = source,
playerName = GetPlayerName(source),
item = itemName,
count = count
})
All dynamic values belong in metadata.
playerSource for player-triggered eventsWhen a log is triggered by a player action, always include playerSource = source in metadata. The SDK will automatically append all player identifiers (license, steam, discord, etc.) — you do not need to collect them manually.
exports.fmsdk:Info("inventory", "Item removed", {
playerSource = source, -- identifiers auto-appended
item = itemName,
count = count
})
Use targetSource for any second player involved in the event.
| Level | When to use |
|---|---|
debug | Verbose tracing during development. Disable in production via config. |
info | Normal operational events: player joins, purchases, routine actions. |
warn | Unusual but non-breaking events: suspicious quantities, retried operations. |
error | Failures that affect functionality: DB errors, failed saves, export failures. |
fatal | Critical failures that threaten server stability or data integrity. |
Use the shorthand exports (Info, Warn, Error) to keep call sites clean. Use Log directly only when you need debug or fatal.
Organize logs by domain. Name datasets to match what you create in the Fivemanage dashboard.
| Dataset | Used for |
|---|---|
default | General server events, catch-all |
inventory | Item add/remove, shops, stashes |
bank / economy | Money transfers, transactions |
admin | Admin actions, bans, kicks |
vehicles | Spawns, modifications, impounds |
combat | Kills, damage, weapon events |
Do not dump every log into "default" — use domain-specific datasets to make filtering useful.
Include all relevant context so that each log is self-contained and searchable.
Useful metadata fields to consider:
playerSource — who triggered the eventtargetSource — a second player involvedplayerName — GetPlayerName(source) where usefulcoords — GetEntityCoords(GetPlayerPed(source)) for location-relevant eventsitem, amount, reason — domain-specific valuesresource — the resource name, useful in multi-script setupsexports.fmsdk:Log("inventory", "warn", "Suspicious item quantity detected", {
playerSource = source,
item = itemName,
amount = amount,
coords = GetEntityCoords(GetPlayerPed(source))
})
Never add exports.fmsdk calls in client-side Lua files. fmsdk logging exports are server-side only. If a client event triggers something worth logging, use a server-side callback or event handler.
Never log raw passwords, tokens, full card numbers, or other sensitive values. Log identifiers and contextual metadata that support debugging without exposing sensitive data.
The fmsdk handles batching internally — logs are queued and sent in intervals. Call exports.fmsdk:Log directly at each call site; do not buffer logs yourself.
Add fmsdk as a dependency in the resource's fxmanifest.lua so FiveM ensures it is loaded first:
dependencies {
'fmsdk'
}
When adding logging to a resource, focus on these categories of events:
warn)When asked to add logging to a resource:
Explore the resource's server-side files to understand the codebase:
Plan which events to instrument based on the categories above. Prioritize:
Group logs by domain and propose datasets. Before writing any code, present a summary of the planned log groups to the user and ask them to confirm or change the dataset name for each group. Follow the rules below.
Write the log calls following all rules:
messagemetadataplayerSource for player eventsAdd the fmsdk dependency to fxmanifest.lua if not already present.
Do not add logging to client-side files.
Do not remove any existing functionality — only add log calls.
Inform the user about any server.cfg and config.json setup required (see references).
After planning but before writing any code, you must ask the user to confirm the dataset name(s). Follow these rules:
Do not ask about every individual log. Categorize all planned logs into domain groups, assign a proposed dataset name to each group, then ask the user once per group.
For example, if the resource has item events, shop events, and error paths, that is two or three groups — not one question per log call.
"default" as the fallbackEvery Fivemanage account has a "default" dataset. If a group of logs does not clearly belong to a named domain, propose "default" for that group.
For domain-specific groups, propose the most appropriate name from the standard set:
| Proposed dataset | Fits when logs are about... |
|---|---|
default | General events, catch-all, or unclear domain |
inventory | Item add/remove, stashes, shops |
bank / economy | Money, transactions, transfers |
admin | Admin commands, kicks, bans |
vehicles | Spawns, impounds, modifications |
combat | Kills, damage, weapon use |
Show the user a clear summary. Example format:
I found logs across 3 groups. Here's how I plan to route them — let me know if you'd like to change any dataset name:
Group Example events Proposed dataset Inventory events item added, item removed, stash access inventoryEconomy events money transfer, shop purchase bankErrors & failures DB save failed, export error defaultReply with any changes (e.g. "use
economyinstead ofbank") or say "looks good" to proceed.
Always check fxmanifest.lua and add fmsdk to the dependencies block if it is not already there.
dependencies {
'fmsdk'
-- other deps...
}
After adding log calls, remind the user:
fmsdk resource on their server (download from the release page)server.cfg:
set FIVEMANAGE_LOGS_API_KEY "your_api_key_here"
ensure fmsdk
config.json inside the fmsdk resource (see references/config-examples.md)references/sdk-api.md — fmsdk export signatures and usage examplesreferences/best-practices.md — structured logging patterns and best practicesreferences/config-examples.md — server.cfg and config.json setup examples