Add Log::rotation_format_func and Log::default_rotation_dir options

These may be redefined to customize log rotation path prefixes,
including use of a directory.  File extensions are still up to
individual log writers to add themselves during the actual rotation.

These new also allow for some simplication to the default
ASCII postprocessor function: it eliminates the need for it doing an
extra/awkward rename() operation that only changes the timestamp format.

This also teaches the supervisor framework to use these new options
to rotate ascii logs into a log-queue/ directory with a specific
file name format (intended for an external archiver process to
monitor separately).
This commit is contained in:
Jon Siwek 2020-06-27 22:43:37 -07:00
parent 6e67a40d24
commit a06ef66edc
21 changed files with 510 additions and 118 deletions

View file

@ -142,6 +142,11 @@ Manager::~Manager()
delete *s;
}
void Manager::InitPostScript()
{
rotation_format_func = zeek::id::find_func("Log::rotation_format_func");
}
WriterBackend* Manager::CreateBackend(WriterFrontend* frontend, zeek::EnumVal* tag)
{
Component* c = Lookup(tag);
@ -1483,7 +1488,7 @@ void Manager::InstallRotationTimer(WriterInfo* winfo)
}
}
std::string Manager::FormatRotationTime(time_t t)
static std::string format_rotation_time_fallback(time_t t)
{
struct tm tm;
char buf[128];
@ -1493,11 +1498,55 @@ std::string Manager::FormatRotationTime(time_t t)
return buf;
}
std::string Manager::FormatRotationPath(std::string_view path, time_t t)
std::string Manager::FormatRotationPath(zeek::EnumValPtr writer,
std::string_view path, double open,
double close, bool terminating,
zeek::FuncPtr postprocessor)
{
auto rot_str = FormatRotationTime(t);
return fmt("%.*s-%s",
static_cast<int>(path.size()), path.data(), rot_str.data());
auto ri = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::Log::RotationFmtInfo);
ri->Assign(0, std::move(writer));
ri->Assign<zeek::TimeVal>(2, open);
ri->Assign<zeek::StringVal>(1, path.size(), path.data());
ri->Assign<zeek::TimeVal>(3, close);
ri->Assign(4, zeek::val_mgr->Bool(terminating));
ri->Assign<zeek::Val>(5, std::move(postprocessor));
std::string rval;
try
{
auto res = rotation_format_func->Invoke(ri);
auto rp_val = res->AsRecordVal();
auto dir_val = rp_val->GetFieldOrDefault(0);
auto prefix = rp_val->GetField(1)->AsString()->CheckString();
auto dir = dir_val->AsString()->CheckString();
if ( ! streq(dir, "") && ! ensure_intermediate_dirs(dir) )
{
reporter->Error("Failed to create dir '%s' returned by "
"Log::rotation_format_func for path %.*s: %s",
dir, static_cast<int>(path.size()), path.data(),
strerror(errno));
dir = "";
}
if ( streq(dir, "") )
rval = prefix;
else
rval = fmt("%s/%s", dir, prefix);
}
catch ( InterpreterException& e )
{
auto rot_str = format_rotation_time_fallback((time_t)open);
rval = fmt("%.*s-%s", static_cast<int>(path.size()), path.data(),
rot_str.data());
reporter->Error("Failed to call Log::rotation_format_func for path %.*s "
"continuing with rotation to: ./%s",
static_cast<int>(path.size()), path.data(), rval.data());
}
return rval;
}
void Manager::Rotate(WriterInfo* winfo)
@ -1505,10 +1554,22 @@ void Manager::Rotate(WriterInfo* winfo)
DBG_LOG(DBG_LOGGING, "Rotating %s at %.6f",
winfo->writer->Name(), network_time);
// Build a temporary path for the writer to move the file to.
auto tmp = FormatRotationPath(winfo->writer->Info().path,
(time_t)winfo->open_time);
winfo->writer->Rotate(tmp.data(), winfo->open_time, network_time, terminating);
static auto default_ppf = zeek::id::find_func("Log::__default_rotation_postprocessor");
zeek::FuncPtr ppf;
if ( winfo->postprocessor )
ppf = {zeek::NewRef{}, winfo->postprocessor};
else
ppf = default_ppf;
auto rotation_path = FormatRotationPath({zeek::NewRef{}, winfo->type},
winfo->writer->Info().path,
winfo->open_time, network_time,
terminating,
std::move(ppf));
winfo->writer->Rotate(rotation_path.data(), winfo->open_time, network_time, terminating);
++rotations_pending;
}
@ -1534,7 +1595,6 @@ bool Manager::FinishedRotation(WriterFrontend* writer, const char* new_name, con
if ( ! winfo )
return true;
// Create the RotationInfo record.
auto info = zeek::make_intrusive<zeek::RecordVal>(zeek::BifType::Record::Log::RotationInfo);
info->Assign(0, {zeek::NewRef{}, winfo->type});
info->Assign(1, zeek::make_intrusive<zeek::StringVal>(new_name));
@ -1543,13 +1603,12 @@ bool Manager::FinishedRotation(WriterFrontend* writer, const char* new_name, con
info->Assign(4, zeek::make_intrusive<zeek::TimeVal>(close));
info->Assign(5, zeek::val_mgr->Bool(terminating));
static auto default_ppf = zeek::id::find_func("Log::__default_rotation_postprocessor");
zeek::Func* func = winfo->postprocessor;
if ( ! func )
{
const auto& id = zeek::detail::global_scope()->Find("Log::__default_rotation_postprocessor");
assert(id);
func = id->GetVal()->AsFunc();
}
func = default_ppf.get();
assert(func);