Written from a line-by-line source review; every example output is from a real run.
Introduction
The log plugin provides structured logging: severity levels (trace, debug, info, warn, error), printf-style formatted messages, and multiple parallel outputs (sinks). It manages a single global logger state: a level threshold, a format (plain or JSON), and a sink list. Every log call is thread-safe: a mutex protects the state and all writes, so it is safe to use from background threads.
Levels and filtering
The levels run from least to most severe: trace < debug < info < warn < error. SetLevel sets a threshold: only messages at or above it get out, the rest are suppressed by the plugin. For example, at an info threshold, Trace and Debug are suppressed, while Info, Warn and Error are written. The emit functions therefore return 1 if the message went out and 0 if the filter suppressed it.
Sinks (outputs)
A sink is the destination the log goes to. There are three kinds: “stderr” (standard error), “file” (a file, with optional rotation) and “syslog” (the system log on Linux; silently ignored on Windows). At most 8 sinks can exist at once, and a message is written to all of them. Add a sink with SetSink / SetSinkRotate / SetSinkRotateTime.
Format
There are two output formats. “plain” (the default) produces a human-readable line: a timestamp, the level, then the message. “json” writes one JSON object per line (with ts, level, msg fields), suitable for machine processing. The message itself is printf-style: %d %x %f %s %% placeholders, with optional width and precision.
Loading the plugin
plugin "../plugins/print/PrintPlugin"; plugin "../plugins/log/LogPlugin";
A typical flow
log.SetLevel("info");
log.SetFormat("plain");
log.SetSink("stderr", "");
log.SetSink("file", "app.log");
log.Info("user=%s action=%s", "alice", "login");
log.Close();What to know about every function (the basics)
The logger state is global and persistent for the run of the script: the settings (level, format, sinks) stay in effect until Close.
The configuration functions (SetLevel, SetFormat, SetSink) return 0 for an unknown value or a failed operation, and 1 for a valid setting — they do not raise an error for an unknown level/format.
An error (stopping the script) is caused only by a wrong argument count or type.
The emit functions (Trace…Error) take at least one argument: the format string; the further arguments fill the placeholders.
A log message is at most 4096 bytes after formatting; anything longer is truncated.
On Windows the “syslog” sink is silent: SetSink returns 1 but nothing is written.
How to read the signatures
The , ... at the end of a signature marks a variable number of further arguments (to fill the printf placeholders). The type after the -> arrow is the return type. For example, log.Info(fmt, ...) -> int takes a format string and any further arguments and returns an integer (1=emitted, 0=suppressed).
Configuration
Setting the level threshold, the format, and the output sinks.
log.SetLevel
log.SetLevel(level) -> int
Sets the level threshold: only messages at or above it get out.
| Parameter | Type | Description |
|---|---|---|
| level | string | The threshold level: trace, debug, info, warn or error (case-insensitive). |
1 for a valid level; 0 if you gave an unknown level name.
printf("%d\n", log.SetLevel("info"));
printf("%d\n", log.SetLevel("nope"));1 0
For controlling how verbose logging is: debug or trace during development, info or warn in production. So the same code produces less noise in a production environment.
log.SetFormat
log.SetFormat(format) -> int
Sets the output format: human-readable (plain) or machine (json).
| Parameter | Type | Description |
|---|---|---|
| format | string | “plain” (the default) or “json” (case-insensitive). |
1 for a valid format; 0 if unknown.
printf("%d\n", log.SetFormat("plain"));
printf("%d\n", log.SetFormat("json"));
printf("%d\n", log.SetFormat("xml"));1 1 0
Use JSON when a machine processes the log (a log aggregator, an analysis tool); plain when a human reads it on the terminal. The setting applies to every message emitted afterwards.
log.SetSink
log.SetSink(type, target) -> int
Adds a new output (sink) to the logger. A message is written to all sinks.
| Parameter | Type | Description |
|---|---|---|
| type | string | “stderr”, “file” or “syslog”. |
| target | string | The target depends on the type: for file, the path; for syslog, the ident (Linux); for stderr, ignored. |
1 if it was added; 0 if the type is unknown, the file cannot be opened, or the sink list (max 8) is full.
printf("%d\n", log.SetSink("stderr", ""));
printf("%d\n", log.SetSink("bogus", ""));1 0
You can add several sinks at once: for example a stderr for the developer console and a file for the durable log. The file sink appends (opens in append mode), it does not overwrite an existing log.
log.SetSinkRotate
log.SetSinkRotate(type, target, maxBytes, maxFiles) -> int
Adds a file sink with size-based rotation: when the file reaches maxBytes, the plugin rotates it (target, target.1, target.2, …).
| Parameter | Type | Description |
|---|---|---|
| type | string | Typically “file” (rotation has no effect on other types, but the sink is still added). |
| target | string | The path of the log file. |
| maxBytes | int | The file size limit in bytes; on reaching it, it rotates. |
| maxFiles | int | The number of files kept (the oldest is dropped on rotation). |
1 if it was added; 0 on error (for example the file cannot be opened, or the sink list is full).
// rotate every 1 MB, keep 5 files
printf("%d\n", log.SetSinkRotate("file", "app.log", 1048576, 5));
log.Close();1
For long-running services, so the log file does not grow without bound. maxBytes and maxFiles together set the maximum disk space spent on the log.
log.SetSinkRotateTime
log.SetSinkRotateTime(type, target, when, maxFiles) -> int
Adds a file sink with time-based rotation: at the given time it renames the active file with a date suffix and opens a new file.
| Parameter | Type | Description |
|---|---|---|
| type | string | Typically “file”. |
| target | string | The path of the log file. |
| when | string | The rotation time, currently “daily” (every day, at the local day change). |
| maxFiles | int | The number of dated files kept; 0 means no automatic cleanup (upper bound 64). |
1 if it was added; 0 on error (an unknown when value or a failed file open).
// rotate daily, keep 7 days of logs
printf("%d\n", log.SetSinkRotateTime("file", "app.log", "daily",
7));
log.Close();1
When you want to split the log by calendar days (for example one file per day). Old days' files get a date suffix; maxFiles automatically cleans up the very old ones.
Logging (by level)
Emitting log messages by severity level. All are printf-style: the first argument is the format, the rest fill the placeholders.
log.Trace
log.Trace(fmt, ...) -> int
The most detailed level (tracing). Gets out only if the threshold is trace.
| Parameter | Type | Description |
|---|---|---|
| fmt | string | The printf-style format string (%d %x %f %s %%, opt. width/precision). |
| ... | any | Further arguments that fill the placeholders. |
1 if it was emitted; 0 if the level threshold suppressed it.
log.SetLevel("info");
log.SetSink("stderr", "");
// the threshold is info, so trace is suppressed
printf("%d\n", log.Trace("entering the function"));0
For very fine-grained tracing (function entry, loop variables). In production you almost always suppress it with the threshold, but you can turn it on to chase a bug.
log.Debug
log.Debug(fmt, ...) -> int
A developer/diagnostic message. Gets out only at a debug or lower threshold.
| Parameter | Type | Description |
|---|---|---|
| fmt | string | The printf-style format string. |
| ... | any | Arguments that fill the placeholders. |
1 if it was emitted; 0 if the threshold suppressed it.
log.SetLevel("info");
log.SetSink("stderr", "");
printf("%d\n", log.Debug("cache size=%d", 128));0
For logging intermediate state and computed values during development. In production you turn it off by setting the threshold to info, without having to delete it from the code.
log.Info
log.Info(fmt, ...) -> int
A general informational message about normal operation.
| Parameter | Type | Description |
|---|---|---|
| fmt | string | The printf-style format string. |
| ... | any | Arguments that fill the placeholders. |
1 if it was emitted; 0 if the threshold suppressed it.
log.SetLevel("info");
log.SetFormat("plain");
log.SetSink("stderr", "");
log.Info("user=%s action=%s", "alice", "login");
log.Close();<time> INFO user=alice action=login
For the milestones of normal operation (startup, request served, task done). This is the typical production threshold, so put the genuinely interesting but non-error events here.
log.Warn
log.Warn(fmt, ...) -> int
A warning: not an error, but a suspicious or noteworthy situation.
| Parameter | Type | Description |
|---|---|---|
| fmt | string | The printf-style format string. |
| ... | any | Arguments that fill the placeholders. |
1 if it was emitted; 0 if the threshold suppressed it.
log.SetLevel("info");
log.SetFormat("plain");
log.SetSink("stderr", "");
log.Warn("disk %d%% full", 92);
log.Close();<time> WARN disk 92% full
For situations that do not stop the program but deserve attention (an approaching resource limit, a deprecated setting, a retry).
log.Error
log.Error(fmt, ...) -> int
An error message: something went wrong, but the logger itself does not stop.
| Parameter | Type | Description |
|---|---|---|
| fmt | string | The printf-style format string. |
| ... | any | Arguments that fill the placeholders. |
1 if it was emitted; 0 if the threshold suppressed it (effectively only at a very high threshold).
log.SetLevel("info");
log.SetFormat("json");
log.SetSink("stderr", "");
log.Error("db connect failed: %s", "timeout");
log.Close();{"ts":"<time>","level":"error","msg":"db connect failed:
timeout"}For actual errors: failed operations, exceptional states. The JSON format is especially useful here if an alerting system watches the error-level lines.
Maintenance
Flushing the buffers and closing the logger.
log.Flush
log.Flush() -> int
Flushes the buffer of every file sink (and stderr), so the pending lines are written to disk/console at once.
This function takes no arguments.
Always 1.
log.SetSink("file", "app.log");
log.Info("event");
printf("%d\n", log.Flush());
log.Close();1
Before a critical point (for example before the program starts a risky operation, or might crash), so the already-emitted log lines are surely written out.
log.Close
log.Close() -> int
Closes all sinks (files, syslog) and empties the sink list. The level and format settings remain.
This function takes no arguments.
Always 1.
log.SetSink("file", "app.log");
log.Info("done");
printf("%d\n", log.Close());1
Call it at the end of the program, so the files close cleanly and all data reaches the disk. After Close you can add new sinks if you want to continue logging for another purpose.
Practical notes
What the log plugin is good for
Diagnostics and tracing: logging the program's operation by level so the noise is controllable.
Several outputs at once: console for development AND a file for the durable log, even syslog for system integration.
Machine processing: in JSON format the log can be fed directly to an analysis or alerting system.
Long-running services: size- or time-based rotation keeps the log files' size in check.
A typical pattern
At the start of the program set the level, the format, and the sinks, then in the code log with the function of the right level (Info for normal events, Warn for suspicious situations, Error for errors). With the level threshold you control in one place how much actually gets out — you need not delete the calls from the code. At the end, call Close.
Common pitfalls
No sink, no output: if you have not called any SetSink, the log goes nowhere. Add at least one sink (typically stderr).
Level filtering: if a message does not appear, the threshold is probably higher than its level. A 0 return from the emit function signals this.
Truncation: a message longer than 4096 bytes is cut off. Log long data across several lines or abbreviated.
Buffering: lines written to a file do not necessarily reach the disk immediately. Call Flush before an important point, and Close at the end.
Error handling
A wrong argument count or type is reported by the runtime as a runtime error, and the script stops. The usual content-level cases, however, are signaled by a neutral return value: an unknown level/format/sink type gives 0, a successful setting gives 1, a message suppressed by the level filter gives 0. So the usual cases need no extra guard checks — inspect the return value only when you want to know whether the setting succeeded or the message got out.
The crypto cryptography plugin
SHA-256, HMAC, secure random, and hex — complete function reference