Skip to main content
The Logger component provides a centralized logging system with multiple output targets: console, files, database, and Discord webhooks. It supports different log levels for filtering and categorizing log messages.

Log Levels

The Logger supports 6 log levels with increasing severity:
LevelMethodUse CaseConsole Color
0LogLegacy/generalDefault
1TraceDetailed debuggingDefault
2InfoGeneral informationBlue
3WarnWarningsYellow
4ErrorErrorsRed
5CriticalCritical failuresBright Red

Method Signature

Important: All logger methods use this signature (not the commonly assumed signature):
Logger:MethodName(component, log, flags, data)
Parameters:
NameTypeRequiredDescription
componentstringYesComponent/resource name
logstringYesLog message
flagstableNoOutput flags {console, file, discord, database}
dataanyNoAdditional data to store (database only)

Logging Methods

Info

Log informational message. Example:
-- Server side
Logger:Info('MyResource', 'Player joined server')

-- With flags
Logger:Info('MyResource', 'Important event occurred', {
    console = true,
    file = true,
    discord = true
})

-- With data
Logger:Info('MyResource', 'Transaction completed', {
    console = true,
    database = true
}, {
    amount = 5000,
    from = 'player1',
    to = 'player2'
})

Warn

Log warning message. Example:
-- Server side
Logger:Warn('AntiCheat', 'Suspicious activity detected', {
    console = true,
    discord = true
})

Error

Log error message. Example:
-- Server side
Logger:Error('Database', 'Failed to save player data', {
    console = true,
    file = true,
    discord = true
}, {
    playerId = 123,
    error = errorMessage
})

Critical

Log critical failure. Example:
-- Server side
Logger:Critical('Core', 'System failure detected', {
    console = true,
    file = true,
    discord = {
        embed = true,
        type = 'error',
        content = '@everyone Critical system failure!'
    }
}, {
    system = 'database',
    uptime = os.time()
})

Trace

Log detailed debugging information. Example:
-- Server side
Logger:Trace('Inventory', 'Item added to inventory', {
    console = true
}, {
    item = 'water',
    count = 5,
    slot = 3
})

Log (Legacy)

General logging (retained for backward compatibility). Example:
-- Server side
Logger:Log('MyResource', 'Generic log message')
Log() method is legacy. Use Info(), Warn(), Error(), etc. instead for proper log level categorization.

Output Flags

The flags parameter controls where logs are output:

Console Output

flags = {
    console = true  -- Print to server console
}
Console Format:
[INFO]  [MyResource] Player joined server
[WARN]  [AntiCheat] Suspicious activity
[ERROR] [Database] Connection failed
Log Level Filter:
  • Controlled by Convar.LOGGING.value
  • Only logs >= this level will print to console
  • Configured in server.cfg

File Output

flags = {
    file = true  -- Write to log file
}
File Structure:
logs/
├── MyResource/
│   ├── 2025-01-15.log
│   └── 2025-01-16.log
├── Database/
│   └── 2025-01-15.log
└── AntiCheat/
    └── 2025-01-15.log
File Format:
[INFO]     [02:30:45 PM]    Player joined server
[WARN]     [02:31:12 PM]    Suspicious activity detected
[ERROR]    [02:32:00 PM]    Connection failed
Files are organized by component name and date. New file created daily.

Discord Output

Discord logging only fires when GlobalState.IsProduction is true AND the log level meets the minimum threshold (Convar.LOGGING.value). It will not send webhooks in development mode.
-- Simple Discord webhook
flags = {
    discord = true
}

-- Advanced Discord embed
flags = {
    discord = {
        embed = true,
        type = 'info',  -- or 'success', 'warning', 'error', 'critical'
        title = 'System Alert',
        description = 'Optional description',
        content = 'Message content',
        webhook = 'https://discord.com/api/webhooks/...'  -- Optional override webhook
    }
}
Discord Webhook Configuration: Set in server.cfg:
set discord_log_webhook "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN"
Embed Colors:
  • trace - Gray
  • info - Blue
  • success - Green
  • warning - Yellow
  • error - Red
  • critical - Bright Red
Example:
Logger:Info('AntiCheat', 'Player banned', {
    console = true,
    discord = {
        embed = true,
        type = 'warning',
        title = 'Player Banned',
        description = 'Automatic ban for cheating',
        content = '@here Cheater detected'
    }
}, {
    player = 'PlayerName',
    reason = 'Aimbot detected',
    evidence = 'Screenshot URL'
})

Database Output

flags = {
    database = true
}
Database Storage:
  • Collection: logs
  • Only in production environment
  • Must pass data parameter for context
Document Structure:
{
    date = 1705334400,      -- Unix timestamp
    level = 2,               -- Log level (1-5)
    component = 'MyResource',
    log = 'Transaction completed',
    data = {                 -- Your custom data
        amount = 5000,
        from = 'player1',
        to = 'player2'
    }
}
Database logging only works when all of these conditions are met:
  1. Proxy.DatabaseReady is true (database connection established)
  2. GlobalState.IsProduction is true (environment set to "prod")
  3. flags.database = true is set in the flags parameter

Complete Examples

Basic Logging

-- Simple info log to console
Logger:Info('MyResource', 'Server started')

-- Warning with file logging
Logger:Warn('Security', 'Failed login attempt', {
    console = true,
    file = true
})

-- Error with all outputs
Logger:Error('Database', 'Connection lost', {
    console = true,
    file = true,
    discord = true,
    database = true
}, {
    host = 'localhost',
    port = 27017,
    error = errorMessage
})

Player Action Logging

-- Log player purchase
AddEventHandler('shop:server:Purchase', function(itemName, price)
    local src = source
    local player = Fetch:Source(src)
    local char = player:GetData('Character')

    Logger:Info('Shop', string.format(
        '%s %s purchased %s for $%d',
        char:GetData('First'),
        char:GetData('Last'),
        itemName,
        price
    ), {
        console = true,
        file = true,
        database = true
    }, {
        characterSID = char:GetData('SID'),
        accountID = player:GetData('AccountID'),
        item = itemName,
        price = price,
        timestamp = os.time()
    })
end)

Anti-Cheat Detection

-- Detect and log cheating
AddEventHandler('anticheat:detection', function(source, cheatType, details)
    local player = Fetch:Source(source)
    local char = player:GetData('Character')

    Logger:Critical('AntiCheat', string.format(
        'CHEAT DETECTED: %s by %s %s (SID: %d)',
        cheatType,
        char:GetData('First'),
        char:GetData('Last'),
        char:GetData('SID')
    ), {
        console = true,
        file = true,
        discord = {
            embed = true,
            type = 'critical',
            title = '🚨 Cheat Detection',
            content = '@here Immediate action required',
            description = string.format('**Type:** %s\n**Player:** %s %s\n**Details:** %s',
                cheatType,
                char:GetData('First'),
                char:GetData('Last'),
                details
            )
        },
        database = true
    }, {
        characterSID = char:GetData('SID'),
        accountID = player:GetData('AccountID'),
        cheatType = cheatType,
        details = details,
        playerCoords = GetEntityCoords(GetPlayerPed(source))
    })

    -- Ban player
    DropPlayer(source, 'Banned for cheating: ' .. cheatType)
end)

Best Practices

Use the right level for the right situation:
-- ✅ Good
Logger:Info('Shop', 'Purchase completed')
Logger:Warn('Security', 'Multiple failed login attempts')
Logger:Error('Database', 'Connection failed')
Logger:Critical('Core', 'System shutdown imminent')

-- ❌ Bad
Logger:Error('Shop', 'Purchase completed')  -- Not an error
Logger:Info('Core', 'Database exploded')    -- Too severe for Info
Always pass data parameter for important logs:
-- ✅ Good - includes context
Logger:Error('Inventory', 'Failed to add item', {
    console = true,
    database = true
}, {
    characterSID = char:GetData('SID'),
    item = itemName,
    count = count,
    error = errorMessage
})

-- ❌ Bad - no context
Logger:Error('Inventory', 'Failed to add item')
Use file logging for high-frequency logs:
-- ✅ Good - file only for frequent logs
Logger:Trace('Movement', 'Player moved', {
    console = false,
    file = true
})

-- ❌ Bad - console spam
Logger:Info('Movement', 'Player moved', {
    console = true
})

Next Steps

Core - Fetch

Player and character data access

Core - Database

Database operations

Configuration

Server configuration

Middleware

Event middleware system
Pro Tip: Create helper functions for common logging patterns:
function LogPlayerAction(component, action, char, data)
    Logger:Info(component, string.format(
        '%s %s: %s',
        char:GetData('First'),
        char:GetData('Last'),
        action
    ), {
        console = true,
        file = true,
        database = true
    }, data)
end