The log module provides structured application logging for Vix.
It is the production-oriented logging API.
#include <vix/log.hpp>
int main()
{
vix::log::info("Server started on port {}", 8080);
vix::log::warn("Cache miss for key {}", "users");
vix::log::error("Database connection failed");
return 0;
}#include <vix/log.hpp>This header includes the public logging API:
#include <vix/log/GlobalLog.hpp>
#include <vix/log/LogAdapter.hpp>
#include <vix/log/LogConfig.hpp>
#include <vix/log/LogContext.hpp>
#include <vix/log/LogFormat.hpp>
#include <vix/log/LogLevel.hpp>The vix::log module gives you a stable logging API for Vix applications.
It supports:
- severity levels,
- formatted messages,
- key/value structured logs,
- JSON logs,
- pretty JSON logs,
- environment-based configuration,
- per-thread context,
- optional async logging,
- global logger configuration.
The public API lives in:
namespace vix::logExample:
vix::log::info("User {} logged in", user_id);Vix has several output APIs.
| API | Purpose |
|---|---|
vix::console |
JavaScript-like development console for people coming from JS. |
vix::print |
Simple readable C++ output. |
vix::inspect |
Deep debugging and diagnostics. |
vix::log |
Structured application logging. |
Use vix::console for familiar local development messages.
Use vix::log when you want real application logs with levels, formats, context, and structured fields.
#include <vix/log.hpp>
int main()
{
vix::log::info("Application started");
vix::log::warn("Using default config file: {}", ".env");
vix::log::error("Failed to open {}", "database.db");
return 0;
}Output shape:
09:31:25 [vix] [info] Application started
09:31:25 [vix] [warning] Using default config file: .env
09:31:25 [vix] [error] Failed to open database.dbThe exact visual style depends on the active log format and terminal color support.
The log module uses fmt-style formatting.
vix::log::info("Server started on port {}", 8080);
vix::log::debug("User id: {}", 42);
vix::log::error("File not found: {}", path);Use {} placeholders for values.
std::string user = "Ada";
int id = 1;
vix::log::info("User {} has id {}", user, id);| API | Purpose |
|---|---|
vix::log::trace(...) |
Log a trace message. |
vix::log::debug(...) |
Log a debug message. |
vix::log::info(...) |
Log an info message. |
vix::log::warn(...) |
Log a warning message. |
vix::log::error(...) |
Log an error message. |
vix::log::critical(...) |
Log a critical message. |
vix::log::log(level, ...) |
Log at a dynamic level. |
vix::log::logf(level, message, kv...) |
Log a structured key/value message. |
vix::log::configure(config) |
Configure the global logger. |
vix::log::set_level(level) |
Set the active log level. |
vix::log::level() |
Get the active log level. |
vix::log::enabled(level) |
Check whether a level is enabled. |
vix::log::set_format(format) |
Set the output format. |
vix::log::set_async(bool) |
Enable or disable async logging. |
vix::log::set_context(ctx) |
Set per-thread log context. |
vix::log::clear_context() |
Clear per-thread log context. |
vix::log::context() |
Get current per-thread context. |
vix::log::set_level_from_env() |
Read level from environment. |
vix::log::set_format_from_env() |
Read format from environment. |
vix::log::parse_level(value) |
Parse a log level from string. |
vix::log::parse_format(value) |
Parse a log format from string. |
vix::log::global() |
Access the global public log adapter. |
enum class LogLevel
{
Trace,
Debug,
Info,
Warn,
Error,
Critical,
Off
};| Level | Use for |
|---|---|
Trace |
Very detailed internal events. |
Debug |
Debug information useful during development. |
Info |
Normal application lifecycle events. |
Warn |
Recoverable problems or unexpected conditions. |
Error |
Operation failed, but the process can continue. |
Critical |
Serious failure requiring immediate attention. |
Off |
Disable logging. |
The default level is usually:
InfoYou can override it with:
VIX_LOG_LEVEL=debug ./appor in code:
vix::log::set_level(vix::log::LogLevel::Debug);vix::log::trace("Parser entered state {}", state_id);Trace is the most verbose level.
Use it for deep internals.
vix::log::debug("Cache size: {}", cache_size);Debug is useful during development and troubleshooting.
vix::log::info("Server started on port {}", 8080);Info is for normal application events.
vix::log::warn("Config file {} not found, using defaults", ".env");Warn is for recoverable problems.
vix::log::error("Failed to connect to database: {}", reason);Error is for failed operations.
vix::log::critical("Fatal startup error: {}", reason);Critical is for serious failures.
Use log when the level is known at runtime.
vix::log::LogLevel level = vix::log::LogLevel::Info;
vix::log::log(level, "Dynamic message with id {}", 42);Use enabled to avoid expensive work.
if (vix::log::enabled(vix::log::LogLevel::Debug))
{
std::string debug_info = build_expensive_debug_string();
vix::log::debug("debug_info={}", debug_info);
}This is useful when preparing the log message is expensive.
vix::log::set_level(vix::log::LogLevel::Debug);Example:
#include <vix/log.hpp>
int main()
{
vix::log::debug("hidden by default");
vix::log::set_level(vix::log::LogLevel::Debug);
vix::log::debug("visible now");
return 0;
}auto level = vix::log::level();Example:
if (vix::log::level() == vix::log::LogLevel::Debug)
{
vix::log::info("Debug logging is enabled");
}vix::log::set_level(vix::log::LogLevel::Off);or:
VIX_LOG_LEVEL=off ./appauto level = vix::log::parse_level("debug");Supported values include:
tracedebuginfowarnwarningerrorcriticalfataloffnevernonesilent0
Unknown values fall back to the backend default parsing behavior.
Set the level using:
VIX_LOG_LEVEL=trace ./app
VIX_LOG_LEVEL=debug ./app
VIX_LOG_LEVEL=info ./app
VIX_LOG_LEVEL=warn ./app
VIX_LOG_LEVEL=error ./app
VIX_LOG_LEVEL=critical ./app
VIX_LOG_LEVEL=off ./appYou can also read from a custom environment variable:
vix::log::set_level_from_env("MY_APP_LOG_LEVEL");Example:
MY_APP_LOG_LEVEL=debug ./appvix::log::set_level_from_env("MY_APP_LOG_LEVEL");enum class LogFormat
{
KV,
JSON,
JSON_PRETTY
};| Format | Meaning |
|---|---|
KV |
Human-readable key/value text. |
JSON |
Single-line JSON. |
JSON_PRETTY |
Pretty JSON with indentation. |
Default format:
KVvix::log::set_format(vix::log::LogFormat::KV);
vix::log::set_format(vix::log::LogFormat::JSON);
vix::log::set_format(vix::log::LogFormat::JSON_PRETTY);auto format = vix::log::parse_format("json");Supported values:
kvjsonjson-prettypretty-jsonjson_pretty
Unknown values fall back to KV.
Use:
VIX_LOG_FORMAT=kv ./app
VIX_LOG_FORMAT=json ./app
VIX_LOG_FORMAT=json_pretty ./appYou can also read from a custom environment variable:
vix::log::set_format_from_env("MY_APP_LOG_FORMAT");Use LogConfig when you want to configure level, format, and async mode together.
vix::log::LogConfig config;
config.level = vix::log::LogLevel::Debug;
config.format = vix::log::LogFormat::JSON;
config.async = false;
vix::log::configure(config);struct LogConfig
{
LogLevel level{LogLevel::Info};
LogFormat format{LogFormat::KV};
bool async{false};
};| Field | Default | Purpose |
|---|---|---|
level |
Info |
Minimum active log level. |
format |
KV |
Output format. |
async |
false |
Whether async logging mode is enabled. |
Enable async logging:
vix::log::set_async(true);Disable async logging:
vix::log::set_async(false);You can also configure it with LogConfig:
vix::log::LogConfig config;
config.async = true;
vix::log::configure(config);Use async mode when you want logging to have less impact on the request path.
Use logf for structured key/value logs.
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"path", "/users",
"status", 200,
"duration_ms", 12
);In KV format, output shape:
09:31:25 [vix] [info] request completed method=GET path=/users status=200 duration_ms=12In JSON format, output shape:
{
"level": "info",
"msg": "request completed",
"method": "GET",
"path": "/users",
"status": 200,
"duration_ms": 12
}logf expects alternating key/value pairs:
vix::log::logf(
vix::log::LogLevel::Info,
"user login",
"user_id", 42,
"ip", "127.0.0.1"
);The pattern is:
"key1", value1, "key2", value2, ...Keys should be string literals or const char *.
Good:
vix::log::logf(
vix::log::LogLevel::Info,
"payment processed",
"amount", 99.5,
"currency", "USD"
);Avoid odd key/value counts.
LogContext carries per-thread metadata.
struct LogContext
{
std::string request_id;
std::string module;
std::unordered_map<std::string, std::string> fields;
};Use it for request IDs, module names, and shared metadata.
vix::log::LogContext ctx;
ctx.request_id = "req-123";
ctx.module = "auth";
ctx.fields["ip"] = "127.0.0.1";
ctx.fields["user_agent"] = "curl";
vix::log::set_context(ctx);Now logs include the context.
vix::log::info("User logged in");In KV format, output shape:
09:31:25 [vix] [info] User logged in rid=req-123 mod=auth ip=127.0.0.1 user_agent=curlvix::log::clear_context();Use this after a request finishes.
vix::log::LogContext ctx = vix::log::context();The logging context is per-thread.
This means each request thread can have its own context:
void handle_request(const std::string &request_id)
{
vix::log::LogContext ctx;
ctx.request_id = request_id;
ctx.module = "http";
vix::log::set_context(ctx);
vix::log::info("Handling request");
vix::log::clear_context();
}#include <vix.hpp>
#include <vix/log.hpp>
using namespace vix;
int main()
{
log::set_level_from_env();
log::set_format_from_env();
App app;
app.get("/users/{id}", [](Request &req, Response &res) {
log::LogContext ctx;
ctx.request_id = req.header("X-Request-Id", "local-request");
ctx.module = "users";
ctx.fields["path"] = "/users/{id}";
log::set_context(ctx);
const std::string id = req.param("id");
log::info("Loading user {}", id);
res.json({
"ok", true,
"id", id
});
log::clear_context();
});
app.run(8080);
return 0;
}Set JSON format:
vix::log::set_format(vix::log::LogFormat::JSON);Example:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"path", "/health",
"status", 200,
"duration_ms", 3
);Output shape:
{
"level": "info",
"msg": "request completed",
"method": "GET",
"path": "/health",
"status": 200,
"duration_ms": 3
}Use JSON when logs are consumed by tools.
Set pretty JSON:
vix::log::set_format(vix::log::LogFormat::JSON_PRETTY);or:
VIX_LOG_FORMAT=json_pretty ./appExample output shape:
{
"level": "info",
"msg": "request completed",
"method": "GET",
"path": "/health",
"status": 200,
"duration_ms": 3
}Pretty JSON is useful for local debugging and demos.
For production log ingestion, prefer single-line JSON.
Set KV format:
vix::log::set_format(vix::log::LogFormat::KV);Example:
vix::log::logf(
vix::log::LogLevel::Warn,
"slow request",
"method", "GET",
"path", "/reports",
"duration_ms", 1200
);Output shape:
09:31:25 [vix] [warning] slow request method=GET path=/reports duration_ms=1200KV is readable in the terminal and still easy to grep.
The underlying logger supports colored console output.
For JSON pretty output, colors follow:
VIX_COLOR=always
VIX_COLOR=never
NO_COLOR=1Examples:
VIX_COLOR=never ./app
NO_COLOR=1 ./app
VIX_COLOR=always ./appNO_COLOR disables colors.
The public vix::log module is a façade.
Internally:
vix::log::* → LogAdapter → vix::utils::Logger → spdlogYou should use the public API:
vix::log::info("hello");instead of directly depending on:
vix::utils::LoggerUse the public module to keep application code stable.
vix::log::LogAdapter &adapter = vix::log::global();Usually, you do not need this.
Use top-level helpers instead:
vix::log::info("hello");
vix::log::set_level(vix::log::LogLevel::Debug);LogAdapter bridges the public log module to the internal logger backend.
Main methods:
auto &log = vix::log::global();
log.set_level(vix::log::LogLevel::Info);
log.set_format(vix::log::LogFormat::KV);
log.info("Server started");For normal application code, prefer the free functions:
vix::log::info("Server started");#include <vix/log.hpp>
int main()
{
vix::log::LogConfig config;
config.level = vix::log::LogLevel::Debug;
config.format = vix::log::LogFormat::KV;
config.async = false;
vix::log::configure(config);
vix::log::LogContext ctx;
ctx.request_id = "req-001";
ctx.module = "example";
ctx.fields["env"] = "dev";
vix::log::set_context(ctx);
vix::log::trace("trace message");
vix::log::debug("debug message");
vix::log::info("info message");
vix::log::warn("warn message");
vix::log::error("error message");
vix::log::critical("critical message");
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"path", "/",
"status", 200,
"duration_ms", 5
);
vix::log::clear_context();
return 0;
}#include <vix.hpp>
#include <vix/log.hpp>
using namespace vix;
static void setup_logging()
{
log::set_level_from_env();
log::set_format_from_env();
}
int main()
{
setup_logging();
App app;
app.get("/", [](Request &, Response &res) {
log::info("GET /");
res.json({
"message", "Hello from Vix",
"module", "log"
});
});
app.get("/health", [](Request &, Response &res) {
log::logf(
log::LogLevel::Info,
"health check",
"method", "GET",
"path", "/health",
"status", 200
);
res.json({
"ok", true
});
});
app.run(8080);
return 0;
}Run:
VIX_LOG_LEVEL=debug VIX_LOG_FORMAT=kv vix run main.cppTest:
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/healthVIX_LOG_LEVEL=debug vix run main.cppVIX_LOG_LEVEL=warn vix run main.cppVIX_LOG_FORMAT=json vix run main.cppVIX_LOG_FORMAT=json_pretty vix run main.cppVIX_LOG_FORMAT=json_pretty VIX_COLOR=never vix run main.cppVIX_LOG_LEVEL=off vix run main.cppFor production services, prefer:
VIX_LOG_LEVEL=info
VIX_LOG_FORMAT=json
VIX_COLOR=neverWhy:
infokeeps useful lifecycle and request logs,jsonis machine-readable,VIX_COLOR=neveravoids ANSI escape codes in log files,- single-line logs are easier for log collectors.
Example systemd environment:
Environment=VIX_LOG_LEVEL=info
Environment=VIX_LOG_FORMAT=json
Environment=VIX_COLOR=neverThis is for JavaScript-like development output:
vix::console.log("user created");This is for structured application logging:
vix::log::info("user created");// Wrong
vix::log::info("hello");Fix:
#include <vix/log.hpp>vix::log::debug("debug value {}", 42);Debug logs are hidden unless the level is Debug or lower.
Enable debug:
vix::log::set_level(vix::log::LogLevel::Debug);or:
VIX_LOG_LEVEL=debug ./appWrong:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method"
);Correct:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET"
);If a worker thread handles multiple requests, clear context after each request.
vix::log::clear_context();Pretty JSON is nice for humans.
For production log collectors, prefer:
VIX_LOG_FORMAT=jsonUse info for normal lifecycle events:
vix::log::info("server started on port {}", 8080);Use debug for development details:
vix::log::debug("cache size {}", cache_size);Use warn for recoverable problems:
vix::log::warn("using fallback config");Use error for failed operations:
vix::log::error("database query failed: {}", reason);Use critical for fatal problems:
vix::log::critical("cannot start service: {}", reason);Use logf for request logs and structured events:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"path", "/users",
"status", 200,
"duration_ms", 12
);Use context for request-scoped metadata:
vix::log::LogContext ctx;
ctx.request_id = request_id;
ctx.module = "http";
vix::log::set_context(ctx);LogAdapter &global() noexcept;Returns the global public log adapter.
auto &logger = vix::log::global();
logger.info("hello");void configure(const LogConfig &config);Configures the global logger.
vix::log::LogConfig config;
config.level = vix::log::LogLevel::Debug;
config.format = vix::log::LogFormat::JSON;
vix::log::configure(config);void set_level(LogLevel level);Sets the active log level.
vix::log::set_level(vix::log::LogLevel::Warn);LogLevel level() noexcept;Returns the current log level.
auto current = vix::log::level();bool enabled(LogLevel level) noexcept;Checks whether a level is enabled.
if (vix::log::enabled(vix::log::LogLevel::Debug))
{
vix::log::debug("debug enabled");
}void set_format(LogFormat format);Sets the output format.
vix::log::set_format(vix::log::LogFormat::JSON);void set_async(bool enable);Enables or disables async logging.
vix::log::set_async(true);void set_context(LogContext ctx);Sets the current per-thread log context.
vix::log::LogContext ctx;
ctx.request_id = "req-1";
ctx.module = "auth";
vix::log::set_context(ctx);void clear_context();Clears the current per-thread context.
vix::log::clear_context();LogContext context();Returns a copy of the current per-thread context.
auto ctx = vix::log::context();void set_level_from_env(std::string_view env_name = "VIX_LOG_LEVEL");Reads the log level from an environment variable.
vix::log::set_level_from_env();void set_format_from_env(std::string_view env_name = "VIX_LOG_FORMAT");Reads the log format from an environment variable.
vix::log::set_format_from_env();LogLevel parse_level(std::string_view value);Parses a log level string.
auto level = vix::log::parse_level("debug");LogFormat parse_format(std::string_view value);Parses a log format string.
auto format = vix::log::parse_format("json");template <typename... Args>
void trace(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a trace message.
vix::log::trace("state={}", state);template <typename... Args>
void debug(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a debug message.
vix::log::debug("cache size={}", size);template <typename... Args>
void info(fmt::format_string<Args...> fmtstr, Args &&...args);Logs an info message.
vix::log::info("server started");template <typename... Args>
void warn(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a warning message.
vix::log::warn("config missing: {}", path);template <typename... Args>
void error(fmt::format_string<Args...> fmtstr, Args &&...args);Logs an error message.
vix::log::error("failed: {}", reason);template <typename... Args>
void critical(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a critical message.
vix::log::critical("fatal error: {}", reason);template <typename... Args>
void log(LogLevel level_value, fmt::format_string<Args...> fmtstr, Args &&...args);Logs a formatted message at a dynamic level.
vix::log::log(vix::log::LogLevel::Info, "hello {}", "Vix");template <typename... Args>
void logf(LogLevel level_value, const std::string &message, Args &&...kvpairs);Logs a message with structured key/value fields.
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"path", "/",
"status", 200
);vix::log is the structured logging module for Vix applications.
Use it for:
- application logs,
- request logs,
- production services,
- JSON logs,
- key/value logs,
- request-scoped context,
- async logging,
- severity-based filtering.
Core API:
vix::log::trace("...");
vix::log::debug("...");
vix::log::info("...");
vix::log::warn("...");
vix::log::error("...");
vix::log::critical("...");vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET",
"status", 200
);Use vix::console for JavaScript-like development output.
Use vix::print for simple readable output.
Use vix::inspect for deep debugging.
Use vix::log for structured application logging.