Add gzip log writing to the ascii writer.

This feature can be enabled globally for all logs by setting
LogAscii::gzip_level to a value greater than 0.

This feature can be enabled on a per-log basis by setting gzip-level in
$confic to a value greater than 0.
This commit is contained in:
Johanna Amann 2017-04-24 13:12:49 -07:00
parent 2c2c9c9052
commit c868a19a28
7 changed files with 191 additions and 8 deletions

View file

@ -24,6 +24,7 @@ Ascii::Ascii(WriterFrontend* frontend) : WriterBackend(frontend)
tsv = false;
use_json = false;
formatter = 0;
gzip_level = 0;
InitConfigOptions();
init_options = InitFilterOptions();
@ -34,6 +35,7 @@ void Ascii::InitConfigOptions()
output_to_stdout = BifConst::LogAscii::output_to_stdout;
include_meta = BifConst::LogAscii::include_meta;
use_json = BifConst::LogAscii::use_json;
gzip_level = BifConst::LogAscii::gzip_level;
separator.assign(
(const char*) BifConst::LogAscii::separator->Bytes(),
@ -89,6 +91,15 @@ bool Ascii::InitFilterOptions()
}
}
else if ( strcmp(i->first, "gzip_level" ) == 0 )
{
gzip_level = atoi(i->second);
if ( gzip_level < 0 || gzip_level > 9 )
{
Error("invalid value for 'gzip_level', must be a number between 0 and 9.");
return false;
}
}
else if ( strcmp(i->first, "use_json") == 0 )
{
if ( strcmp(i->second, "T") == 0 )
@ -192,7 +203,7 @@ bool Ascii::WriteHeaderField(const string& key, const string& val)
{
string str = meta_prefix + key + separator + val + "\n";
return safe_write(fd, str.c_str(), str.length());
return InternalWrite(fd, str.c_str(), str.length());
}
void Ascii::CloseFile(double t)
@ -203,7 +214,7 @@ void Ascii::CloseFile(double t)
if ( include_meta && ! tsv )
WriteHeaderField("close", Timestamp(0));
safe_close(fd);
InternalClose(fd);
fd = 0;
}
@ -219,7 +230,7 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
if ( output_to_stdout )
path = "/dev/stdout";
fname = IsSpecial(path) ? path : path + "." + LogExt();
fname = IsSpecial(path) ? path : path + "." + LogExt() + (( gzip_level > 0 ) ? ".gz" : "");
fd = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
@ -231,6 +242,25 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
return false;
}
if ( gzip_level > 0 )
{
assert(gzip_level < 10);
char mode[4];
snprintf(mode, 3, "wb%d", gzip_level);
errno = 0; // errno will only be set under certain circumstances by gzdopen.
gzfile = gzdopen(fd, mode);
if ( gzfile == nullptr )
{
Error(Fmt("cannot gzip %s: %s", fname.c_str(),
Strerror(errno)));
return false;
}
}
else
{
gzfile = 0;
}
if ( ! WriteHeader(path) )
{
Error(Fmt("error writing to %s: %s", fname.c_str(), Strerror(errno)));
@ -264,7 +294,7 @@ bool Ascii::WriteHeader(const string& path)
{
// A single TSV-style line is all we need.
string str = names + "\n";
if ( ! safe_write(fd, str.c_str(), str.length()) )
if ( ! InternalWrite(fd, str.c_str(), str.length()) )
return false;
return true;
@ -275,7 +305,7 @@ bool Ascii::WriteHeader(const string& path)
+ get_escaped_string(separator, false)
+ "\n";
if ( ! safe_write(fd, str.c_str(), str.length()) )
if ( ! InternalWrite(fd, str.c_str(), str.length()) )
return false;
if ( ! (WriteHeaderField("set_separator", get_escaped_string(set_separator, false)) &&
@ -337,14 +367,14 @@ bool Ascii::DoWrite(int num_fields, const Field* const * fields,
char hex[4] = {'\\', 'x', '0', '0'};
bytetohex(bytes[0], hex + 2);
if ( ! safe_write(fd, hex, 4) )
if ( ! InternalWrite(fd, hex, 4) )
goto write_error;
++bytes;
--len;
}
if ( ! safe_write(fd, bytes, len) )
if ( ! InternalWrite(fd, bytes, len) )
goto write_error;
if ( ! IsBuf() )
@ -368,7 +398,7 @@ bool Ascii::DoRotate(const char* rotated_path, double open, double close, bool t
CloseFile(close);
string nname = string(rotated_path) + "." + LogExt();
string nname = string(rotated_path) + "." + LogExt() + (gzfile ? ".gz" : "");
if ( rename(fname.c_str(), nname.c_str()) != 0 )
{
@ -434,4 +464,49 @@ string Ascii::Timestamp(double t)
return tmp;
}
bool Ascii::InternalWrite(int fd, const char* data, int len)
{
if ( gzfile )
{
while ( len > 0 )
{
int n = gzwrite(gzfile, data, len);
if ( n < 0 )
{
if ( n == Z_ERRNO )
Error(Fmt("Ascii::InternalWrite error: %s\n", Strerror(errno)));
else
Error(Fmt("Ascii::InternalWrite error: %s\n", gzerror(gzfile, &n)));
return false;
}
data += n;
len -= n;
}
}
else
return safe_write(fd, data, len);
return true;
}
bool Ascii::InternalClose(int fd)
{
if ( gzfile )
{
if ( gzclose(gzfile) < 0 )
{
Error(Fmt("Ascii::InternalClose error: %s\n", Strerror(errno)));
return false;
}
}
else
{
safe_close(fd);
}
return true;
}