Skip to content

Commit 9470e75

Browse files
committed
adding ifql parser
1 parent 544cfb0 commit 9470e75

9 files changed

Lines changed: 493 additions & 40 deletions

File tree

‎.rubocop.yml‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,24 @@ Layout/LineLength:
22
Max: 120
33
Exclude:
44
- 'spec/**'
5+
- 'spec/ifql/**'
56
Metrics/MethodLength:
67
Max: 100
78
Metrics/ClassLength:
89
Max: 1500
910
Metrics/BlockLength:
10-
Max: 100
11+
Max: 200
12+
Metrics/PerceivedComplexity:
13+
Max: 13
14+
Metrics/CyclomaticComplexity:
15+
Max: 11
16+
Metrics/AbcSize:
17+
Exclude:
18+
- 'spec/**'
19+
- 'spec/ifql/**'
20+
- 'lib/telemetry/ifql/parser.rb'
21+
Naming/MethodParameterName:
22+
Enabled: false
1123
Style/Documentation:
1224
Enabled: false
1325
Style/ModuleFunction:
@@ -17,6 +29,4 @@ AllCops:
1729
NewCops: enable
1830
SuggestExtensions: false
1931
Style/FrozenStringLiteralComment:
20-
Enabled: false
21-
Naming/FileName:
2232
Enabled: false

‎lib/telemetry/ifql/formats.rb‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module Telemetry
2+
module IFQL
3+
module Formats
4+
def measurement_error(message, show_error_message: true, status: 500, **)
5+
response = MEASUREMENT.dup
6+
response[:result] = {
7+
error: message,
8+
show_error_message: show_error_message,
9+
status: status
10+
}
11+
response
12+
end
13+
module_function :measurement_error
14+
15+
MEASUREMENT = {
16+
results: [
17+
{
18+
statement_id: 0,
19+
series: [
20+
{
21+
name: 'measurements',
22+
columns: ['name'],
23+
values: []
24+
}
25+
]
26+
}
27+
]
28+
}.freeze
29+
30+
FIELD_KEYS = {
31+
results: [
32+
{
33+
statement_id: 0,
34+
series: [
35+
{
36+
name: nil,
37+
columns: %w[fieldKey fieldType],
38+
values: []
39+
}
40+
]
41+
}
42+
]
43+
}.freeze
44+
45+
DATABASE = {
46+
results: [
47+
{
48+
statement_id: 0,
49+
series: [
50+
{
51+
name: 'databases',
52+
columns: ['name'],
53+
values: [['telegraf']]
54+
}
55+
]
56+
}
57+
]
58+
}.freeze
59+
60+
RETENTION_POLCIES = {
61+
results: [
62+
{
63+
statement_id: 0,
64+
series: [
65+
{
66+
columns: %w[
67+
name
68+
duration
69+
shardGroupDuration
70+
replicaN
71+
default
72+
],
73+
values: [['autogen', '9600h0m0s', '24h0m0s', 1, true]]
74+
}
75+
]
76+
}
77+
]
78+
}.freeze
79+
80+
TAG_VALUES = {
81+
results: [
82+
{
83+
statement_id: 0,
84+
series: [
85+
{
86+
name: 'conflux',
87+
columns: %w[
88+
key
89+
value
90+
],
91+
values: []
92+
}
93+
]
94+
}
95+
]
96+
}.freeze
97+
end
98+
end
99+
end

‎lib/telemetry/ifql/parser.rb‎

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
require 'telemetry/number_helper'
2+
3+
module Telemetry
4+
module IFQL
5+
class Parser
6+
include Telemetry::NumberHelper
7+
attr_reader :query, :database, :params
8+
9+
def initialize(query, db: 'telegraf', **params)
10+
@original_query = query
11+
@query = query.downcase
12+
if @query.include? 'ms'
13+
@query.scan(/(\d+)ms/).flatten.each do |ms_time|
14+
@query.sub! "#{ms_time}ms", (ms_time.to_f.round(-4) / 1000).to_s
15+
end
16+
end
17+
18+
@database = db
19+
@params = params
20+
@time_filter = nil
21+
@limit_processed = false
22+
end
23+
24+
def query_type(query: @query)
25+
@query_type ||= if query.include? ';'
26+
:multi_data
27+
elsif query.include?('show measurements')
28+
:measurement
29+
elsif query.include? 'show databases'
30+
:database
31+
elsif query.include? 'show retention policies'
32+
:rp
33+
elsif query.include? 'show field keys'
34+
:field_key
35+
elsif query.include? 'show tag keys'
36+
:tag_key
37+
elsif query.include? 'show tag values'
38+
:tag_value
39+
elsif query.include? 'show series'
40+
:series
41+
else
42+
:data
43+
end
44+
end
45+
46+
def measurement(query = @query)
47+
@measurement ||= if query.include?('from')
48+
query.split('from').last.split.first.split('.').last.tr('"', '')
49+
elsif query.include?('with measurement')
50+
query.split('with measurement').last.split('/')[1]
51+
end
52+
end
53+
54+
def limit?
55+
return !limit.nil? if @limit_processed
56+
57+
!limit.nil?
58+
end
59+
60+
def limit(query = @query)
61+
return @limit if @limit_processed && @limit.is_a?(Integer)
62+
return nil unless query.include? 'limit'
63+
64+
limit = query.split('limit').last.split.first
65+
return nil unless integer?(limit)
66+
67+
@limit_processed = true
68+
@limit = limit.to_i
69+
end
70+
71+
def time_filter?
72+
!@time_filter.nil? if @time_filter_processed
73+
74+
conditions.each do |cond|
75+
if cond.include?('time')
76+
@time_filter = cond
77+
break
78+
end
79+
end
80+
81+
@time_filter_processed = true
82+
83+
!@time_filter.nil?
84+
end
85+
86+
def conditions(query = @query)
87+
return @conditions unless @conditions.nil?
88+
return @conditions = [] unless query.include?('where')
89+
90+
@conditions = query.split('where').last
91+
@conditions = @conditions.split('group').first if @conditions.include?('group')
92+
@conditions = @conditions.split('fill').first if @conditions.include?('fill')
93+
@conditions = @conditions.split('and').collect { |e| e.strip.tr('\\', '') }
94+
@conditions.collect do |cond|
95+
cond.chop! if cond[-1, 1] == ')' && cond[-2, 1] != '('
96+
cond[0] = '' if cond[0] == '('
97+
end
98+
99+
@conditions
100+
rescue StandardError
101+
[]
102+
end
103+
104+
def group_by(query = @query)
105+
@group_by ||= query.split('group by')[1].split('fill').first.tr('\\', '').split(',').collect(&:strip)
106+
rescue StandardError
107+
[]
108+
end
109+
110+
def group_by_time
111+
@group_by_time unless @group_by_time
112+
@group_by_time = nil
113+
group_by.each do |group|
114+
next unless group.include?('time')
115+
116+
@group_by_time = group.split('(')[1].split(')').first.split(',').first
117+
temp_time = @group_by_time.include?('h') ? @group_by_time.split('h').first.to_i * 60 * 60 : 0
118+
119+
if @group_by_time.include?('h') && @group_by_time.include?('m')
120+
temp_time += @group_by_time.split('h').last.split('m').first.to_i * 60
121+
elsif @group_by_time.include? 'm'
122+
temp_time += @group_by_time.split('m').first.to_i * 60
123+
end
124+
125+
if @group_by_time.include?('s') && @group_by_time.include?('m')
126+
temp_time += @group_by_time.split('s').first.to_i
127+
elsif @group_by_time.include?('s')
128+
temp_time += @group_by_time.split('m').last.split('s').first.to_i
129+
end
130+
131+
@group_by_time = temp_time
132+
break
133+
end
134+
@group_by_time
135+
end
136+
137+
def group_by_time?
138+
@group_by_time unless @group_by_time.nil?
139+
group_by.each do |group|
140+
if group.include?('time')
141+
@group_by_time = true
142+
break
143+
end
144+
end
145+
146+
@group_by_time = false if @group_by_time.nil?
147+
@group_by_time
148+
end
149+
end
150+
end
151+
end

‎lib/telemetry/metrics/parser/line_protocol.rb‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
require 'shellwords'
2-
require 'telemetry/metrics/parser/number_helper'
2+
require 'telemetry/number_helper'
33

44
module Telemetry
55
module Metrics
66
module Parser
77
module LineProtocol
8-
extend Telemetry::Metrics::Parser::NumberHelper
8+
extend Telemetry::NumberHelper
99

1010
def parse(line, use_shellwords: false)
1111
if use_shellwords

‎lib/telemetry/metrics/parser/number_helper.rb‎

Lines changed: 0 additions & 33 deletions
This file was deleted.

‎lib/telemetry/number_helper.rb‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module Telemetry
2+
module NumberHelper
3+
def number?(str)
4+
[str.to_f.to_s, str.to_i.to_s].include?(str)
5+
end
6+
module_function :number?
7+
8+
def float?(string)
9+
string == string.to_f.to_s
10+
end
11+
module_function :float?
12+
13+
def integer?(string)
14+
string == string.to_i.to_s
15+
end
16+
module_function :integer?
17+
18+
def convert_to_number(string)
19+
if integer?(string)
20+
string.to_i
21+
elsif float?(string)
22+
string.to_f
23+
else
24+
string
25+
end
26+
end
27+
module_function :convert_to_number
28+
end
29+
end

‎spec/ifql/formats_spec.rb‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require 'spec_helper'
2+
require 'telemetry/ifql/formats'
3+
4+
RSpec.describe Telemetry::IFQL::Formats do
5+
it 'can run measurement_error' do
6+
expect(Telemetry::IFQL::Formats.measurement_error('error message', status: 501)).to be_a Hash
7+
results = Telemetry::IFQL::Formats.measurement_error('error message', status: 501)
8+
expect(results[:result][:status]).to eq 501
9+
expect(results[:result][:error]).to eq 'error message'
10+
end
11+
it 'has a default measurement' do
12+
expect(Telemetry::IFQL::Formats::MEASUREMENT).to be_a Hash
13+
end
14+
15+
it 'has field keys' do
16+
expect(Telemetry::IFQL::Formats::FIELD_KEYS).to be_a Hash
17+
end
18+
19+
it 'has database' do
20+
expect(Telemetry::IFQL::Formats::DATABASE).to be_a Hash
21+
end
22+
23+
it 'has retention policies' do
24+
expect(Telemetry::IFQL::Formats::RETENTION_POLCIES).to be_a Hash
25+
end
26+
27+
it 'has tag values' do
28+
expect(Telemetry::IFQL::Formats::TAG_VALUES).to be_a Hash
29+
end
30+
end

0 commit comments

Comments
 (0)