Log
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;
}Header
#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>What the log module does
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);Log vs Console vs Print
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.
Quick example
#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.
Formatted messages
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);Public API overview
| 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. |
Log levels
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. |
Default level
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);Trace
vix::log::trace("Parser entered state {}", state_id);Trace is the most verbose level.
Use it for deep internals.
Debug
vix::log::debug("Cache size: {}", cache_size);Debug is useful during development and troubleshooting.
Info
vix::log::info("Server started on port {}", 8080);Info is for normal application events.
Warn
vix::log::warn("Config file {} not found, using defaults", ".env");Warn is for recoverable problems.
Error
vix::log::error("Failed to connect to database: {}", reason);Error is for failed operations.
Critical
vix::log::critical("Fatal startup error: {}", reason);Critical is for serious failures.
Dynamic level logging
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);Check if a level is enabled
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.
Set the log level
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;
}Get the active log level
auto level = vix::log::level();Example:
if (vix::log::level() == vix::log::LogLevel::Debug)
{
vix::log::info("Debug logging is enabled");
}Disable logging
vix::log::set_level(vix::log::LogLevel::Off);or:
VIX_LOG_LEVEL=off ./appParse log levels
auto level = vix::log::parse_level("debug");Supported values include:
tracedebuginfowarnwarningerrorcriticalfataloffnevernonesilent0
Unknown values fall back to the backend default parsing behavior.
Environment log level
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");Log formats
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:
KVSet the log format
vix::log::set_format(vix::log::LogFormat::KV);
vix::log::set_format(vix::log::LogFormat::JSON);
vix::log::set_format(vix::log::LogFormat::JSON_PRETTY);Parse log formats
auto format = vix::log::parse_format("json");Supported values:
kvjsonjson-prettypretty-jsonjson_pretty
Unknown values fall back to KV.
Environment log format
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");Configure the logger
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);LogConfig
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. |
Async logging
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.
Key/value logs
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}Key/value argument rules
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.
Log context
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.
Set context
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=curlClear context
vix::log::clear_context();Use this after a request finishes.
Get context
vix::log::LogContext ctx = vix::log::context();Per-thread 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();
}Request logging example
#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;
}JSON logging
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.
Pretty JSON logging
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.
KV logging
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.
Colors
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.
Default logger backend
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.
Access the global adapter
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
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");Complete example
#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;
}Complete HTTP example
#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/healthEnvironment examples
Debug logs
VIX_LOG_LEVEL=debug vix run main.cppWarnings and errors only
VIX_LOG_LEVEL=warn vix run main.cppJSON logs
VIX_LOG_FORMAT=json vix run main.cppPretty JSON logs
VIX_LOG_FORMAT=json_pretty vix run main.cppJSON logs without colors
VIX_LOG_FORMAT=json_pretty VIX_COLOR=never vix run main.cppDisable logs
VIX_LOG_LEVEL=off vix run main.cppRecommended production setup
For 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=neverCommon mistakes
Using console instead of log for application logs
This is for JavaScript-like development output:
vix::console.log("user created");This is for structured application logging:
vix::log::info("user created");Forgetting the header
// Wrong
vix::log::info("hello");Fix:
#include <vix/log.hpp>Expecting debug logs to appear by default
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 ./appPassing wrong key/value pairs to logf
Wrong:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method"
);Correct:
vix::log::logf(
vix::log::LogLevel::Info,
"request completed",
"method", "GET"
);Forgetting to clear context
If a worker thread handles multiple requests, clear context after each request.
vix::log::clear_context();Using pretty JSON for production ingestion
Pretty JSON is nice for humans.
For production log collectors, prefer:
VIX_LOG_FORMAT=jsonBest practices
Use 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);API reference
global
LogAdapter &global() noexcept;Returns the global public log adapter.
auto &logger = vix::log::global();
logger.info("hello");configure
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);set_level
void set_level(LogLevel level);Sets the active log level.
vix::log::set_level(vix::log::LogLevel::Warn);level
LogLevel level() noexcept;Returns the current log level.
auto current = vix::log::level();enabled
bool enabled(LogLevel level) noexcept;Checks whether a level is enabled.
if (vix::log::enabled(vix::log::LogLevel::Debug))
{
vix::log::debug("debug enabled");
}set_format
void set_format(LogFormat format);Sets the output format.
vix::log::set_format(vix::log::LogFormat::JSON);set_async
void set_async(bool enable);Enables or disables async logging.
vix::log::set_async(true);set_context
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);clear_context
void clear_context();Clears the current per-thread context.
vix::log::clear_context();context
LogContext context();Returns a copy of the current per-thread context.
auto ctx = vix::log::context();set_level_from_env
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();set_format_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();parse_level
LogLevel parse_level(std::string_view value);Parses a log level string.
auto level = vix::log::parse_level("debug");parse_format
LogFormat parse_format(std::string_view value);Parses a log format string.
auto format = vix::log::parse_format("json");trace
template <typename... Args>
void trace(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a trace message.
vix::log::trace("state={}", state);debug
template <typename... Args>
void debug(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a debug message.
vix::log::debug("cache size={}", size);info
template <typename... Args>
void info(fmt::format_string<Args...> fmtstr, Args &&...args);Logs an info message.
vix::log::info("server started");warn
template <typename... Args>
void warn(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a warning message.
vix::log::warn("config missing: {}", path);error
template <typename... Args>
void error(fmt::format_string<Args...> fmtstr, Args &&...args);Logs an error message.
vix::log::error("failed: {}", reason);critical
template <typename... Args>
void critical(fmt::format_string<Args...> fmtstr, Args &&...args);Logs a critical message.
vix::log::critical("fatal error: {}", reason);log
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");logf
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
);Summary
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.