fluent-plugin-juniper-telemetry 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/firewall.pb.rb +83 -0
- data/lib/fluent/plugin/parser_juniper_analyticsd.rb +125 -0
- data/lib/fluent/plugin/parser_juniper_jti.rb +282 -0
- data/lib/fluent/plugin/parser_juniper_na.rb +147 -0
- data/lib/google/protobuf/descriptor.pb.rb +289 -0
- data/lib/jvision_top.pb.rb +59 -0
- data/lib/logical_port.pb.rb +74 -0
- data/lib/lsp_mon.pb.rb +109 -0
- data/lib/lsp_stats.pb.rb +46 -0
- data/lib/port.pb.rb +89 -0
- metadata +106 -0
data/lib/firewall.pb.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# This file is auto-generated. DO NOT EDIT!
|
5
|
+
#
|
6
|
+
require 'protobuf/message'
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
# Imports
|
11
|
+
#
|
12
|
+
require 'jvision_top.pb'
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
# Message Classes
|
17
|
+
#
|
18
|
+
class Firewall < ::Protobuf::Message; end
|
19
|
+
class FirewallStats < ::Protobuf::Message; end
|
20
|
+
class MemoryUsage < ::Protobuf::Message; end
|
21
|
+
class CounterStats < ::Protobuf::Message; end
|
22
|
+
class PolicerStats < ::Protobuf::Message; end
|
23
|
+
class ExtendedPolicerStats < ::Protobuf::Message; end
|
24
|
+
class HierarchicalPolicerStats < ::Protobuf::Message; end
|
25
|
+
|
26
|
+
|
27
|
+
##
|
28
|
+
# Message Fields
|
29
|
+
#
|
30
|
+
class Firewall
|
31
|
+
repeated ::FirewallStats, :firewall_stats, 1
|
32
|
+
end
|
33
|
+
|
34
|
+
class FirewallStats
|
35
|
+
required :string, :filter_name, 1
|
36
|
+
optional :uint64, :timestamp, 2
|
37
|
+
repeated ::MemoryUsage, :memory_usage, 3
|
38
|
+
repeated ::CounterStats, :counter_stats, 4
|
39
|
+
repeated ::PolicerStats, :policer_stats, 5
|
40
|
+
repeated ::HierarchicalPolicerStats, :hierarchical_policer_stats, 6
|
41
|
+
end
|
42
|
+
|
43
|
+
class MemoryUsage
|
44
|
+
required :string, :name, 1
|
45
|
+
optional :uint64, :allocated, 2
|
46
|
+
end
|
47
|
+
|
48
|
+
class CounterStats
|
49
|
+
required :string, :name, 1
|
50
|
+
optional :uint64, :packets, 2
|
51
|
+
optional :uint64, :bytes, 3
|
52
|
+
end
|
53
|
+
|
54
|
+
class PolicerStats
|
55
|
+
required :string, :name, 1
|
56
|
+
optional :uint64, :out_of_spec_packets, 2
|
57
|
+
optional :uint64, :out_of_spec_bytes, 3
|
58
|
+
optional ::ExtendedPolicerStats, :extended_policer_stats, 4
|
59
|
+
end
|
60
|
+
|
61
|
+
class ExtendedPolicerStats
|
62
|
+
optional :uint64, :offered_packets, 1
|
63
|
+
optional :uint64, :offered_bytes, 2
|
64
|
+
optional :uint64, :transmitted_packets, 3
|
65
|
+
optional :uint64, :transmitted_bytes, 4
|
66
|
+
end
|
67
|
+
|
68
|
+
class HierarchicalPolicerStats
|
69
|
+
required :string, :name, 1
|
70
|
+
optional :uint64, :premium_packets, 2
|
71
|
+
optional :uint64, :premium_bytes, 3
|
72
|
+
optional :uint64, :aggregate_packets, 4
|
73
|
+
optional :uint64, :aggregate_bytes, 5
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
##
|
78
|
+
# Extended Message Fields
|
79
|
+
#
|
80
|
+
class ::JuniperNetworksSensors < ::Protobuf::Message
|
81
|
+
optional ::Firewall, :jnpr_firewall_ext, 6, :extension => true
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Fluent
|
2
|
+
class TextParser
|
3
|
+
class JuniperAnalyticsdParser < Parser
|
4
|
+
|
5
|
+
Plugin.register_parser("juniper_analyticsd", self)
|
6
|
+
|
7
|
+
config_param :output_format, :string, :default => 'structured'
|
8
|
+
|
9
|
+
# This method is called after config_params have read configuration parameters
|
10
|
+
def configure(conf)
|
11
|
+
super
|
12
|
+
|
13
|
+
## Check if "output_format" has a valid value
|
14
|
+
unless @output_format.to_s == "structured" ||
|
15
|
+
@output_format.to_s == "flat" ||
|
16
|
+
@output_format.to_s == "statsd"
|
17
|
+
|
18
|
+
raise ConfigError, "output_format value '#{@output_format}' is not valid. Must be : structured, flat or statsd"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(text)
|
23
|
+
|
24
|
+
payload = JSON.parse(text)
|
25
|
+
time = Engine.now
|
26
|
+
|
27
|
+
## Extract contextual info
|
28
|
+
record_type = payload["record-type"]
|
29
|
+
record_time = payload["time"]
|
30
|
+
device_name = payload["router-id"]
|
31
|
+
port_name = payload["port"]
|
32
|
+
|
33
|
+
## Record time is in microsecond and until 0.14 Fluentd do not support lower than 1s
|
34
|
+
## We need to trim record time for now to fit fluentd
|
35
|
+
json_time = (record_time/1000000).to_i
|
36
|
+
|
37
|
+
if record_type == 'traffic-stats'
|
38
|
+
|
39
|
+
## Delete contextual info
|
40
|
+
payload.delete("record-type")
|
41
|
+
payload.delete("time")
|
42
|
+
payload.delete("router-id")
|
43
|
+
payload.delete("port")
|
44
|
+
|
45
|
+
payload.each do |key, value|
|
46
|
+
record = {}
|
47
|
+
|
48
|
+
if output_format.to_s == 'flat'
|
49
|
+
full_name = "device.#{clean_up_name(device_name)}.interface.#{clean_up_name(port_name)}.type.#{key}"
|
50
|
+
|
51
|
+
record[full_name.downcase]= value
|
52
|
+
|
53
|
+
elsif output_format.to_s == 'structured'
|
54
|
+
record['device'] = device_name
|
55
|
+
record['type'] = record_type + '.' + key
|
56
|
+
record['interface'] = port_name
|
57
|
+
record['value'] = value
|
58
|
+
|
59
|
+
elsif output_format.to_s == 'statsd'
|
60
|
+
|
61
|
+
full_name = "interface.#{clean_up_name(port_name)}.type.#{key}"
|
62
|
+
record[:statsd_type] = 'gauge'
|
63
|
+
record[:statsd_key] = full_name.downcase
|
64
|
+
record[:statsd_gauge] = value
|
65
|
+
else
|
66
|
+
$log.warn "Output_format '#{output_format.to_s}' not supported for #{record_type}"
|
67
|
+
end
|
68
|
+
|
69
|
+
yield json_time, record
|
70
|
+
end
|
71
|
+
elsif record_type == 'queue-stats'
|
72
|
+
|
73
|
+
## Delete contextual info
|
74
|
+
payload.delete("record-type")
|
75
|
+
payload.delete("time")
|
76
|
+
payload.delete("router-id")
|
77
|
+
payload.delete("port")
|
78
|
+
|
79
|
+
payload.each do |key, value|
|
80
|
+
record = {}
|
81
|
+
|
82
|
+
if output_format.to_s == 'flat'
|
83
|
+
|
84
|
+
full_name = "device.#{clean_up_name(device_name)}.interface.#{clean_up_name(port_name)}.queue.#{key}"
|
85
|
+
|
86
|
+
record[full_name.downcase]= value
|
87
|
+
|
88
|
+
elsif output_format.to_s == 'structured'
|
89
|
+
record['device'] = device_name
|
90
|
+
record['type'] = record_type + '.' + key
|
91
|
+
record['interface'] = port_name
|
92
|
+
record['value'] = value
|
93
|
+
|
94
|
+
elsif output_format.to_s == 'statsd'
|
95
|
+
full_name = "interface.#{clean_up_name(port_name)}.queue.#{key}"
|
96
|
+
record[:statsd_type] = 'gauge'
|
97
|
+
record[:statsd_key] = full_name.downcase
|
98
|
+
record[:statsd_gauge] = value
|
99
|
+
|
100
|
+
else
|
101
|
+
$log.warn "Output_format '#{output_format.to_s}' not supported for #{record_type}"
|
102
|
+
end
|
103
|
+
|
104
|
+
yield json_time, record
|
105
|
+
end
|
106
|
+
else
|
107
|
+
$log.warn "Recard type '#{record_type}' not supported"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
## Clean up device name and interface name to remove restricted caracter
|
112
|
+
## Used for flat and statsd format
|
113
|
+
def clean_up_name(name)
|
114
|
+
|
115
|
+
tmp = name
|
116
|
+
|
117
|
+
tmp.gsub!('/', '_')
|
118
|
+
tmp.gsub!(':', '_')
|
119
|
+
tmp.gsub!('.', '_')
|
120
|
+
|
121
|
+
return tmp.to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,282 @@
|
|
1
|
+
require 'protobuf'
|
2
|
+
require 'jvision_top.pb.rb'
|
3
|
+
require 'port.pb.rb'
|
4
|
+
require 'logical_port.pb.rb'
|
5
|
+
require 'firewall.pb.rb'
|
6
|
+
|
7
|
+
module Fluent
|
8
|
+
class TextParser
|
9
|
+
class JuniperJtiParser < Parser
|
10
|
+
|
11
|
+
Plugin.register_parser("juniper_jti", self)
|
12
|
+
|
13
|
+
config_param :output_format, :string, :default => 'structured'
|
14
|
+
|
15
|
+
# This method is called after config_params have read configuration parameters
|
16
|
+
def configure(conf)
|
17
|
+
super
|
18
|
+
|
19
|
+
## Check if "output_format" has a valid value
|
20
|
+
unless @output_format.to_s == "structured" ||
|
21
|
+
@output_format.to_s == "flat" ||
|
22
|
+
@output_format.to_s == "statsd"
|
23
|
+
|
24
|
+
raise ConfigError, "output_format value '#{@output_format}' is not valid. Must be : structured, flat or statsd"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse(text)
|
29
|
+
|
30
|
+
## Decode GBP packet
|
31
|
+
jti_msg = TelemetryStream.decode(text)
|
32
|
+
|
33
|
+
resource = ""
|
34
|
+
|
35
|
+
## Extract device name & Timestamp
|
36
|
+
device_name = jti_msg.system_id
|
37
|
+
gpb_time = jti_msg.timestamp
|
38
|
+
|
39
|
+
## Extract sensor
|
40
|
+
begin
|
41
|
+
jnpr_sensor = jti_msg.enterprise.juniperNetworks
|
42
|
+
datas_sensors = JSON.parse(jnpr_sensor.to_json)
|
43
|
+
$log.debug "Extract sensor data from " + device_name
|
44
|
+
rescue
|
45
|
+
$log.warn "Unable to extract sensor data sensor from jti_msg.enterprise.juniperNetworks, something went wrong"
|
46
|
+
$log.debug "Unable to extract sensor data sensor from jti_msg.enterprise.juniperNetworks, Data Dump : " + jti_msg.inspect.to_s
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
## Go over each Sensor
|
51
|
+
datas_sensors.each do |sensor, s_data|
|
52
|
+
|
53
|
+
##############################################################
|
54
|
+
### Support for resource /junos/system/linecard/interface/ ##
|
55
|
+
##############################################################
|
56
|
+
if sensor == "jnpr_interface_ext"
|
57
|
+
|
58
|
+
resource = "/junos/system/linecard/interface/"
|
59
|
+
|
60
|
+
datas_sensors[sensor]['interface_stats'].each do |datas|
|
61
|
+
|
62
|
+
# Save all info extracted on a list
|
63
|
+
sensor_data = []
|
64
|
+
|
65
|
+
# Catch Exception during parsing
|
66
|
+
begin
|
67
|
+
## Extract interface name and clean up
|
68
|
+
# interface_name = datas['if_name']
|
69
|
+
sensor_data.push({ 'device' => device_name })
|
70
|
+
sensor_data.push({ 'interface' => datas['if_name'] })
|
71
|
+
|
72
|
+
# Check if the interface has a parent
|
73
|
+
if datas.key?('parent_ae_name')
|
74
|
+
sensor_data.push({ 'interface_parent' => datas['parent_ae_name'] })
|
75
|
+
datas.delete("parent_ae_name")
|
76
|
+
end
|
77
|
+
|
78
|
+
## Clean up Current object
|
79
|
+
datas.delete("if_name")
|
80
|
+
datas.delete("init_time")
|
81
|
+
datas.delete("snmp_if_index")
|
82
|
+
|
83
|
+
datas.each do |section, data|
|
84
|
+
|
85
|
+
## egress_queue_info is an Array
|
86
|
+
if data.kind_of?(Array)
|
87
|
+
data.each do |queue|
|
88
|
+
|
89
|
+
## Create local copy to avoid variable sharing
|
90
|
+
local_sensor_data = sensor_data.dup
|
91
|
+
|
92
|
+
## Save and Cleanup Queue number
|
93
|
+
local_sensor_data.push({ 'egress_queue' => queue['queue_number'] })
|
94
|
+
queue.delete("queue_number")
|
95
|
+
|
96
|
+
queue.each do |type,value|
|
97
|
+
local_sensor_data.push({ 'type' => section + '.' + type })
|
98
|
+
local_sensor_data.push({ 'value' => value })
|
99
|
+
|
100
|
+
record = build_record(output_format, local_sensor_data)
|
101
|
+
yield gpb_time, record
|
102
|
+
end
|
103
|
+
end
|
104
|
+
else
|
105
|
+
data.each do |type,value|
|
106
|
+
|
107
|
+
## Create local copy to avoid using some variable
|
108
|
+
local_sensor_data = sensor_data.dup
|
109
|
+
|
110
|
+
local_sensor_data.push({ 'type' => section + '.' + type })
|
111
|
+
local_sensor_data.push({ 'value' => value })
|
112
|
+
|
113
|
+
record = build_record(output_format, local_sensor_data)
|
114
|
+
yield gpb_time, record
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
rescue
|
119
|
+
$log.warn "Unable to parse " + sensor + " sensor, an error occured.."
|
120
|
+
$log.debug "Unable to parse " + sensor + " sensor, Data Dump : " + datas.inspect.to_s
|
121
|
+
end
|
122
|
+
end
|
123
|
+
##############################################################
|
124
|
+
### Support for resource /junos/system/linecard/firewall/ ##
|
125
|
+
##############################################################
|
126
|
+
# elsif sensor == "jnpr_firewall_ext"
|
127
|
+
#
|
128
|
+
# resource = "/junos/system/linecard/firewall"
|
129
|
+
#
|
130
|
+
# datas_sensors[sensor]['firewall_stats'].each do |datas|
|
131
|
+
#
|
132
|
+
# begin
|
133
|
+
# ## Extract interface name and clean up
|
134
|
+
# sensor_data.push({ 'device' => device_name })
|
135
|
+
# sensor_data.push({ 'filter_name' => datas['filter_name'] })
|
136
|
+
#
|
137
|
+
# ## Clean up Current object
|
138
|
+
# # datas.delete("filter_name")
|
139
|
+
#
|
140
|
+
# $log.warn "Sensor Filter : " + datas['filter_name']
|
141
|
+
#
|
142
|
+
# rescue
|
143
|
+
# $log.warn "Unable to parse " + sensor + " sensor, an error occured.."
|
144
|
+
# $log.debug "Unable to parse " + sensor + " sensor, Data Dump : " + datas.inspect.to_s
|
145
|
+
# end
|
146
|
+
# end
|
147
|
+
|
148
|
+
##############################################################
|
149
|
+
### Support for resource /junos/system/linecard/interface/logical/usage ##
|
150
|
+
##############################################################
|
151
|
+
elsif sensor == "jnprLogicalInterfaceExt"
|
152
|
+
|
153
|
+
resource = "/junos/system/linecard/interface/logical/usage"
|
154
|
+
|
155
|
+
datas_sensors[sensor]['interface_info'].each do |datas|
|
156
|
+
|
157
|
+
# Save all info extracted on a list
|
158
|
+
sensor_data = []
|
159
|
+
|
160
|
+
begin
|
161
|
+
## Extract interface name and clean up
|
162
|
+
sensor_data.push({ 'device' => device_name })
|
163
|
+
sensor_data.push({ 'interface' => datas['if_name'] })
|
164
|
+
|
165
|
+
## Clean up Current object
|
166
|
+
datas.delete("if_name")
|
167
|
+
datas.delete("init_time")
|
168
|
+
datas.delete("snmp_if_index")
|
169
|
+
datas.delete("op_state")
|
170
|
+
|
171
|
+
datas.each do |section, data|
|
172
|
+
data.each do |type, value|
|
173
|
+
|
174
|
+
sensor_data.push({ 'type' => section + '.' + type })
|
175
|
+
sensor_data.push({ 'value' => value })
|
176
|
+
|
177
|
+
record = build_record(output_format, sensor_data)
|
178
|
+
yield gpb_time, record
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
rescue
|
183
|
+
$log.warn "Unable to parse " + sensor + " sensor, an error occured.."
|
184
|
+
$log.debug "Unable to parse " + sensor + " sensor, Data Dump : " + datas.inspect.to_s
|
185
|
+
end
|
186
|
+
end
|
187
|
+
else
|
188
|
+
$log.warn "Unsupported sensor : " + sensor
|
189
|
+
# puts datas_sensors[sensor].inspect.to_s
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def clean_up_name(name)
|
195
|
+
|
196
|
+
tmp = name
|
197
|
+
## Clean up device name and interface name to remove restricted caracter
|
198
|
+
tmp.gsub!('/', '_')
|
199
|
+
tmp.gsub!(':', '_')
|
200
|
+
tmp.gsub!('.', '_')
|
201
|
+
|
202
|
+
return tmp
|
203
|
+
end
|
204
|
+
|
205
|
+
def build_record(type, data_to_build)
|
206
|
+
|
207
|
+
if type.to_s == 'flat'
|
208
|
+
|
209
|
+
# initialize variables
|
210
|
+
name = ""
|
211
|
+
sensor_value = ""
|
212
|
+
|
213
|
+
## Concatene all key/value into a string and stop at "value"
|
214
|
+
data_to_build.each do |entry|
|
215
|
+
entry.each do |key, value|
|
216
|
+
|
217
|
+
if key == "value"
|
218
|
+
sensor_value = value
|
219
|
+
next
|
220
|
+
end
|
221
|
+
|
222
|
+
if name == ""
|
223
|
+
name = key + "." + clean_up_name(value).to_s
|
224
|
+
else
|
225
|
+
name = name + "." + key + "." + clean_up_name(value).to_s
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
record = { name => sensor_value }
|
231
|
+
return record
|
232
|
+
elsif output_format.to_s == 'structured'
|
233
|
+
record = {}
|
234
|
+
## Convert list into Hash
|
235
|
+
## Each entry on the list is a hash with 1 key/value
|
236
|
+
data_to_build.each do |entry|
|
237
|
+
entry.each do |key, value|
|
238
|
+
record[key] = value
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
return record
|
243
|
+
|
244
|
+
elsif output_format.to_s == 'statsd'
|
245
|
+
|
246
|
+
record = {}
|
247
|
+
|
248
|
+
# initialize variables
|
249
|
+
name = ""
|
250
|
+
sensor_value = ""
|
251
|
+
|
252
|
+
## Concatene all key/value into a string, exclude device & stop at "value"
|
253
|
+
data_to_build.each do |entry|
|
254
|
+
entry.each do |key, value|
|
255
|
+
|
256
|
+
if key == "value"
|
257
|
+
sensor_value = value
|
258
|
+
next
|
259
|
+
elsif key == "device"
|
260
|
+
next
|
261
|
+
else
|
262
|
+
if name == ""
|
263
|
+
name = key + "." + clean_up_name(value).to_s
|
264
|
+
else
|
265
|
+
name = name + "." + key + "." + clean_up_name(value).to_s
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
record[:statsd_type] = 'gauge'
|
272
|
+
record[:statsd_key] = name.downcase
|
273
|
+
record[:statsd_gauge] = sensor_value
|
274
|
+
|
275
|
+
return record
|
276
|
+
else
|
277
|
+
$log.warn "Output_format '#{type.to_s}' not supported"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|