One file. Ten languages. Zero dependencies.
Copy. Paste. Log.
from logx import info, warn, error
info("Server started on port %d", 8080)
warn("Memory at %.1f%%", 74.2)
error("Connection lost")LOGX_INFO("Server started on port %d", 8080);
LOGX_WARN("Memory at %.1f%%", 74.2);
LOGX_ERROR("Connection lost");logx_info!("Server started on port {}", 8080);
logx_warn!("Memory at {:.1}%", 74.2);
logx_error!("Connection lost");const { info } = require('logx');
info("Server started on port %d", 8080);No installs. No config files. No hunting down 200 transitive deps.
- Why LogX?
- Quick Start
- Installation
- API Reference
- Environment Variables
- Output Format
- Philosophy
- Contributing
- Publishing to GitHub
- License
Logging should be as easy as print(). But print() doesn't give you levels, timestamps, colors, or file output.
Most logging libraries give you all that — and also give you a headache. Setup, configuration, dependencies, framework lock-in...
LogX is the opposite. One file per language. Same API philosophy everywhere. Drop it in, include it, done.
| Feature | print() |
LogX |
|---|---|---|
| Log levels | ❌ | ✅ TRACE, INFO, WARN, ERROR, FATAL |
| Timestamps | ❌ | ✅ [HH:MM:SS.mmm] |
| File & line | ❌ | ✅ Automatic |
| Colored output | ❌ | ✅ Auto TTY detection |
| File logging | ❌ | ✅ Optional, one call |
| Thread safe | ❌ | ✅ Mutex-guarded |
| Level filtering | ❌ | ✅ LOG_LEVEL=WARN ./app |
| Still one file | ✅ | ✅ |
| Language | File | Include |
|---|---|---|
| Python | python/logx/__init__.py |
from logx import info |
| JavaScript | js/logx.js |
const { info } = require('./logx') |
| TypeScript | ts/logx.ts |
import { info } from './logx' |
| C | c/logx.h |
#include "logx.h" → LOGX_INFO(...) |
| C++ | cpp/logx.h |
#include "logx.h" → LOGX_INFO << ... |
| Rust | rust/logx.rs |
#[macro_use] mod logx; → logx_info!(...) |
| Go | go/logx.go |
import "yourmodule/logx" → logx.Info(...) |
| Java | java/logx.java |
import Logx; → Logx.info(...) |
| Zig | zig/logx.zig |
@import("logx.zig") → logx.log(.info, ...) |
| Assembly | asm/logx.asm |
%include "logx.asm" → log_info "..." |
- Copy the relevant file from this repo into your project.
- Include/import it.
- Start logging.
pip install python-logxfrom logx import trace, info, warn, error, fatal, set_log_file
info("hello %d", 42)
error("something broke")
set_log_file("/tmp/app.log") # redirect to filenpm install logxconst { trace, info, warn, error, fatal, setLogFile } = require('logx');
info('hello %d', 42);
error('something broke');import { trace, info, warn, error, fatal, setLogFile } from 'logx';
info('hello %d', 42);
error('something broke');#include "logx.h"
int main() {
LOGX_INFO("hello %d", 42);
LOGX_ERROR("something broke");
}// Optional: log to file
lx_set_log_file("/tmp/app.log");gcc -std=c11 main.c -o app -lpthread#include "logx.h"
int main() {
LOGX_INFO << "hello " << 42;
LOGX_ERROR << "something broke";
}// Optional: log to file
Logx::setLogFile("/tmp/app.log");
Logx::setLogFile(); // back to terminalg++ -std=c++11 main.cpp -o app#[macro_use] mod logx;
fn main() {
logx_info!("hello {}", 42);
logx_error!("something broke");
}// Optional: log to file
logx::set_log_file("/tmp/app.log");Add to Cargo.toml:
[dependencies]
libc = "0.2"package main
import "yourmodule/logx"
func main() {
logx.Info("hello %d", 42)
logx.Error("something broke")
}// Optional: log to file
logx.SetLogFile("/tmp/app.log")public class Main {
public static void main(String[] args) {
Logx.info("hello %d", 42);
Logx.error("something broke");
}
}// Optional: log to file
Logx.setLogFile("/tmp/app.log");javac Logx.java Main.java && java Mainconst logx = @import("logx.zig");
pub fn main() void {
logx.log(.info, "hello 42", @src());
logx.log(.error, "something broke", @src());
}// Optional: log to file
try logx.setLogFile("/tmp/app.log");%include "logx.asm"
section .data
log_str(msg_hello, "hello 42")
log_str(msg_error, "something broke")
section .text
global _start
_start:
call log_init
log_info msg_hello
log_error msg_error
call log_close
mov rax, 60
xor rdi, rdi
syscall; Optional: log to file (define before including)
%define LOG_FILE_PATH "/tmp/app.log"
%include "logx.asm"nasm -felf64 main.asm -o main.o && ld main.o -o main| Level | Value | Description |
|---|---|---|
| TRACE | 0 | Finest-grained diagnostic |
| INFO | 1 | General operational info |
| WARN | 2 | Something unexpected (non-fatal) |
| ERROR | 3 | Runtime error or failure |
| FATAL | 4 | Unrecoverable — exits the process |
| Language | Log calls | Set log file | Clear log file |
|---|---|---|---|
| Python | trace(), info(), warn(), error(), fatal() |
set_log_file(path) |
set_log_file(None) |
| JavaScript | trace(), info(), warn(), error(), fatal() |
setLogFile(path) |
setLogFile(null) |
| TypeScript | trace(), info(), warn(), error(), fatal() |
setLogFile(path) |
setLogFile(null) |
| C | LOGX_TRACE(), LOGX_INFO(), LOGX_WARN(), LOGX_ERROR(), LOGX_FATAL() |
lx_set_log_file(path) |
lx_set_log_file(NULL) |
| C++ | LOGX_TRACE <<, LOGX_INFO <<, LOGX_WARN <<, LOGX_ERROR <<, LOGX_FATAL << |
Logx::setLogFile(path) |
Logx::setLogFile() |
| Rust | logx_trace!(), logx_info!(), logx_warn!(), logx_error!(), logx_fatal!() |
set_log_file(path) |
— |
| Go | logx.Trace(), logx.Info(), logx.Warn(), logx.Error(), logx.Fatal() |
logx.SetLogFile(path) |
logx.SetLogFile("") |
| Java | Logx.trace(), Logx.info(), Logx.warn(), Logx.error(), Logx.fatal() |
Logx.setLogFile(path) |
Logx.setLogFile(null) |
| Zig | logx.log(.trace,), logx.log(.info,), logx.log(.warn,), logx.log(.err,), logx.log(.fatal,) |
logx.setLogFile(path) |
— |
| Assembly | log_trace, log_info, log_warn, log_error, log_fatal |
%define LOG_FILE_PATH before include |
call log_close |
| Variable | Values | Default |
|---|---|---|
LOG_LEVEL |
TRACE, INFO, WARN, ERROR, FATAL |
TRACE |
LOG_COLOR |
0, 1, yes |
Auto (enabled if both stdout and stderr are TTYs) |
Example:
LOG_LEVEL=WARN LOG_COLOR=0 ./myapp[HH:MM:SS.mmm][LEVEL] filename:line -> message
Example:
[14:23:01.042][INFO ] server.c:42 -> Server started on port 8080
[14:23:01.043][WARN ] memory.c:17 -> Memory at 74.2%
[14:23:01.044][ERROR] network.c:89 -> Connection lost
LogX is not trying to replace OpenTelemetry. It is built for:
- Prototypes & hackathons
- CLI tools & scripts
- Game jams
- Students learning a new language
- Small-to-medium projects
- Anyone who just wants to log without ceremony
"If you can write print(), you already know how to use LogX."
See CONTRIBUTING.md for guidelines.
# Install GitHub CLI if you haven't
# https://cli.github.com/
# Authenticate
gh auth login
# Create the repo (from inside the project directory)
gh repo create logx --public --source=. --remote=origin --pushOr manually:
# Create a repo on github.com, then:
git remote add origin https://github.com/YOUR_USERNAME/logx.git
git branch -M main
git push -u origin mainnpm (JavaScript / TypeScript):
# Make sure you're logged in
npm login
# Publish from js/ directory
cd js
npm publish
# Publish from ts/ directory
cd ../ts
npm publishPyPI (Python):
cd python
pip install build twine
python -m build
python -m twine upload dist/*crates.io (Rust):
cd rust
cargo login
cargo publishgit tag v1.0.0
git push origin v1.0.0
# Or via GitHub CLI:
gh release create v1.0.0 --title "v1.0.0" --notes "Initial release"- Description: "One file. Ten languages. Zero dependencies. — A copy-paste logging library for Python, JS, TS, C, C++, Rust, Go, Java, Zig, and Assembly."
- Topics:
logging,logger,zero-dependency,single-file,python,javascript,typescript,c,cpp,rust,go,java,zig,assembly - Website: (optional) Link to your GitHub Pages or personal site
logger/
├── asm/logx.asm # x86-64 Assembly (Linux, NASM)
├── c/logx.h # C99/C11
├── cpp/logx.h # C++11
├── go/logx.go # Go
├── java/logx.java # Java
├── js/logx.js # JavaScript (Node)
├── python/logx/ # Python
│ └── __init__.py
├── rust/logx.rs # Rust
├── ts/logx.ts # TypeScript
├── zig/logx.zig # Zig
├── test/ # Tests per language
├── README.md
├── CONTRIBUTING.md
├── LICENSE # BSD 2-Clause
└── .gitignore
BSD 2-Clause. See LICENSE.