Structured Task Logging
The built-in leveled logger — levels, namespaces, a pluggable sink — plus per-job task logs.
The built-in leveled logger — levels, namespaces, a pluggable sink — plus per-job task logs.
The SDK ships a tiny zero-dependency leveled logger, FlexiQLogger. It writes
to stderr by default, so it never pollutes stdout (the CLI's JSON output and
piped data stay clean). FlexiQ uses it internally; it is public API for your
own use too.
import org.byteveda.flexiq.logging.FlexiQLogger;
FlexiQLogger log = FlexiQLogger.create("billing"); // tagged [flexiq:billing]
flexiq.worker().handle("charge", ChargeRequest.class, request -> {
log.info("charging " + request.amount());
return charge(request);
});DEBUG < INFO < WARN < ERROR < SILENT. The threshold defaults to WARN and is
read once from FLEXIQ_LOG_LEVEL; override it at runtime — globally and
immediately:
import org.byteveda.flexiq.logging.LogLevel;
FlexiQLogger.setLevel(LogLevel.DEBUG);debug also takes a Supplier<String> that is only evaluated when the level
passes the threshold — so expensive log lines cost nothing when filtered out:
log.debug(() -> "payload=" + bigObject);warn and error take an optional Throwable; its stack trace is appended to
the line.
log.error("delivery failed", exception);FlexiQLogger.create(ns) tags every line [flexiq:ns]; FlexiQLogger.root()
is the bare [flexiq] logger.
Replace the output sink to route lines to a file, a JSON transport, or your
logging framework — globally and immediately. LogSink is a functional
interface receiving every formatted line that clears the threshold:
import org.byteveda.flexiq.logging.LogSink;
FlexiQLogger.setSink((level, line) -> slf4jLogger.info(line));The sink only sees the Java SDK's own lines — logs from the native core do not flow through it.
Separately from the process logger, jobs can carry persisted, queryable
log lines. writeTaskLog appends a line to storage; getTaskLogs reads a
job's lines back:
flexiq.writeTaskLog(jobId, "import", "info", "processed batch 3/10");
for (var entry : flexiq.getTaskLogs(jobId)) {
System.out.println(entry.loggedAt + " " + entry.level + " " + entry.message);
}Each TaskLog carries id, jobId, taskName, level, message, an
optional extra payload, and loggedAt (Unix milliseconds). Because they live
in storage, task logs survive restarts and are visible from any process on the
same backend.