logstash-input-proc 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ ![](https://github.com/eperry/logstash-input-proc/wiki/MemInfoDashboard.png)
2
+
3
+ # Logstash Plugin
4
+
5
+ This is a plugin for [Logstash](https://github.com/elasticsearch/logstash).
6
+
7
+ This plugin is to read the /proc virtual file system , decode the files in it.
8
+ I am using the following pages for reference
9
+
10
+ - http://man7.org/linux/man-pages/man5/proc.5.html
11
+
12
+
13
+
14
+
15
+ ## Documentation
16
+
17
+
18
+ ### 1. Plugin Developement and Testing
19
+
20
+ #### Code
21
+ - To get started, you'll need JRuby with the Bundler gem installed.
22
+ ```sh
23
+ bundle install
24
+ ```
25
+
26
+ - Then clone this repo
27
+ - You will need to either clone the logstash repo or download the binary
28
+
29
+
30
+
31
+ ### 2. Running the unpublished Plugin in Logstash
32
+
33
+ #### 2.1 Run in a local Logstash clone
34
+
35
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
36
+ ```ruby
37
+ gem "logstash-input-proc", :path => "/your/local/logstash-input-proc"
38
+ ```
39
+ - Install plugin
40
+ ```sh
41
+ bin/plugin install --no-verify
42
+ ```
43
+ - install Ruby Debug
44
+ ```sh
45
+ bin/plugin install logstash-codec-rubydebug
46
+ ```
47
+ - Run Logstash with your plugin
48
+ ```sh
49
+ bin/logstash -e 'input {proc {interval=>60}} output { stdout{ codec=>"rubydebug"}}'
50
+ ```
51
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
52
+
53
+ #### 2.2 Run in an installed Logstash
54
+
55
+ You can use the same **2.1** method to run your plugin in an installed Logstash by editing its `Gemfile` and pointing the `:path` to your local plugin development directory or you can build the gem and install it using:
56
+
57
+ - Build your plugin gem
58
+ ```sh
59
+ gem build logstash-output-proc.gemspec
60
+ ```
61
+ - Install the plugin from the Logstash home
62
+ ```sh
63
+ bin/plugin install /your/local/plugin/logstash-input-proc.gem
64
+ ```
65
+ - Start Logstash and proceed to test the plugin
66
+ -
67
+ # Example Config all features enabled
68
+ ```ruby
69
+ input {
70
+ proc {
71
+ interval=>60
72
+ vmstats =>{ }
73
+ loadavg =>{ }
74
+ meminfo =>{ }
75
+ pidstats =>{
76
+ user => "root"
77
+ }
78
+
79
+ }
80
+ }
81
+
82
+ output {
83
+ stdout{
84
+ codec=>"rubydebug"
85
+ }
86
+ }
87
+ ```
88
+ #Example Minimal
89
+
90
+ ```ruby
91
+ input {
92
+ proc {
93
+ interval=>60
94
+ meminfo =>{ }
95
+ }
96
+ }
97
+
98
+ output {
99
+ stdout{
100
+ codec=>"rubydebug"
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## 3.0 Kibana Dashboards
106
+
107
+ Still a work in progress but I have saved a copy of the Kibana 4.1 dashboards I have created
108
+ in the ~/Kibana Directory, you should be able to import them from the Kibana->settings->Objects pages
109
+
110
+ These dashboards are right now a way of me validating the data loaded in elasticsearch is usable and provide an example for others to work off of. They work with the setup
111
+ of elasticsearch as defined below.
112
+
113
+
114
+ ## 4.0 Elasticsearch Templates
115
+
116
+ In the ~/ElasitcSearch Directory are all the Elasticsearch templates I am developing to work with this plugin.
117
+ While they may not be exactly what you need they are a good start.
118
+
119
+ I load them via the ${ES_HOME/config/templates directory but feel free to load them in your preffered way
120
+
121
+ These templates are based on the fact that your indexes for the data are created like so:
122
+ ```
123
+ output {
124
+ elasticsearch {
125
+ host => localhost
126
+ index => "%{type}-%{+YYYY.MM.dd}"
127
+ }
128
+ }
129
+ ```
130
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,562 @@
1
+ # encoding: utf-8
2
+ require "logstash/inputs/base"
3
+ require "logstash/namespace"
4
+ require "stud/interval"
5
+ require "socket" # for Socket.gethostname
6
+ require 'etc'
7
+
8
+ # Generate a repeating message.
9
+ #
10
+ # This plugin is intented only as an example.
11
+
12
+ class LogStash::Inputs::Proc < LogStash::Inputs::Base
13
+ config_name "proc"
14
+
15
+ # If undefined, Logstash will complain, even if codec is unused.
16
+ default :codec, "plain"
17
+
18
+ # The message string to use in the event.
19
+ #config :message, :validate => :string, :default => "Hello World!"
20
+
21
+ # Set how frequently messages should be sent.
22
+ #
23
+ # The default, `60`, means send a message every 60 second.
24
+ config :interval, :validate => :number, :default => 60
25
+ config :vmstats, :validate => :hash
26
+ config :loadavg, :validate => :hash
27
+ config :meminfo, :validate => :hash
28
+ config :pidstats, :validate => :hash
29
+ config :diskstats, :validate => :hash
30
+ config :mounts, :validate => :hash
31
+ config :netdev, :validate => :hash
32
+ config :cpuinfo, :validate => :hash
33
+ config :crypto, :validate => :hash
34
+ config :wireless, :validate => :hash
35
+ config :sysipcshm, :validate => :hash
36
+
37
+ public
38
+ def register
39
+ @host = Socket.gethostname
40
+ @logger.info("Registering Proc Input", :type => @type, :interval => @interval)
41
+
42
+ end # def register
43
+
44
+ def readVmStats(queue)
45
+ file = Pathname.new("/proc/vmstat")
46
+ lines = file.readlines
47
+ vmstats = {}
48
+ lines.each { |line|
49
+ #@logger.info? && @logger.info("LINE: "+line)
50
+ m = /(\w+)\s+([\.\d]+)/.match(line)
51
+ if (m && m.length >= 3 )
52
+ vmstats[m[1]]=m[2].to_i
53
+ end
54
+ }
55
+ event = LogStash::Event.new( 'vmstats'=> vmstats, "file" => file.to_s,"host" => @host, "type" => "vmstats" )
56
+ decorate(event)
57
+ queue << event
58
+
59
+ end
60
+
61
+ def readLoadAverage(queue)
62
+ file = Pathname.new("/proc/loadavg")
63
+ lines = file.readlines
64
+ loadavg = {}
65
+ lines.each { |line|
66
+ m = /([\d\.]+)\s+([\d\.]+)\s+([\d\.])+\s+(\d+)\/(\d+)\s+(\d+)/.match(line)
67
+ if (m && m.length >=6 )
68
+ loadavg["1minute"] = m[1].to_i
69
+ loadavg["10minute"] = m[2].to_i
70
+ loadavg["15minute"] = m[3].to_i
71
+ loadavg["runnable"] = m[4].to_i
72
+ loadavg["existing"] = m[5].to_i
73
+ loadavg["lastcreatedpid"] = m[6].to_i
74
+ event = LogStash::Event.new( "loadavg" => loadavg, "file" => file.to_s,"host" => @host, "type" => "loadavg" )
75
+ decorate(event)
76
+ queue << event
77
+ end
78
+
79
+ }
80
+ end
81
+
82
+ def readMemInfo(queue)
83
+ file = Pathname.new("/proc/meminfo")
84
+ lines = file.readlines
85
+ meminfo={}
86
+ lines.each { |line|
87
+ m = /(\w+):\s+(\d+)/.match(line)
88
+ if (m && m.length >=3 )
89
+ meminfo[m[1]] = m[2].to_i
90
+ #else
91
+ # puts("#"+m.to_s)
92
+ end
93
+ }
94
+ meminfo["CalcMemUsed"]=meminfo["MemTotal"]-meminfo["MemFree"]
95
+ event = LogStash::Event.new("meminfo"=>meminfo, "file" => file.to_s,"host" => @host, "type" => "meminfo" )
96
+ decorate(event)
97
+ queue << event
98
+
99
+ end
100
+
101
+ def readPidStats(queue)
102
+ @logger.info? && @logger.info("in " + $0)
103
+ fuid = -1
104
+
105
+ if @pidstats.has_key?("user")
106
+ fuid = Etc.getpwnam(@pidstats["user"]).uid
107
+ @logger.info? && @logger.info("Filtering userid =" + @pidstats["user"] )
108
+ end
109
+ process = Hash.new
110
+ #Loosely based on the GEM ProcTable which was based on the Perl Module ProcTable
111
+ Dir.foreach("/proc"){ |file|
112
+ next if file =~ /\D/ # Skip non-numeric directories
113
+ if fuid >= 0
114
+ fileUid = File.stat("/proc/"+file).uid
115
+ next if fileUid != fuid
116
+ end
117
+
118
+ # Get /proc/<pid>/cmdline information. Strip out embedded nulls.
119
+ begin
120
+ data = IO.read("/proc/#{file}/cmdline").tr("\000", ' ').strip
121
+ process["cmdline"] = data
122
+ rescue
123
+ next # Process terminated, on to the next process
124
+ end
125
+
126
+ # Get /proc/<pid>/cwd information
127
+ process["cwd"] = File.readlink("/proc/#{file}/cwd") rescue nil
128
+
129
+ # Get /proc/<pid>/environ information. Environment information
130
+ # is represented as a Hash, with the environment variable as the
131
+ # key and its value as the hash value.
132
+ process["environ"] = Hash.new
133
+
134
+ begin
135
+ IO.read("/proc/#{file}/environ").split("\0").each{ |str|
136
+ key, value = str.split('=')
137
+ process["environ"][key] = value
138
+ }
139
+ rescue Errno::EACCES, Errno::ESRCH, Errno::ENOENT
140
+ # Ignore and move on.
141
+ end
142
+
143
+ # Get /proc/<pid>/exe information
144
+ process["exe"] = File.readlink("/proc/#{file}/exe") rescue nil
145
+
146
+ # Get /proc/<pid>/fd information. File descriptor information
147
+ # is represented as a Hash, with the fd as the key, and its
148
+ # symlink as the value.
149
+ process["fd"] = Hash.new
150
+
151
+ begin
152
+ Dir.foreach("/proc/#{file}/fd/") { |fd|
153
+ process["fd"][fd] = File.readlink("/proc/#{file}/fd/"+fd) rescue nil
154
+ }
155
+ rescue
156
+ process["fd"] = ""
157
+ # # Ignore and move on
158
+ end
159
+
160
+ # Get /proc/<pid>/root information
161
+ process["root"] = File.readlink("/proc/#{file}/root") rescue nil
162
+
163
+ # Get /proc/<pid>/stat information
164
+ stat = IO.read("/proc/#{file}/stat") rescue next
165
+
166
+ # Get number of LWP, one directory for each in /proc/<pid>/task/
167
+ # Every process has at least one thread, so if we fail to read the task directory, set nlwp to 1.
168
+ process["nlwp"] = Dir.glob("/proc/#{file}/task/*").length rescue process["nlwp"] = 1
169
+
170
+ # Deal with spaces in comm name. Courtesy of Ara Howard.
171
+ re = %r/\([^\)]+\)/
172
+ comm = stat[re]
173
+ comm.tr!(' ', '-')
174
+ stat[re] = comm
175
+
176
+ stat = stat.split
177
+
178
+ process["pid"] = stat[0].to_i
179
+ process["comm"] = stat[1].tr('()','') # Remove parens
180
+ process["state"] = stat[2]
181
+ process["ppid"] = stat[3].to_i
182
+ process["pgrp"] = stat[4].to_i
183
+ process["session"] = stat[5].to_i
184
+ process["tty_nr"] = stat[6].to_i
185
+ process["tpgid"] = stat[7].to_i
186
+ process["flags"] = stat[8].to_i
187
+ process["minflt"] = stat[9].to_i
188
+ process["cminflt"] = stat[10].to_i
189
+ process["majflt"] = stat[11].to_i
190
+ process["cmajflt"] = stat[12].to_i
191
+ process["utime"] = stat[13].to_i
192
+ process["stime"] = stat[14].to_i
193
+ process["cutime"] = stat[15].to_i
194
+ process["cstime"] = stat[16].to_i
195
+ process["priority"] = stat[17].to_i
196
+ process["nice"] = stat[18].to_i
197
+ # Skip 19
198
+ process["itrealvalue"] = stat[20].to_i
199
+ process["starttime"] = stat[21].to_i
200
+ process["vsize"] = stat[22].to_i
201
+ process["rss"] = stat[23].to_i
202
+ process["rlim"] = stat[24].to_i
203
+ process["startcode"] = stat[25].to_i
204
+ process["endcode"] = stat[26].to_i
205
+ process["startstack"] = stat[27].to_i
206
+ process["kstkesp"] = stat[28].to_i
207
+ process["kstkeip"] = stat[29].to_i
208
+ process["signal"] = stat[30].to_i
209
+ process["blocked"] = stat[31].to_i
210
+ process["sigignore"] = stat[32].to_i
211
+ process["sigcatch"] = stat[33].to_i
212
+ process["wchan"] = stat[34].to_i
213
+ process["nswap"] = stat[35].to_i
214
+ process["cnswap"] = stat[36].to_i
215
+ process["exit_signal"] = stat[37].to_i
216
+ process["processor"] = stat[38].to_i
217
+ process["rt_priority"] = stat[39].to_i
218
+ process["policy"] = stat[40].to_i
219
+ # Get /proc/<pid>/status information (name, uid, euid, gid, egid)
220
+ begin
221
+ IO.foreach("/proc/#{file}/status") do |line|
222
+ case line
223
+ when /Name:\s*?(\w+)/
224
+ process["name"] = $1
225
+ when /Uid:\s*?(\d+)\s*?(\d+)/
226
+ process["uid"] = $1.to_i
227
+ process["euid"] = $2.to_i
228
+ when /Gid:\s*?(\d+)\s*?(\d+)/
229
+ process["gid"] = $1.to_i
230
+ process["egid"] = $2.to_i
231
+ end
232
+ end
233
+ rescue Errno::ESRCH, Errno::ENOENT
234
+ next
235
+ end
236
+
237
+ # If cmdline is empty use comm instead
238
+ process["cmdline"] = process["comm"] if process["cmdline.empty?"]
239
+
240
+
241
+ event = LogStash::Event.new( "file" => "/proc" ,"host" => @host, "type" => "pidstats" , "process" => process);
242
+ decorate(event)
243
+ queue << event
244
+
245
+ }
246
+
247
+
248
+ end
249
+ def readDiskStats(queue)
250
+ # 1 - major number
251
+ # 2 - minor mumber
252
+ # 3 - device name
253
+ # 4 - reads completed successfully
254
+ # 5 - reads merged
255
+ # 6 - sectors read
256
+ # 7 - time spent reading (ms)
257
+ # 8 - writes completed
258
+ # 9 - writes merged
259
+ #10 - sectors written
260
+ #11 - time spent writing (ms)
261
+ #12 - I/Os currently in progress
262
+ #13 - time spent doing I/Os (ms)
263
+ #14 - weighted time spent doing I/Os (ms)
264
+ file = Pathname.new("/proc/diskstats")
265
+ lines = file.readlines
266
+ lines.each { |line|
267
+ #@logger.info? && @logger.info("LINE: "+line)
268
+ m = line.split(/\s+/)
269
+ if (m && m.length >= 13 )
270
+ event = LogStash::Event.new("raw"=>line,
271
+ "major" => m[1].to_i,
272
+ "minor" => m[2].to_i,
273
+ "dev" => m[3],
274
+ "readsCompleted" => m[4].to_i,
275
+ "readsMerged" => m[5].to_i,
276
+ "sectorsRead" => m[6].to_i,
277
+ "readsTimeSpentMS" => m[7].to_i,
278
+ "writesCompleted" => m[8].to_i,
279
+ "writesMerged" => m[9].to_i,
280
+ "sectorsWritten" => m[10].to_i,
281
+ "writesTimeSpentMS" => m[11].to_i,
282
+ "iosInProgress" => m[12].to_i,
283
+ "ioTimeSpentMS" => m[13].to_i,
284
+ "ioWeightedTimeSpentMS" => m[14].to_i,
285
+ "file" => file.to_s,
286
+ "host" => @host,
287
+ "type" => "diskstats" )
288
+ decorate(event)
289
+ queue << event
290
+ end
291
+ }
292
+
293
+ end
294
+ def readMounts(queue)
295
+ #The 1st column specifies the device that is mounted.
296
+ #The 2nd column reveals the mount point.
297
+ #The 3rd column tells the file-system type.
298
+ #The 4th column tells you if it is mounted read-only (ro) or read-write (rw).
299
+ #The 5th and 6th columns are dummy values
300
+ file = Pathname.new("/proc/mounts")
301
+ lines = file.readlines
302
+ lines.each { |line|
303
+ #@logger.info? && @logger.info("LINE: "+line)
304
+ m = line.split(/\s+/)
305
+ if (m && m.length >= 6 )
306
+ event = LogStash::Event.new("raw"=>line,
307
+ "device" => m[0],
308
+ "mountpoint" => m[1],
309
+ "fsType" => m[2],
310
+ "flagsRaw" => m[3],
311
+ "flags" => m[3].split(/\,/),
312
+ "dummy1" => m[4],
313
+ "dummy2" => m[5],
314
+ "file" => file.to_s,
315
+ "host" => @host,
316
+ "type" => "mounts" )
317
+ decorate(event)
318
+ queue << event
319
+ end
320
+ }
321
+
322
+ end
323
+ def readNetDev(queue)
324
+ # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
325
+
326
+ file = Pathname.new("/proc/net/dev")
327
+ lines = file.readlines
328
+ junk = lines.shift
329
+ junk = lines.shift
330
+ lines.each { |line|
331
+ #@logger.info? && @logger.info("LINE: "+line)
332
+ m = line.strip.split(/[:\s]+/)
333
+ if (m && m.length >= 17 )
334
+ event = LogStash::Event.new("raw"=>line,
335
+ "iface" => m[0],
336
+ "rxbytes" => m[1].to_i,
337
+ "rxpackets" => m[2].to_i,
338
+ "rxerrors" => m[3].to_i,
339
+ "rxdrops" => m[4].to_i,
340
+ "rxfifo" => m[5].to_i,
341
+ "rxframe" => m[6].to_i,
342
+ "rxcompressed" => m[7].to_i,
343
+ "rxmulticast" => m[8].to_i,
344
+ "txbytes" => m[9].to_i,
345
+ "txpackets" => m[10].to_i,
346
+ "txerrors" => m[11].to_i,
347
+ "txdrops" => m[12].to_i,
348
+ "txfifo" => m[13].to_i,
349
+ "txframe" => m[14].to_i,
350
+ "txcompressed" => m[15].to_i,
351
+ "txmulticast" => m[16].to_i,
352
+ "file" => file.to_s,
353
+ "host" => @host,
354
+ "type" => "netdev" )
355
+ decorate(event)
356
+ queue << event
357
+ end
358
+ }
359
+
360
+ end
361
+ def readCpuInfo(queue)
362
+ # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
363
+ cpuinfo = Hash.new
364
+ file = Pathname.new("/proc/cpuinfo")
365
+ lines = file.readlines
366
+ lines.each { |line|
367
+ #@logger.info? && @logger.info("LINE: "+line)
368
+ if ( line.length == 1 )
369
+ event = LogStash::Event.new(
370
+ "cpuinfo" => cpuinfo,
371
+ "file" => file.to_s,
372
+ "host" => @host,
373
+ "type" => "cpuinfo" )
374
+ decorate(event)
375
+ queue << event
376
+ cpuinfo = Hash.new
377
+ next
378
+ end
379
+ m = line.strip.split(/\s+:\s+/)
380
+ if ( m && m.length >= 2 )
381
+ if ( "flags" == m[0] )
382
+ cpuinfo[m[0]] = m[1].strip.split(/\s+/)
383
+ next
384
+ end
385
+ if ( /(processor|cpu MHz|physical id|siblings|core id|cpu cores|apicid|initial apicid|cpuid level|bogomips|clflush size|cache size)/.match(m[0]) )
386
+ cpuinfo[m[0]] = m[1].to_i
387
+ next
388
+ end
389
+ if ( /(cpu MHz|bogomips)/.match(m[0]) )
390
+ cpuinfo[m[0]] = m[1].to_f
391
+ next
392
+ end
393
+ if ( /(cache size)/.match(m[0]) )
394
+ cpuinfo[m[0]] = m[1].split(/\s+/)[0].to_i
395
+ next
396
+ end
397
+ cpuinfo[m[0]] = m[1]
398
+ end
399
+ }
400
+ end
401
+ def readCrypto(queue)
402
+ # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
403
+ #processor : 0
404
+ #vendor_id : GenuineIntel
405
+ #cpu family : 6
406
+ #model : 69
407
+ #model name : Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
408
+ #stepping : 1
409
+ #microcode : 0x17
410
+ #cpu MHz : 799.996
411
+ #cache size : 3072 KB
412
+ #physical id : 0
413
+ #siblings : 4
414
+ #core id : 0
415
+ #cpu cores : 2
416
+ #apicid : 0
417
+ #initial apicid : 0
418
+ #fpu : yes
419
+ #fpu_exception : yes
420
+ #cpuid level : 13
421
+ #wp : yes
422
+ #flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmo
423
+ #n pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 movbe popcnt tsc_deadline_timer
424
+ #aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid
425
+ #bogomips : 3391.99
426
+ #clflush size : 64
427
+ #cache_alignment : 64
428
+ #address sizes : 39 bits physical, 48 bits virtual
429
+ #power management:
430
+
431
+ crypto = Hash.new
432
+ file = Pathname.new("/proc/crypto")
433
+ lines = file.readlines
434
+ lines.each { |line|
435
+ #@logger.info? && @logger.info("LINE: "+line)
436
+ if ( line.length == 1 )
437
+ event = LogStash::Event.new(
438
+ "crypto" => crypto,
439
+ "file" => file.to_s,
440
+ "host" => @host,
441
+ "type" => "crypto" )
442
+ decorate(event)
443
+ queue << event
444
+ next
445
+ end
446
+ m = line.strip.split(/[:\s]+/)
447
+ if ( m && m.length >= 2 )
448
+ crypto[m[0]] = m[1]
449
+ end
450
+ }
451
+ end
452
+
453
+ def readWireless(queue)
454
+ # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
455
+ file = Pathname.new("/proc/net/wireless")
456
+ #Inter-| sta-| Quality | Discarded packets | Missed | WE
457
+ #face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
458
+ # wlan0: 0000 32. -78. -256 0 0 0 19 89 0
459
+ lines = file.readlines
460
+ junk = lines.shift
461
+ junk = lines.shift
462
+ lines.each { |line|
463
+ #@logger.info? && @logger.info("LINE: "+line)
464
+ m = line.strip.split(/[:\s]+/)
465
+ #puts(m)
466
+ if (m && m.length >= 11 )
467
+ event = LogStash::Event.new(
468
+ "raw" => line,
469
+ "iface" => m[0],
470
+ "status" => m[1].to_i,
471
+ "linkQuality" => m[2].to_f,
472
+ "levelQuality" => m[3].to_f,
473
+ "noiseQulity" => m[4].to_i,
474
+ "nwidDiscard" => m[5].to_i,
475
+ "cryptDiscard" => m[6].to_i,
476
+ "fragDiscard" => m[7].to_i,
477
+ "retryDiscard" => m[8].to_i,
478
+ "miscDiscard" => m[9].to_i,
479
+ "missedBeacon" => m[10].to_i,
480
+ "we22" => m[11].to_i,
481
+ "file" => file.to_s,
482
+ "host" => @host,
483
+ "type" => "wireless" )
484
+ decorate(event)
485
+ queue << event
486
+ end
487
+ }
488
+
489
+ end
490
+ def readSysIpcShm(queue)
491
+ # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
492
+ file = Pathname.new("/proc/sysvipc/shm")
493
+ # key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap
494
+ # 0 589824 1600 524288 1708 1739 2 1000 1000 1000 1000 1433801660 1433801660 1433801659 12288 0
495
+ # 0 491521 1600 524288 1479 871 2 1000 1000 1000 1000 1433801655 0 1433801655 147456 0
496
+ lines = file.readlines
497
+ junk = lines.shift
498
+ lines.each { |line|
499
+ m = line.strip.split(/[\s]+/)
500
+ if (m && m.length >= 14 )
501
+ event = LogStash::Event.new(
502
+ "raw" => line,
503
+ "key" => m[0],
504
+ "shmid" => m[1].to_i,
505
+ "perms" => m[2].to_i,
506
+ "size" => m[3].to_i,
507
+ "cpid" => m[4].to_i,
508
+ "lpid" => m[5].to_i,
509
+ "nattch"=> m[6].to_i,
510
+ "uid" => m[7].to_i,
511
+ "gid" => m[8].to_i,
512
+ "cuid" => m[9].to_i,
513
+ "cgid" => m[10].to_i,
514
+ "atime" => m[11].to_i,
515
+ "dtime" => m[12].to_i,
516
+ "ctime" => m[13].to_i,
517
+ "rss" => m[14].to_i,
518
+ "file" => file.to_s,
519
+ "host" => @host,
520
+ "type" => "sysipcshm" )
521
+ decorate(event)
522
+ queue << event
523
+ end
524
+ }
525
+
526
+ end
527
+
528
+ def run(queue)
529
+ loop do
530
+ begin
531
+ start = Time.now
532
+ readVmStats(queue) if @vmstats
533
+ readLoadAverage(queue) if @loadavg
534
+ readMemInfo(queue) if @meminfo
535
+ readPidStats(queue) if @pidstats
536
+ readDiskStats(queue) if @diskstats
537
+ readMounts(queue) if @mounts
538
+ readNetDev(queue) if @netdev
539
+ readCpuInfo(queue) if @cpuinfo
540
+ readCrypto(queue) if @crypto
541
+ readWireless(queue) if @wireless
542
+ readSysIpcShm(queue) if @sysipcshm
543
+ duration = Time.now - start
544
+ @logger.info("Parsing completed", :duration => duration, :interval => @interval )
545
+ # Sleep for the remainder of the interval, or 0 if the duration ran
546
+ # longer than the interval.
547
+ sleeptime = [0, @interval - duration].max
548
+ if sleeptime == 0
549
+ @logger.warn("Parsing longer than the interval. Skipping sleep.",
550
+ :duration => duration,
551
+ :interval => @interval)
552
+ else
553
+ sleep(sleeptime)
554
+ end
555
+ rescue => exception
556
+ #puts exception.message
557
+ puts exception.backtrace
558
+ raise
559
+ end # rescue
560
+ end # loop
561
+ end # def run
562
+ end # class LogStash::Inputs::Example