Added an option to the JSON formatter to use ISO 8601 for timestamps.

- It's not *exactly* ISO 8601 which doesn't seem to support
   subseconds, but subseconds are very important to us and
   most things that support ISO8601 seem to also support subseconds
   in the way I'm implemented it.
This commit is contained in:
Seth Hall 2014-03-10 14:22:35 -04:00
parent a56c343715
commit c9aaf9e753
11 changed files with 77 additions and 13 deletions

View file

@ -78,6 +78,7 @@ const set_separator: string;
const empty_field: string;
const unset_field: string;
const use_json: bool;
const json_iso_timestamps: bool;
# Options for the DataSeries writer.

View file

@ -59,6 +59,7 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
output_to_stdout = BifConst::LogAscii::output_to_stdout;
include_meta = BifConst::LogAscii::include_meta;
use_json = BifConst::LogAscii::use_json;
json_iso_timestamps = BifConst::LogAscii::json_iso_timestamps;
separator.assign(
(const char*) BifConst::LogAscii::separator->Bytes(),
@ -147,7 +148,7 @@ bool Ascii::DoInit(const WriterInfo& info, int num_fields, const Field* const *
if ( use_json )
{
// Write out JSON formatted logs.
formatter = new threading::formatter::JSON(this);
formatter = new threading::formatter::JSON(this, json_iso_timestamps);
// Using JSON implicitly turns off the header meta fields.
include_meta = false;
}

View file

@ -48,6 +48,7 @@ private:
bool include_meta;
bool tsv;
bool use_json;
bool json_iso_timestamps;
string separator;
string set_separator;

View file

@ -52,7 +52,7 @@ ElasticSearch::ElasticSearch(WriterFrontend* frontend) : WriterBackend(frontend)
curl_handle = HTTPSetup();
json = new threading::formatter::JSON(this);
json = new threading::formatter::JSON(this, false);
}
ElasticSearch::~ElasticSearch()

View file

@ -4,13 +4,15 @@
#include <sstream>
#include <errno.h>
#include <math.h>
#include "./JSON.h"
using namespace threading::formatter;
JSON::JSON(MsgThread* t) : Formatter(t)
JSON::JSON(MsgThread* t, bool json_iso_timestamps) : Formatter(t)
{
iso_timestamps = json_iso_timestamps;
}
JSON::~JSON()
@ -100,16 +102,35 @@ bool JSON::Describe(ODesc* desc, Value* val) const
case TYPE_TIME:
{
// ElasticSearch uses milliseconds for timestamps and json only
// supports signed ints (uints can be too large).
uint64_t ts = (uint64_t) (val->val.double_val * 1000);
if ( ts >= INT64_MAX )
if ( iso_timestamps )
{
thread->Error(thread->Fmt("time value too large for JSON: %" PRIu64, ts));
desc->AddRaw("null", 4);
char buffer[40];
time_t t = time_t(val->val.double_val);
if ( strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S", gmtime(&t)) == 0 )
thread->Error(thread->Fmt("strftime error for JSON: %" PRIu64));
else
{
double integ;
double frac = modf(val->val.double_val, &integ);
snprintf(buffer, sizeof(buffer), "%s.%06.0fZ", buffer, frac*1000000);
desc->AddRaw("\"", 1);
desc->Add(buffer);
desc->AddRaw("\"", 1);
}
}
else
desc->Add(ts);
{
// ElasticSearch uses milliseconds for timestamps and json only
// supports signed ints (uints can be too large).
uint64_t ts = (uint64_t) (val->val.double_val * 1000);
if ( ts >= INT64_MAX )
{
thread->Error(thread->Fmt("time value too large for JSON: %" PRIu64, ts));
desc->AddRaw("null", 4);
}
else
desc->Add(ts);
}
break;
}

View file

@ -13,7 +13,7 @@ namespace threading { namespace formatter {
*/
class JSON : public Formatter {
public:
JSON(threading::MsgThread* t);
JSON(threading::MsgThread* t, bool json_iso_timestamps);
virtual ~JSON();
virtual bool Describe(ODesc* desc, threading::Value* val) const;
@ -23,6 +23,7 @@ public:
virtual threading::Value* ParseValue(string s, string name, TypeTag type, TypeTag subtype = TYPE_ERROR) const;
private:
bool iso_timestamps;
};
}}