12#include <nlohmann/json.hpp>
35 std::lock_guard<std::mutex> lock(write_mutex_);
36 if (file_.is_open()) {
50 logger->info(
"Audit logging disabled");
53 std::filesystem::create_directories(config_.
log_dir);
54 auto path = config_.
log_dir /
"audit.jsonl";
55 current_file_size_ = std::filesystem::exists(path)
56 ? std::filesystem::file_size(path) : 0;
57 file_.open(path, std::ios::app);
58 if (!file_.is_open()) {
59 logger->error(
"Failed to open audit log: {}", path.string());
62 logger->info(
"Audit log opened: {}", path.string());
73 if (!config_.
enabled || !file_.is_open()) {
78 line[
"timestamp"] = utc_timestamp();
80 line[
"sequence"] =
static_cast<int64_t>(sequence_.fetch_add(1));
84 auto seq = entry_count_.fetch_add(1);
85 logger->info(
"Audit: tool='{}', caller='{}', seq={}",
95void AuditLogger::write_line(
const std::string&
line) {
96 std::lock_guard<std::mutex> lock(write_mutex_);
98 file_ <<
line <<
'\n';
99 current_file_size_ +=
line.size() + 1;
115 std::lock_guard<std::mutex> lock(write_mutex_);
116 if (file_.is_open()) {
129 return entry_count_.load();
139 return config_.
log_dir /
"audit.jsonl";
148std::string AuditLogger::utc_timestamp() {
149 auto now = std::chrono::system_clock::now();
150 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
151 now.time_since_epoch()) % 1000;
152 auto time = std::chrono::system_clock::to_time_t(now);
155 std::ostringstream
ss;
156 ss << std::put_time(&
utc,
"%Y-%m-%dT%H:%M:%S")
157 <<
'.' << std::setfill(
'0') << std::setw(3) <<
ms.count() <<
'Z';
166void AuditLogger::rotate_if_needed() {
181void AuditLogger::rotate_files() {
183 auto base = config_.
log_dir /
"audit.jsonl";
186 auto src = base.string() +
"." + std::to_string(
i);
187 auto dst = base.string() +
"." + std::to_string(
i + 1);
189 std::filesystem::remove(
src);
190 }
else if (std::filesystem::exists(
src)) {
191 std::filesystem::rename(
src,
dst);
194 std::filesystem::rename(base, base.string() +
".1");
195 file_.open(base, std::ios::app);
196 current_file_size_ = 0;
197 logger->info(
"Audit log rotated");
218 if (
ctx ==
nullptr ||
ctx->logger ==
nullptr) {
226 ?
j[
"args"].dump() :
"{}";
230 ?
j[
"directives"].dump() :
"[]";
232 ctx->logger->record(entry);
233 }
catch (
const std::exception&
e) {
234 logger->error(
"Audit hook callback failed: {}",
e.what());
252 ? *
ctx.parent_conversation_id :
"";
254 ?
"error" :
"success";
AuditHookContext — bridges engine state to audit hook callback.
JSONL audit logger for MCP tool calls.
static int hook_callback(entropic_hook_point_t hook_point, const char *context_json, char **modified_json, void *user_data)
Hook callback for POST_TOOL_CALL integration.
AuditLogger(const AuditLogConfig &config)
Construct with configuration.
bool initialize()
Open the log file and prepare for writing.
void flush()
Force flush buffered entries to disk.
std::filesystem::path log_path() const
Get the file path of the current audit log.
void record(const AuditEntry &entry)
Record a tool call audit entry.
size_t entry_count() const
Get the number of entries recorded this session.
~AuditLogger()
Destructor — flushes and closes the log file.
entropic_hook_point_t
Hook points in the engine lifecycle.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Activate model on GPU (WARM → ACTIVE).
@ optional
optional: every escape asks the host's path approver
void populate_from_hook_context(AuditEntry &entry, const AuditHookContext &ctx)
Populate AuditEntry fields from AuditHookContext state.
nlohmann::json audit_entry_to_json(const AuditEntry &entry)
Serialize AuditEntry fields to a JSON object.
std::string config
–config FILE
A single audit log entry for one MCP tool call.
int delegation_depth
Current delegation depth (0 = lead)
std::string result_content
Tool result text (full, never truncated)
double elapsed_ms
Tool execution duration in milliseconds.
std::string parent_conversation_id
Parent conversation ID (empty for lead)
int iteration
Engine loop iteration number.
std::string params_json
Tool parameters as JSON string (never truncated)
std::string tool_name
Fully-qualified tool name (e.g., "filesystem.write_file")
std::string result_status
"success", "error", or "timeout"
std::string caller_id
Identity/tier name (e.g., "eng", "qa", "lead")
std::string directives_json
Directives array as JSON string ("[]" if none)
Context passed to AuditLogger hook via user_data pointer.
Audit log configuration within StorageConfig.
size_t max_file_size
Rotation size in bytes (0 = unlimited)
size_t flush_interval_entries
Flush every N entries (0 = every entry)
std::string session_id
UUID for this session.
std::filesystem::path log_dir
Directory for audit log files.
bool enabled
Master toggle for audit logging.
size_t max_files
Max rotated files to keep.