Print Module
The print module provides enhanced output functionality that replaces Lua's standard print function. It captures all output in a structured format, supports various data types, and integrates with the application's logging system for debugging and monitoring.
Functions
print(...)
Enhanced print function with output capture and formatting capabilities.
Parameters:
...(variadic): Any number of values of any type to print
Returns:
- None (void function)
Behavior:
- Captures all output in a private logs array
- Automatically formats different data types
- Concatenates multiple arguments with spaces
- Maintains chronological order (newest first in logs array)
- Accessible via
Lua.get_private(state, :logs)in Elixir
Basic Examples:
lua
-- Simple string output
print("Hello, World!")
-- Multiple arguments
print("User:", username, "ID:", user_id)
-- Numbers and calculations
print("Result:", 42 * 3.14159)
-- Booleans and nil
print("Success:", true, "Error:", nil)
-- Output captured in logs array:
-- ["Success: true Error: nil", "Result: 131.94678", "User: john_doe ID: 123", "Hello, World!"]Advanced Printing Features
Table Printing
lua
-- Tables are automatically formatted
local user = {
name = "John Doe",
email = "john@example.com",
roles = {"admin", "user"},
metadata = {
created = "2024-01-15",
verified = true
}
}
print("User data:", user)
-- Output: User data: {name = "John Doe", email = "john@example.com", roles = {"admin", "user"}, metadata = {created = "2024-01-15", verified = true}}
-- Pretty printing helper
function print_table(t, indent)
indent = indent or 0
local spacing = string.rep(" ", indent)
if type(t) ~= "table" then
print(spacing .. tostring(t))
return
end
for k, v in pairs(t) do
if type(v) == "table" then
print(spacing .. k .. ":")
print_table(v, indent + 1)
else
print(spacing .. k .. ": " .. tostring(v))
end
end
end
print_table(user)
-- Output:
-- name: John Doe
-- email: john@example.com
-- roles:
-- 1: admin
-- 2: user
-- metadata:
-- created: 2024-01-15
-- verified: trueDebug Printing
lua
-- Debug helper with source location
function debug_print(label, value, show_type)
local info = debug.getinfo(2, "Sl")
local location = info.short_src .. ":" .. info.currentline
if show_type then
print(string.format("[DEBUG %s] %s = %s (type: %s)",
location, label, tostring(value), type(value)))
else
print(string.format("[DEBUG %s] %s = %s",
location, label, tostring(value)))
end
end
-- Usage
local result = calculate_something()
debug_print("calculation result", result, true)
-- Output: [DEBUG script.lua:45] calculation result = 42.5 (type: number)Formatted Output
lua
-- Printf-style formatting
function printf(format, ...)
print(string.format(format, ...))
end
printf("Order #%d: %s - $%.2f", order_id, customer_name, total_amount)
-- Output: Order #12345: John Doe - $99.99
-- Table formatting
function print_table_formatted(headers, rows)
-- Calculate column widths
local widths = {}
for i, header in ipairs(headers) do
widths[i] = #header
for _, row in ipairs(rows) do
widths[i] = math.max(widths[i], #tostring(row[i]))
end
end
-- Print header
local header_line = ""
local separator = ""
for i, header in ipairs(headers) do
header_line = header_line .. string.format("%-" .. widths[i] .. "s ", header)
separator = separator .. string.rep("-", widths[i]) .. " "
end
print(header_line)
print(separator)
-- Print rows
for _, row in ipairs(rows) do
local row_line = ""
for i, value in ipairs(row) do
row_line = row_line .. string.format("%-" .. widths[i] .. "s ", tostring(value))
end
print(row_line)
end
end
-- Usage
print_table_formatted(
{"ID", "Name", "Status", "Amount"},
{
{1, "Order A", "Pending", "$50.00"},
{2, "Order B", "Complete", "$125.50"},
{3, "Order C", "Shipped", "$75.25"}
}
)
-- Output:
-- ID Name Status Amount
-- -- ------ -------- -------
-- 1 Order A Pending $50.00
-- 2 Order B Complete $125.50
-- 3 Order C Shipped $75.25Logging Patterns
Progress Tracking
lua
function print_progress(current, total, label)
local percentage = (current / total) * 100
local bar_width = 30
local filled = math.floor((current / total) * bar_width)
local bar = string.rep("█", filled) .. string.rep("░", bar_width - filled)
print(string.format("%s: [%s] %.1f%% (%d/%d)",
label, bar, percentage, current, total))
end
-- Usage in a loop
for i = 1, 100 do
-- Process item
process_item(i)
-- Print progress every 10 items
if i % 10 == 0 then
print_progress(i, 100, "Processing")
end
end
-- Output examples:
-- Processing: [███░░░░░░░░░░░░░░░░░░░░░░░░░░░] 10.0% (10/100)
-- Processing: [██████░░░░░░░░░░░░░░░░░░░░░░░░] 20.0% (20/100)
-- Processing: [███████████████░░░░░░░░░░░░░░░] 50.0% (50/100)Status Messages
lua
-- Status message helpers
function print_success(message)
print("✅ SUCCESS: " .. message)
end
function print_error(message)
print("❌ ERROR: " .. message)
end
function print_warning(message)
print("⚠️ WARNING: " .. message)
end
function print_info(message)
print("ℹ️ INFO: " .. message)
end
-- Usage
print_info("Starting batch processing")
print_success("Connected to database")
print_warning("Low memory available")
print_error("Failed to connect to API")Timing and Performance
lua
-- Timer utility
function timed_operation(label, func)
print("Starting: " .. label)
local start_time = os.clock()
local success, result = pcall(func)
local elapsed = os.clock() - start_time
if success then
print(string.format("✅ %s completed in %.3f seconds", label, elapsed))
return result
else
print(string.format("❌ %s failed after %.3f seconds: %s",
label, elapsed, result))
return nil
end
end
-- Usage
local result = timed_operation("Database query", function()
return database.query("main-db", "SELECT * FROM large_table", {})
end)
-- Output:
-- Starting: Database query
-- ✅ Database query completed in 0.245 secondsIntegration with Application Logging
Structured Logging
lua
function log_event(event_type, data)
local log_entry = {
timestamp = os.date("%Y-%m-%d %H:%M:%S"),
event = event_type,
data = data
}
-- Print for debugging
print("EVENT:", encoding.json(log_entry))
-- Also store in database
database.query(
"logs-db",
"INSERT INTO event_log (timestamp, event_type, data_json) VALUES (?, ?, ?)",
{log_entry.timestamp, event_type, encoding.json(data)}
)
end
-- Usage
log_event("order_processed", {
order_id = "12345",
customer_id = "cust_789",
total = 99.99,
items_count = 3
})Audit Trail
lua
function audit_log(action, entity_type, entity_id, changes)
local audit_entry = string.format(
"AUDIT: [%s] %s %s:%s | Changes: %s",
os.date("%Y-%m-%d %H:%M:%S"),
action,
entity_type,
entity_id,
encoding.json(changes)
)
print(audit_entry)
-- Store in audit log
database.query(
"audit-db",
"INSERT INTO audit_log (action, entity_type, entity_id, changes, timestamp) VALUES (?, ?, ?, ?, NOW())",
{action, entity_type, entity_id, encoding.json(changes)}
)
end
-- Usage
audit_log("UPDATE", "order", "ord_12345", {
status = {from = "pending", to = "processing"},
updated_by = "user_123"
})Best Practices
Use descriptive prefixes: Make logs searchable and filterable
luaprint("[OrderProcessor] Starting batch processing") print("[OrderProcessor] Processed order:", order_id) print("[OrderProcessor] Batch complete:", processed_count, "orders")Include context in error messages: Aid debugging
luafunction safe_operation(data) if not data.required_field then print("ERROR: Missing required_field in data:", encoding.json(data)) return false end -- Process data endAvoid printing sensitive data: Redact or mask sensitive information
luafunction print_user_info(user) print("User:", user.name, "Email:", mask_email(user.email)) end function mask_email(email) local parts = string.match(email, "^(..).*(@.*)$") if parts then return parts[1] .. "****" .. parts[2] end return "****" endImplement log levels: Control verbosity
lualocal LOG_LEVEL = { ERROR = 1, WARN = 2, INFO = 3, DEBUG = 4 } local current_level = LOG_LEVEL.INFO function log(level, ...) if level <= current_level then local prefix = "" for k, v in pairs(LOG_LEVEL) do if v == level then prefix = "[" .. k .. "]" break end end print(prefix, ...) end end -- Usage log(LOG_LEVEL.ERROR, "Critical error occurred") log(LOG_LEVEL.DEBUG, "Debug info:", debug_data) -- Won't print if level is INFO
Output Capture
- All print statements are captured in memory
- Logs are accessible from the host application
- Output is preserved even if script fails
- Maximum log size is limited to prevent memory issues
Performance
- Print operations are buffered for efficiency
- Large data structures are truncated automatically
- Circular buffer prevents unlimited memory growth
- Consider using conditional logging in performance-critical sections