Structured logging, leveled output, JSON format, and size-based file rotation for Alya applications.
- β‘ High Performance: Micro-benchmarked at ~1 Β΅s per text log and 500 ns on filtered-out log rejections.
- π― Six Leveled Channels: Full hierarchy including
TRACE (0),DEBUG (1),INFO (2),WARN (3),ERROR (4),FATAL (5), andOFF (6). - ποΈ Structured Context Fields: Attach key-value metadata to logger instances or individual call-sites.
- π Dual Formatting: Human-friendly ANSI color badges in text mode, or compact escaped JSON objects for log aggregators (ELK, Datadog, CloudWatch).
- π Size-Based File Rotation: Built-in rolling file appender automatically archives logs once a size limit is reached, maintaining a configurable number of backup files (
.1,.2, ...). - π Multi-Appender Architecture: Fan-out log entries simultaneously across console output, static log files, and rolling log archives.
logger/
βββ alya.toml # Package manifest (v0.1.0)
βββ src/
β βββ lib.alya # Public API facade & factory helpers
β βββ types.alya # Structs, constants, level getters
β βββ core/
β βββ utils.alya # ANSI stripping, JSON escaping, file helpers
β βββ levels.alya # Level conversions and ANSI badges
β βββ formatters.alya # Text and JSON formatters
β βββ appenders.alya # Console, File, RollingFile appenders
β βββ logger.alya # Core logger dispatching & methods
βββ examples/
β βββ demo.alya # Full feature demonstration
βββ tests/
β βββ test_basic.alya # Core logger lifecycle & setters
β βββ test_levels.alya # Level parsing, badges, and filters
β βββ test_json.alya # JSON serialization & string escaping
β βββ test_appenders.alya # Console and File appenders
β βββ test_rotation.alya # Size threshold & file rotation limits
βββ benches/
βββ bench_basic.alya # Micro-benchmark suite
Add logger to your project's alya.toml:
[dependencies]
logger = { git = "https://github.com/alya-lang/logger", branch = "main" }Or install it directly via the Alya CLI:
alyac add logger --git https://github.com/alya-lang/logger --branch main
alyac installimport "logger" as log
function main()
log::log_info("Application service started")
log::log_warn("Database connection pool is 80% full")
log::log_error("Failed to query cache cluster")
end
main()
import "logger" as log
function main()
let app_log = log::create("ApiGateway", log::LOG_INFO())
log::logger_set_timestamps(app_log, 1)
log::logger_info(app_log, "Server listening on 0.0.0.0:8080")
log::logger_debug(app_log, "This debug trace is skipped at INFO level")
end
main()
import "logger" as log
function main()
let auth_log = log::create("AuthService", log::LOG_INFO())
log::logger_set_timestamps(auth_log, 1)
log::logger_add_field(auth_log, "env", "production")
let call_fields = [
log::field("user_id", "4092"),
log::field("ip", "10.0.4.15")
]
log::logger_info_fields(auth_log, "User session authenticated", call_fields)
end
main()
Output:
[21:40:12] [AuthService] [INFO] User session authenticated env=production user_id=4092 ip=10.0.4.15
import "logger" as log
function main()
let json_log = log::create("Telemetry", log::LOG_INFO())
log::logger_set_format(json_log, log::FORMAT_JSON())
let event_fields = [
log::field("latency_ms", "28"),
log::field("status", "200")
]
log::logger_info_fields(json_log, "HTTP transaction completed", event_fields)
end
main()
Output:
{"level":"INFO","time":1789157665,"target":"Telemetry","msg":"HTTP transaction completed","fields":{"latency_ms":"28","status":"200"}}A single logger can write to multiple output streams simultaneously.
import "logger" as log
function main()
let multi_log = log::create("App", log::LOG_INFO())
log::logger_add_console(multi_log)
log::logger_add_file(multi_log, "logs/app.log")
log::logger_info(multi_log, "Written to both console and static log file")
end
main()
Automatically archives old logs once the file size reaches a specified byte threshold:
import "logger" as log
function main()
let rot_log = log::create("App", log::LOG_INFO())
# Rotate at 10 MB (10485760 bytes), keep 5 backups (app.log.1 ... app.log.5)
log::logger_add_rolling_file(rot_log, "logs/app.log", 10485760, 5)
log::logger_info(rot_log, "Service transaction record")
end
main()
| Function | Arguments | Description |
|---|---|---|
create(name, level) |
name = "", level = 2 |
Creates a new Logger instance |
logger_new(name, level) |
name = "", level = 2 |
Constructor matching std/log convention |
logger_set_level(l, level) |
l: Logger, level: int |
Sets the minimum threshold level |
logger_set_colored(l, colored) |
l: Logger, colored: 0 | 1 |
Enables/disables ANSI colors |
logger_set_timestamps(l, enabled) |
l: Logger, enabled: 0 | 1 |
Enables/disables [HH:MM:SS] timestamps |
logger_set_format(l, format) |
l: Logger, format: 1 | 2 |
Sets text (1) or JSON (2) formatting |
logger_set_file(l, path) |
l: Logger, path: string |
Sets destination file path |
logger_add_console(l) |
l: Logger |
Registers stdout console appender |
logger_add_file(l, path) |
l: Logger, path: string |
Registers static file appender |
logger_add_rolling_file(l, path, max_bytes, max_files) |
l: Logger, ... |
Registers size-based rolling appender |
logger_add_field(l, key, value) |
l: Logger, key, val |
Adds persistent context field |
logger_clear_appenders(l) |
l: Logger |
Clears all registered appenders |
logger_clear_fields(l) |
l: Logger |
Clears persistent context fields |
| Function | Arguments | Description |
|---|---|---|
logger_log(l, level, msg) |
l: Logger, level: int, msg: string |
Logs message at specific level |
logger_trace(l, msg) |
l: Logger, msg: string |
Logs at TRACE level (0) |
logger_debug(l, msg) |
l: Logger, msg: string |
Logs at DEBUG level (1) |
logger_info(l, msg) |
l: Logger, msg: string |
Logs at INFO level (2) |
logger_warn(l, msg) |
l: Logger, msg: string |
Logs at WARN level (3) |
logger_error(l, msg) |
l: Logger, msg: string |
Logs at ERROR level (4) |
logger_fatal(l, msg) |
l: Logger, msg: string |
Logs at FATAL level (5) |
logger_info_fields(l, msg, fields) |
l: Logger, msg: string, fields: array |
Logs with call-site structured fields |
| Function | Arguments | Description |
|---|---|---|
log_trace(msg) |
msg: string |
Prints quick colored [TRACE] line |
log_debug(msg) |
msg: string |
Prints quick colored [DEBUG] line |
log_info(msg) |
msg: string |
Prints quick colored [INFO ] line |
log_warn(msg) |
msg: string |
Prints quick colored [WARN ] line |
log_error(msg) |
msg: string |
Prints quick colored [ERROR] line |
log_fatal(msg) |
msg: string |
Prints quick colored [FATAL] line |
level_to_str(level) |
level: int |
Converts numeric level to name string |
level_from_str(str) |
str: string |
Parses level name (case-insensitive) |
Run the complete test suite:
alyac testRun micro-benchmarks:
alyac run benches/bench_basic.alyaRun feature demonstration:
alyac run examples/demo.alyaContributions are welcome! Please follow these steps:
- Fork the repository and clone it locally
- Install dependencies:
alyac install
- Create your feature branch (
git checkout -b feature/my-feature) - Verify tests and formatting before opening a PR:
alyac test - Commit your changes (
git commit -m "feat: add feature") and open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.