Skip to content

Commit

Permalink
Merge pull request #1 from Optum/develop
Browse files Browse the repository at this point in the history
v0.2.0
  • Loading branch information
Esity authored Sep 30, 2022
2 parents 1d5ce6f + 33b4382 commit 9f4cd55
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Telemetry::Metrics::Parser Changelog

## v0.2.0
Adding new line validation methods

## v0.1.1
* Adding more rspec tests for shellwords
* Adding in **opts to from_line_protocol method
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ results[:fields] # => { temperature: 82 }
results[:timestamp] # => 1465839830100400200
```

#### Validations
```ruby
Telemetry::Metrics::Parser::LineProtocol.line_is_valid?('weather,location=us-midwest temperature=82 1465839830100400200') # true
Telemetry::Metrics::Parser::LineProtocol.line_is_valid?('weather,location=us-midwest temperature=this_field_is_a_string 1465839830100400200') # false but returned as a string error
```

Authors
----------
Expand Down
77 changes: 77 additions & 0 deletions lib/telemetry/metrics/parser/line_protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,83 @@ def hash_to_line(hash)
hash.map { |k, v| "#{k}=#{v}" }.join(',').strip.delete_suffix(',')
end
module_function :hash_to_line

def line_is_recent?(timestamp, max_age_sec: 86_400)
return false unless timestamp.is_a?(Integer)
return false unless max_age_sec.is_a?(Integer)

current_epoch_ns = DateTime.now.strftime('%s%9N').to_i
timestamp >= current_epoch_ns - (max_age_sec * 1000 * 1000 * 1000 * 3)
end
module_function :line_is_recent?

def field_is_number?(value)
return false if value.nil?
return true if value.is_a?(Integer)
return true if value.is_a?(Float)

%(f i).include?(value[-1])
end
module_function :field_is_number?

def tag_is_valid?(key, value)
return false if key.nil? || value.nil?
return false unless value.chars.detect { |ch| !valid_tag_chars.include?(ch) }.nil?
return false unless key.to_s.chars.detect { |ch| !valid_tag_chars.include?(ch) }.nil?

true
end
module_function :tag_is_valid?

def node_group_tag?(tags)
tags[:influxdb_node_group].is_a?(String)
end
module_function :node_group_tag?

def database_tag?(tags)
tags[:influxdb_database].is_a?(String)
end
module_function :database_tag?

def measurement_valid?(measurement)
return false unless measurement.is_a?(String)

measurement.chars.detect { |ch| !valid_measurement_chars.include?(ch) }.nil?
end
module_function :measurement_valid?

def valid_measurement_chars
@valid_measurement_chars ||= ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a + %w[_ - .]
end
module_function :valid_measurement_chars

def valid_tag_chars
@valid_tag_chars ||= ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a + %w[_ - .]
end
module_function :valid_tag_chars

def line_is_valid?(line) # rubocop:disable Metrics/AbcSize
line = parse(line) if line.is_a?(String)
return "line is too old, #{line}" unless line_is_recent?(line[:timestamp])
return "line is missing influxdb_database, #{line}" unless node_group_tag? line[:tags]
return "line is missing influxdb_node_group, #{line}" unless database_tag? line[:tags]
return "measurement name #{line[:measurement]} is not valid" unless measurement_valid?(line[:measurement])

line[:fields].each do |field, value|
next if field_is_number?(value)

return "field values must be an Integer or String, #{field} :#{value} #{value.class}"
end

line[:tags].each do |tag, value|
next if tag_is_valid?(tag, value)

return "tags must be a-z0-9_-. but was given #{tag}: #{value}"
end

true
end
module_function :line_is_valid?
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/telemetry/metrics/parser/version.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Telemetry
module Metrics
module Parser
VERSION = '0.1.1'.freeze
VERSION = '0.2.0'.freeze
end
end
end
59 changes: 59 additions & 0 deletions spec/validate_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'spec_helper'
require 'telemetry/metrics/parser/line_protocol'

RSpec.describe Telemetry::Metrics::Parser::LineProtocol do
it 'can validate the measurement' do
expect(described_class.measurement_valid?('foobar')).to eq true
expect(described_class.measurement_valid?('FooBar')).to eq true
expect(described_class.measurement_valid?('foo-bar')).to eq true
expect(described_class.measurement_valid?('foo-bar_test')).to eq true
expect(described_class.measurement_valid?('foo.test-bar_again')).to eq true
end

it 'can validate tags' do
expect(described_class.tag_is_valid?('foobar', 'testing')).to eq true
expect(described_class.tag_is_valid?('foo_bar', 'testing')).to eq true
expect(described_class.tag_is_valid?('foo-bar', 'testing')).to eq true
expect(described_class.tag_is_valid?('foo.bar', 'testing')).to eq true
expect(described_class.tag_is_valid?('test', 'foo.bar')).to eq true
expect(described_class.tag_is_valid?('test', 'foo-bar')).to eq true
expect(described_class.tag_is_valid?('test', 'foo_bar')).to eq true
expect(described_class.tag_is_valid?('test world', 'foo_bar')).to eq false
expect(described_class.tag_is_valid?('test&world', 'foo_bar')).to eq false
expect(described_class.tag_is_valid?('test', 'foo%bar')).to eq false
end

it 'can validate fields' do
expect(described_class.field_is_number?(1)).to eq true
expect(described_class.field_is_number?(0.11111)).to eq true
expect(described_class.field_is_number?('foobar')).to eq false
expect(described_class.field_is_number?('1i')).to eq true
expect(described_class.field_is_number?('1f')).to eq true
expect(described_class.field_is_number?('1.1f')).to eq true
end

it 'can validate the line is current' do
expect(described_class.line_is_recent?(1_465_839_830_100_400_200)).to eq false
expect(described_class.line_is_recent?(2_665_839_830_100_400_200)).to eq true
expect(described_class.line_is_recent?('11111')).to eq false
end

it 'can verify a node_group tag exists' do
expect(described_class.node_group_tag?({ foo: 'bar' })).to eq false
expect(described_class.node_group_tag?({ influxdb_node_group: 'bar' })).to eq true
end

it 'can verify a database_tag exists' do
expect(described_class.database_tag?({ foo: 'bar' })).to eq false
expect(described_class.database_tag?({ influxdb_database: 'bar' })).to eq true
end

it 'can validate a line' do
expect(described_class.line_is_valid?('weather,location=us-midwest temperature=82 1465839830100400200')).to be_a String
expect(described_class.line_is_valid?('weather,location=us-midwest temperature=82 2465839830100400200')).to be_a String
expect(described_class.line_is_valid?('weather,location=us-midwest,influxdb_database=foo temperature=82 2465839830100400200')).to be_a String
expect(described_class.line_is_valid?('weather,location=us-midwest,influxdb_database=foo,influxdb_node_group=foo temperature=82 2465839830100400200')).to be_truthy
expect(described_class.line_is_valid?('weather,location=us-midwest,influxdb_database=foo,influxdb_node_group=foo temperature=82,field=aaa 2465839830100400200')).to be_a String
expect(described_class.line_is_valid?('weather,locat%ion=us-midw%est,influxdb_database=foo,influxdb_node_group=foo temperature=82 2465839830100400200')).to be_a String
end
end

0 comments on commit 9f4cd55

Please sign in to comment.