Skip to content

Commit

Permalink
Improve nanosecond timestamp support.
Browse files Browse the repository at this point in the history
- timeNanos is deprecated because the 53 bit mantissa used for doubles
  does not have sufficient precision to represent the current time in
  nanoseconds past the unix epoch (which currently requires 61 bits).
- instead, we now support formats with split seconds and nanoseconds:
  - timestampSeconds, timestampNanos
  - timestamp { seconds, nanos }
  In both cases, the "seconds" part represents seconds since the unix epoch,
  and the "nano" part is the nanosecond component only (0..999999999).
  Managed VMs is using the latter, but it can only be ingested via
  json/msgpack/etc, while the former is suitable for use in an in_tail regex.

This should be considered an interim solution until
fluent/fluentd#461 is resolved.
  • Loading branch information
mr-salty committed May 10, 2015
1 parent 6f7b27e commit c7652c0
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 2 deletions.
16 changes: 15 additions & 1 deletion lib/fluent/plugin/out_google_cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,21 @@ def write(chunk)
'entries' => [],
}
arr.each do |time, record|
if (record.has_key?('timeNanos'))
if (record.has_key?('timestamp') &&
record['timestamp'].has_key?('seconds') &&
record['timestamp'].has_key?('nanos'))
ts_secs = record['timestamp']['seconds']
ts_nanos = record['timestamp']['nanos']
record.delete('timestamp')
elsif (record.has_key?('timestampSeconds') &&
record.has_key?('timestampNanos'))
ts_secs = record['timestampSeconds']
ts_nanos = record['timestampNanos']
record.delete('timestampSeconds')
record.delete('timestampNanos')
elsif (record.has_key?('timeNanos'))
# This is deprecated since the precision is insufficient.
# Use timestampSeconds/timestampNanos instead
ts_secs = (record['timeNanos'] / 1000000000).to_i
ts_nanos = record['timeNanos'] % 1000000000
record.delete('timeNanos')
Expand Down
10 changes: 9 additions & 1 deletion test/plugin/test_out_google_cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def test_timestamps
expected_ts = []
emit_index = 0
[Time.at(123456.789), Time.at(0), Time.now].each do |ts|
# Test both the "native" fluentd timestamp and timeNanos.
# Test the "native" fluentd timestamp as well as our nanosecond tags.
d.emit({'message' => log_entry(emit_index)}, ts.to_f)
# The native timestamp currently only supports second granularity
# (fluentd issue #461), so strip nanoseconds from the expected value.
Expand All @@ -280,6 +280,14 @@ def test_timestamps
'timeNanos' => ts.tv_sec * 1000000000 + ts.tv_nsec})
expected_ts.push(ts)
emit_index += 1
d.emit({'message' => log_entry(emit_index),
'timestamp' => {'seconds' => ts.tv_sec, 'nanos' => ts.tv_nsec}})
expected_ts.push(ts)
emit_index += 1
d.emit({'message' => log_entry(emit_index),
'timestampSeconds' => ts.tv_sec, 'timestampNanos' => ts.tv_nsec})
expected_ts.push(ts)
emit_index += 1
end
d.run
verify_index = 0
Expand Down

2 comments on commit c7652c0

@broniek
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes fluentd to crash in record processing when someone has innocent timestamp field.
Line 171 causes:
2015-06-25 08:33:15 +0000 [warn]: temporarily failed to flush the buffer. next_retry=2015-06-25 08:33:22 +0000 error_class="NoMethodError" error="undefined method `has_key?' for 1435221182.562538:Float" plugin_id="object:3feb02398820"

And as a result all data is lost. Please fix.

@mr-salty
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #20 (pending review)

Please sign in to comment.