On this page
  1. tecs.log
  2. JSON Lines output
  3. Module contents
    1. Types
    2. Functions
    3. Values
  4. Types
    1. Logger
  5. Functions
    1. categoryName
    2. closeFile
    3. filePath
    4. get
    5. loggers
    6. openFile
    7. setLevel
  6. Values
    1. CRITICAL
    2. DEBUG
    3. ERROR
    4. INFO
    5. TRACE
    6. VERBOSE
    7. WARN

tecs.log

Named, leveled logging.

Create one named logger per subsystem. Logger names form the stable filtering surface:

local logger <const> = tecs.log.get("game.combat")

logger:info("wave %d spawned %d enemies", 3, 12)
logger:setLevel(tecs.log.DEBUG)

Messages go to the platform log destination, including logcat on Android and Console on Apple platforms.

Logger methods check priority before formatting. Pass raw arguments rather than formatting first. Guard work that exists only to build a message:

local snapshot <const> = {frame = 12, player = "Alice"}
if logger:enabled(tecs.log.DEBUG) then
    logger:debug("snapshot: %s", tecs.data.encodeJSON(snapshot))
end

JSON Lines output

Add a queryable file beside the platform destination:

local path <const> = tecs.io.files.writablePath("game.jsonl")
if not tecs.log.openFile(path) then
    logger:error("could not open %s", path)
end

With file output open, the earlier info call writes a line like:

{"time":12.345,"level":"INFO","logger":"game.combat","message":"wave 3 spawned 12 enemies"}

Each line records elapsed platform time, level, logger, and message. closeFile stops file output and leaves the platform destination active.

Module contents

Types

Type Kind Description
Logger record Represents a named log category.

Functions

Function Kind Description
categoryName Static Returns the name registered for a category.
closeFile Static Stops writing to the file.
filePath Static Returns the open log file path, or nil when no file is open.
get Static Returns the logger for name, creating it the first time.
loggers Static Returns every registered logger name.
openFile Static Writes every accepted line to path as JSON Lines and truncates the file.
setLevel Static Sets the minimum priority for every category.

Values

Value Type Description
CRITICAL integer Read-only. Contains the critical priority.
DEBUG integer Read-only. Contains the debug priority.
ERROR integer Read-only. Contains the error priority.
INFO integer Read-only. Contains the informational priority.
TRACE integer Read-only. Contains the trace priority.
VERBOSE integer Read-only. Contains the verbose priority.
WARN integer Read-only. Contains the warning priority.

Types

tecs.log.Logger record

Represents a named log category.

record tecs.log.Logger
    name: string
    category: integer

    critical: function(self, message: string, ...: any)
    debug: function(self, message: string, ...: any)
    enabled: function(self, priority: integer): boolean
    error: function(self, message: string, ...: any)
    info: function(self, message: string, ...: any)
    level: function(self): integer
    setLevel: function(self, priority: integer)
    trace: function(self, message: string, ...: any)
    verbose: function(self, message: string, ...: any)
    warn: function(self, message: string, ...: any)
end

tecs.log.Logger.name field

Read-only. Contains the registered logger name written to the platform log.

tecs.log.Logger.name: string

tecs.log.Logger.category field

Engine-owned. Contains the category allocated during this run. The number may change across runs, so game code should filter by name.

tecs.log.Logger.category: integer

tecs.log.Logger:critical Instance

Logs at CRITICAL. See trace for the formatting rules.

function tecs.log.Logger.critical(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

tecs.log.Logger:debug Instance

Logs at DEBUG. See trace for the formatting rules.

function tecs.log.Logger.debug(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

tecs.log.Logger:enabled Instance

Reports whether the logger would emit a message at priority.

Call this directly to guard work that only exists to build a log message, such as serializing a table. The level methods already guard themselves.

function tecs.log.Logger.enabled(self, priority: integer): boolean
Arguments
Name Type Description
self Logger
priority integer
Returns
Type Description
boolean

tecs.log.Logger:error Instance

Logs at ERROR. See trace for the formatting rules. Logging is all this does; it neither raises nor returns anything.

function tecs.log.Logger.error(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

tecs.log.Logger:info Instance

Logs at INFO. See trace for the formatting rules.

function tecs.log.Logger.info(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

tecs.log.Logger:level Instance

Returns the minimum priority this logger emits.

function tecs.log.Logger.level(self): integer
Arguments
Name Type Description
self Logger
Returns
Type Description
integer Returns the platform priority until something sets one.

tecs.log.Logger:setLevel Instance

Sets the minimum priority this logger emits.

function tecs.log.Logger.setLevel(self, priority: integer)
Arguments
Name Type Description
self Logger
priority integer One of the constants on log. The logger emits messages at this priority and drops anything lower.
Returns

None.

tecs.log.Logger:trace Instance

Logs at TRACE and applies string.format specifiers only when emitted.

The method checks the level before formatting, so a filtered call costs a load and a compare and the arguments are never touched. Building those arguments is still the caller's cost; guard that with enabled.

function tecs.log.Logger.trace(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string A string.format template when arguments follow, and a literal otherwise, so a % in a plain message is safe.
... any Formatted into message. A wrong count or a wrong specifier raises from string.format, and only on the calls that are actually emitted.
Returns

None.

tecs.log.Logger:verbose Instance

Logs at VERBOSE. See trace for the formatting rules.

function tecs.log.Logger.verbose(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

tecs.log.Logger:warn Instance

Logs at WARN. See trace for the formatting rules.

function tecs.log.Logger.warn(self, message: string, ...: any)
Arguments
Name Type Description
self Logger
message string
... any
Returns

None.

Functions

tecs.log.categoryName Static

Returns the name registered for a category.

function tecs.log.categoryName(category: integer): string

Arguments

Name Type Description
category integer

Returns

Type Description
string Never returns nil. An unregistered category comes back as "category:<number>" rather than as an error.

tecs.log.closeFile Static

Stops writing to the file.

Does nothing when no file is open, so it is safe to call on a shutdown path that does not know whether one was ever asked for.

function tecs.log.closeFile()

Arguments

None.

Returns

None.

tecs.log.filePath Static

Returns the open log file path, or nil when no file is open.

function tecs.log.filePath(): string

Arguments

None.

Returns

Type Description
string The path as it was given, not resolved against the working directory, so a relative one is only meaningful to a reader in the same place the game ran.

tecs.log.get Static

Returns the logger for name, creating it the first time.

Names are the unit of filtering, so they are what a subsystem should use: tecs.gfx, tecs.debug.events. Each maps to one SDL category, which is what SDL_SetLogPriority takes.

function tecs.log.get(name: string): log.Logger

Arguments

Name Type Description
name string Compared byte for byte, so two spellings are two categories with two levels.

Returns

Type Description
log.Logger Returns the same object on every call for a name. A new logger starts at the platform's default priority.

tecs.log.loggers Static

Returns every registered logger name.

function tecs.log.loggers(): {string}

Arguments

None.

Returns

Type Description
{string} A fresh array each call, sorted, holding only names something has already asked get for. A subsystem that has not run yet is absent.

tecs.log.openFile Static

Writes every accepted line to path as JSON Lines and truncates the file.

The platform destination keeps receiving the human-readable form, so The platform still sends its human-readable stream to tail -f, logcat, or Console.app. The file makes a log queryable after the fact: seek to an offset, read to the end.

Calling this while another file is open closes the previous file and moves subsequent lines to path.

function tecs.log.openFile(path: string): boolean

Arguments

Name Type Description
path string Truncated if it exists, created if it does not, including when it is the file already open, so this is not a way to check one is. Directories are not made.

Returns

Type Description
boolean False when the file cannot open. In that case nothing else changes and a file already open keeps receiving lines.

tecs.log.setLevel Static

Sets the minimum priority for every category.

function tecs.log.setLevel(priority: integer)

Arguments

Name Type Description
priority integer Overrides every per-logger level already set, so this is a reset and not a floor.

Returns

None.

Values

tecs.log.CRITICAL variable

Read-only. Contains the critical priority.

tecs.log.CRITICAL: integer

tecs.log.DEBUG variable

Read-only. Contains the debug priority.

tecs.log.DEBUG: integer

tecs.log.ERROR variable

Read-only. Contains the error priority.

tecs.log.ERROR: integer

tecs.log.INFO variable

Read-only. Contains the informational priority.

tecs.log.INFO: integer

tecs.log.TRACE variable

Read-only. Contains the trace priority.

tecs.log.TRACE: integer

tecs.log.VERBOSE variable

Read-only. Contains the verbose priority.

tecs.log.VERBOSE: integer

tecs.log.WARN variable

Read-only. Contains the warning priority.

tecs.log.WARN: integer