Logbert includes a powerful Lua scripting engine (MoonSharp) that allows you to filter, transform, and analyze log messages programmatically.
- Getting Started
- Script Structure
- Filter Function
- Process Function
- Message API
- Examples
- Best Practices
- Debugging
- Click Tools → Script Editor
- The script editor window opens with a default template
┌────────────────────────────────────────────────────┐
│ [New] [Open] [Save] [Run] [Clear] │
├────────────────────────────────────────────────────┤
│ │
│ -- Lua Script Editor │
│ function filter(message) │
│ return true │
│ end │
│ │
├────────────────────────────────────────────────────┤
│ Output: │
│ Script loaded successfully │
└────────────────────────────────────────────────────┘
Toolbar Buttons:
- New - Clear editor and start fresh
- Open - Load saved script
- Save - Save current script
- Run - Execute script
- Clear - Clear output panel
Try this simple script:
-- Show only error messages
function filter(message)
return message.Level == "Error"
end
print("Error filter loaded")- Copy the script above
- Click Run
- Check output panel for "Error filter loaded"
- Return to main window - only error messages are shown
A Logbert script can define two functions:
-- Filter function: return true to show message, false to hide
function filter(message)
return true -- Show all messages
end
-- Process function: transform message before display
function process(message)
return message -- No transformation
end
-- Initialization code
print("Script loaded successfully")Execution Order:
- Script is loaded and initialized
- For each log message:
a.
filter(message)is called → decides if message is shown b. If shown,process(message)is called → transforms message c. Message is displayed
function filter(message)
-- Return true to show message, false to hide it
return boolean
endmessage- LogMessage object with properties (see Message API)
true- Message is shownfalse- Message is hidden
Show only errors:
function filter(message)
return message.Level == "Error"
endHide debug messages:
function filter(message)
return message.Level ~= "Debug"
endShow messages from specific logger:
function filter(message)
return message.Logger == "MyApp.Database"
endMultiple conditions:
function filter(message)
local isError = message.Level == "Error"
local isDatabase = string.match(message.Logger, "Database")
return isError and isDatabase
endTime-based filter:
function filter(message)
-- Only show messages during business hours
local hour = message.Timestamp.Hour
return hour >= 9 and hour <= 17
endMessage content filter:
function filter(message)
-- Show only messages containing "Exception"
return string.match(message.Message, "Exception") ~= nil
endfunction process(message)
-- Modify message and return it
return message
endmessage- LogMessage object (modifiable)
- Modified
messageobject
Uppercase logger:
function process(message)
message.Logger = string.upper(message.Logger)
return message
endAdd prefix to message:
function process(message)
message.Message = "[FILTERED] " .. message.Message
return message
endRedact sensitive data:
function process(message)
-- Remove email addresses
message.Message = string.gsub(message.Message, "%S+@%S+", "[EMAIL]")
-- Remove credit card numbers
message.Message = string.gsub(message.Message, "%d%d%d%d%-%d%d%d%d%-%d%d%d%d%-%d%d%d%d", "[CARD]")
return message
endmessage.Index -- int: Message sequence number
message.Level -- string: "Trace", "Debug", "Info", "Warning", "Error", "Fatal"
message.Logger -- string: Logger name (e.g., "MyApp.Service")
message.Message -- string: Log message textmessage.Timestamp.Year -- int: 2024
message.Timestamp.Month -- int: 1-12
message.Timestamp.Day -- int: 1-31
message.Timestamp.Hour -- int: 0-23
message.Timestamp.Minute -- int: 0-59
message.Timestamp.Second -- int: 0-59
message.Timestamp.Millisecond -- int: 0-999
message.Timestamp.Timestamp -- int: Unix timestampmessage.TimeShift.Days -- int
message.TimeShift.Hours -- int
message.TimeShift.Minutes -- int
message.TimeShift.Seconds -- int
message.TimeShift.Milliseconds -- intmessage.RawData -- object: Original data structure (format-specific)Read-Only (in filter):
- All properties are read-only in
filter()function - Used for decision making only
Modifiable (in process):
message.Logger- Can be modifiedmessage.Message- Can be modified- Other properties are effectively read-only (modifying has no effect)
Show only errors that occurred during business hours:
function filter(message)
-- Check if error
if message.Level ~= "Error" and message.Level ~= "Fatal" then
return false
end
-- Check time
local hour = message.Timestamp.Hour
local isBusinessHours = hour >= 9 and hour <= 17
-- Check weekday (Monday-Friday)
-- Note: This would require adding DayOfWeek to API
-- For now, just use hours
return isBusinessHours
end
print("Business hours error filter active")Monitor critical services and highlight:
-- List of critical services
local criticalServices = {
"Payment",
"Authentication",
"Database"
}
function filter(message)
-- Only show warnings and errors
if message.Level ~= "Warning" and
message.Level ~= "Error" and
message.Level ~= "Fatal" then
return false
end
-- Check if from critical service
for _, service in ipairs(criticalServices) do
if string.match(message.Logger, service) then
return true
end
end
return false
end
function process(message)
-- Add [CRITICAL] prefix
message.Message = "[CRITICAL] " .. message.Message
return message
end
print("Critical service monitor active")
print("Watching: Payment, Authentication, Database")Analyze and categorize exceptions:
function filter(message)
return message.Level == "Error" or message.Level == "Fatal"
end
function process(message)
local msg = message.Message
-- Categorize exception
local category = "Unknown"
if string.match(msg, "NullReference") then
category = "NULL_REF"
elseif string.match(msg, "Timeout") then
category = "TIMEOUT"
elseif string.match(msg, "Connection") then
category = "NETWORK"
elseif string.match(msg, "Permission") or string.match(msg, "Access") then
category = "SECURITY"
elseif string.match(msg, "OutOfMemory") then
category = "MEMORY"
end
-- Prepend category
message.Message = "[" .. category .. "] " .. msg
return message
end
print("Exception analyzer active")Show only first occurrence of repeated messages:
-- Track seen messages
local seenMessages = {}
function filter(message)
local key = message.Logger .. "|" .. message.Message
if seenMessages[key] then
-- Message already seen, hide it
return false
else
-- First time seeing this message
seenMessages[key] = true
return true
end
end
print("Rate limiter active - showing unique messages only")Extract and highlight slow operations:
function filter(message)
-- Show messages containing timing information
return string.match(message.Message, "%d+ms") ~= nil
end
function process(message)
-- Extract timing
local timing = string.match(message.Message, "(%d+)ms")
if timing then
local ms = tonumber(timing)
-- Categorize by speed
if ms > 5000 then
message.Message = "🔴 VERY SLOW (" .. ms .. "ms): " .. message.Message
elseif ms > 1000 then
message.Message = "🟡 SLOW (" .. ms .. "ms): " .. message.Message
end
end
return message
end
print("Performance tracker active")Flexible filter with multiple patterns:
-- Configuration
local config = {
showLevels = {"Error", "Fatal", "Warning"},
includeLoggers = {"Payment", "Database"},
excludePatterns = {"Heartbeat", "HealthCheck"},
includePatterns = {"Exception", "Failed", "Timeout"}
}
function filter(message)
-- Check level
local levelMatch = false
for _, level in ipairs(config.showLevels) do
if message.Level == level then
levelMatch = true
break
end
end
if not levelMatch then
return false
end
-- Check logger
local loggerMatch = false
for _, logger in ipairs(config.includeLoggers) do
if string.match(message.Logger, logger) then
loggerMatch = true
break
end
end
if not loggerMatch then
return false
end
-- Check exclude patterns
for _, pattern in ipairs(config.excludePatterns) do
if string.match(message.Message, pattern) then
return false
end
end
-- Check include patterns (at least one must match)
for _, pattern in ipairs(config.includePatterns) do
if string.match(message.Message, pattern) then
return true
end
end
return false
end
print("Multi-pattern filter active")-
Keep filters simple
- Complex filters slow down message processing
- Test with large log files
-
Avoid expensive operations
- Don't read files in filter/process
- Don't make network calls
- Minimize string operations
-
Cache computed values
-- Bad: Recomputes every time function filter(message) return string.match(message.Logger, "Database") ~= nil end -- Good: Cache result function filter(message) local hasDatabase = string.match(message.Logger, "Database") return hasDatabase ~= nil end
-
Use print statements
function filter(message) print("Checking message " .. message.Index) print("Level: " .. message.Level) print("Logger: " .. message.Logger) return message.Level == "Error" end
-
Check output panel
- View print output
- Look for error messages
- Verify script loaded
-
Test incrementally
- Start with simple filter
- Add complexity gradually
- Test each change
-
Use configuration tables
local config = { levels = {"Error", "Fatal"}, loggers = {"Payment", "Database"} } function filter(message) -- Use config end
-
Create helper functions
function contains(list, value) for _, item in ipairs(list) do if item == value then return true end end return false end function filter(message) local errorLevels = {"Error", "Fatal"} return contains(errorLevels, message.Level) end
-
Comment your code
-- Show only errors from critical services during business hours function filter(message) -- Check level local isError = message.Level == "Error" -- Check time local hour = message.Timestamp.Hour local isBusinessHours = hour >= 9 and hour <= 17 -- Check logger local isCritical = string.match(message.Logger, "Payment") or string.match(message.Logger, "Database") return isError and isBusinessHours and isCritical end
Error: "attempt to index a nil value"
Problem: Accessing property that doesn't exist
-- Wrong
if message.NonExistentProperty == "value" then
-- Correct
if message.Logger == "MyLogger" thenError: "filter must return boolean"
Problem: Filter function doesn't return true/false
-- Wrong
function filter(message)
message.Level == "Error" -- Missing return
end
-- Correct
function filter(message)
return message.Level == "Error"
endError: "Script timeout"
Problem: Infinite loop or very slow operation
-- Wrong
function filter(message)
while true do -- Infinite loop
-- ...
end
end
-- Correct: Use simple conditions
function filter(message)
return message.Level == "Error"
end1. Print Everything:
function filter(message)
print("=== Message " .. message.Index .. " ===")
print("Level: " .. message.Level)
print("Logger: " .. message.Logger)
print("Message: " .. message.Message)
print("Hour: " .. message.Timestamp.Hour)
print("")
return true
end2. Incremental Testing:
-- Step 1: Show everything
function filter(message)
return true
end
-- Step 2: Add level check
function filter(message)
print("Level: " .. message.Level)
return message.Level == "Error"
end
-- Step 3: Add logger check
function filter(message)
local levelOk = message.Level == "Error"
print("Level OK: " .. tostring(levelOk))
local loggerOk = string.match(message.Logger, "Database") ~= nil
print("Logger OK: " .. tostring(loggerOk))
return levelOk and loggerOk
end3. Safe Property Access:
function filter(message)
-- Check if property exists
if message.Logger then
return string.match(message.Logger, "Database") ~= nil
end
return false
endstring.match(str, pattern) -- Find pattern in string
string.find(str, pattern) -- Find pattern, returns position
string.gsub(str, pattern, rep) -- Replace pattern
string.upper(str) -- Convert to uppercase
string.lower(str) -- Convert to lowercase
string.len(str) -- String lengthtable.insert(list, value) -- Add to list
table.remove(list, index) -- Remove from list
#list -- List lengthif condition then
-- code
elseif other_condition then
-- code
else
-- code
end-- For loop
for i = 1, 10 do
print(i)
end
-- While loop
while condition do
-- code
end
-- For each
for index, value in ipairs(list) do
print(value)
end== -- Equal
~= -- Not equal
> -- Greater than
< -- Less than
>= -- Greater or equal
<= -- Less or equal
and -- Logical AND
or -- Logical OR
not -- Logical NOT- Lua 5.2 Reference
- MoonSharp Documentation
- Lua String Patterns
- Example scripts in
examples/scripts/folder (planned)