[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

{} as record separators?

Bob Norfolk

8/19/2006 6:17:00 PM

I'm working on a ruby script to read Nagios's status.dat and output it's
data.

The data format looks like this:

service {
host_name=www.bob.com
service_description=bob-website
modified_attributes=0
check_command=check-bob-website
event_handler=
has_been_checked=1
should_be_scheduled=1
check_execution_time=0.155
check_latency=0.250
check_type=0
current_state=0
last_hard_state=0
current_attempt=1
max_attempts=3
state_type=1
last_state_change=1155243779
last_hard_state_change=1155243779
last_time_ok=1155507506
last_time_warning=1154915720
last_time_unknown=0
last_time_critical=1155243478
plugin_output=HTTP OK HTTP/1.1 200 OK - 0.117 second response
time
performance_data=time=0.116677s;;;0.000000 size=3998B;;;0
last_check=1155507506
next_check=1155507806
current_notification_number=0
last_notification=0
next_notification=0
no_more_notifications=0
notifications_enabled=1
active_checks_enabled=1
passive_checks_enabled=0
event_handler_enabled=0
problem_has_been_acknowledged=0
acknowledgement_type=0
flap_detection_enabled=0
failure_prediction_enabled=1
process_performance_data=1
obsess_over_service=1
last_update=1155507620
is_flapping=0
percent_state_change=0.00
scheduled_downtime_depth=0
}


What I've written works, but it only works for one block. I'm not quite
sure how to make it work for the whole block?

Any advice would be greatly appreciated.

Here's the code I've written:

Class server

def read_nagiosstatus(filename)
nagios_status = {}
for line in IO.readlines(filename):
line.strip! # Remove all extraneous
whitespace
line.sub!(/#.*$/, "") # Remove comments
next unless line.length > 0 # check for end of file
var, value = line.split(/\s*=\s*/, 2)
nagios_status[var.intern] = value
end
return nagios_status
end

nagiosstatus = read_nagiosstatus("status.dat")
puts "Host name is #{nagiosstatus[:host_name]}"
puts "Service description is #{nagiosstatus[:service_description]}"

--
Posted via http://www.ruby-....

8 Answers

yu.ching.tien

8/20/2006 12:04:00 AM

0

** first try **


data = {}
File.foreach( "nagios.dat" ) do |e|
next if e =~ /service \{|\}/
k,v = e.strip.split("=")
data[k] = v
end


it didnt work because of line below has more than one "="

> performance_data=time=0.116677s;;;0.000000 size=3998B;;;0


** second try **

data = {}
File.foreach( "nagios.dat") do |e|
next if e =~ /service \{|\}/
if e.strip =~ /(.*?)=(.*)/
data[$1]=$2
end
end

Scott

8/20/2006 12:19:00 AM

0

Wow, this can't be "The Ruby Way", but it works:

def nagios_data(data)
blocks = data.strip.split(/.*\}\n(?=\w+\s+\{)/)
blocks.map do |nagios_data|
data_points = nagios_data.split("\n")
# you can possibly use this as a hash key if they will be unique
# block_name = data_points[0][/\w+/]
data_points[1..-1].inject({}) do |values, data_point|
unless data_point =~ /\s+\}/
key, value = data_point.strip.sub(/#.*$/, "").split(/\s*=\s*/, 2)
values[key.intern] = value
end
values
end
end
end

require 'pp'

pp nagios_data(File.read("status.dat"))

Bob Norfolk

8/20/2006 12:30:00 AM

0

Scott wrote:
> Wow, this can't be "The Ruby Way", but it works:
>
> def nagios_data(data)
> blocks = data.strip.split(/.*\}\n(?=\w+\s+\{)/)
> blocks.map do |nagios_data|
> data_points = nagios_data.split("\n")
> # you can possibly use this as a hash key if they will be unique
> # block_name = data_points[0][/\w+/]
> data_points[1..-1].inject({}) do |values, data_point|
> unless data_point =~ /\s+\}/
> key, value = data_point.strip.sub(/#.*$/, "").split(/\s*=\s*/, 2)
> values[key.intern] = value
> end
> values
> end
> end
> end
>
> require 'pp'
>
> pp nagios_data(File.read("status.dat"))


When I try running this code, I get:

nagios_test2.rb:10:in `nagios_data': undefined method `intern' for
nil:NilClass (NoMethodError)
from nagios_test2.rb:7:in `inject'
from nagios_test2.rb:7:in `each'
from nagios_test2.rb:7:in `inject'
from nagios_test2.rb:7:in `nagios_data'
from nagios_test2.rb:3:in `map'
from nagios_test2.rb:3:in `nagios_data'
from nagios_test2.rb:19


Where does the intern method come from?

--
Posted via http://www.ruby-....

Bob Norfolk

8/20/2006 12:52:00 AM

0

> Here's the code I've written:
>
> Class server
>
> def read_nagiosstatus(filename)
> nagios_status = {}
> for line in IO.readlines(filename):
> line.strip! # Remove all extraneous
> whitespace
> line.sub!(/#.*$/, "") # Remove comments
> next unless line.length > 0 # check for end of file
> var, value = line.split(/\s*=\s*/, 2)
> nagios_status[var.intern] = value
> end
> return nagios_status
> end
>
> nagiosstatus = read_nagiosstatus("status.dat")
> puts "Host name is #{nagiosstatus[:host_name]}"
> puts "Service description is #{nagiosstatus[:service_description]}"

So this code actually works. It reads through my key=value pairs just
fine. But of course, there's no code here to separate between multiple
instances of {}.

I understand now how to split on {} thanks to the examples you've all
posted.

What I don't understand though, is how would I address or list these?
I've got two problems to solve.

The first is that I'd be happy if I could just get an object that was
unique based on the host_name and I could call
nagios_status[(:host_name,:plugin_output)] for each host in the
status.dat file.

The second is that each host_name has multiple services. My unique key
needs to be based on the host_name variable. And I think I need to end
up so I have an object that's like host_name.service_name.variables.




def read_nagiosstatus(filename)
nagios_status = {}
for line in IO.readlines(filename):
line.strip! # Remove all extraneous
whitespace
line.sub!(/#.*$/, "") # Remove comments
next unless line.length > 0 # check for end of file
var, value = line.split(/\s*=\s*/, 2)
nagios_status[var.intern] = value
end
return nagios_status
end

nagiosstatus = read_nagiosstatus("status.dat")
puts #{nagios_status[:host_name]}

--
Posted via http://www.ruby-....

John Johnson

8/20/2006 12:59:00 AM

0

On Sat, 19 Aug 2006 14:17:11 -0400, Bob Norfolk =

<punkrockgeekboy@yahoo.com> wrote:

> I'm working on a ruby script to read Nagios's status.dat and output it=
's
> data.
Bob,

See if this works for you.

Regards,
JJ

#
# Copyright 2006, by John Johnson, All Rights Reserved
# Released under the NewBSD license.
#

require 'ostruct'
require 'pp'

class Services < Hash

SERVER_RE =3D /^\s*service\s*\{(.+?)\n\s*\}\s*$/m
VALUE_RE =3D /^\s*([^=3D]+)\s*=3D\s*([^\n=3D]*?)$/
INTEGER_RE =3D /^([-+]?\d+)$/
FLOAT_RE =3D /^([-+]?\d*\.\d*[eE]?\d*)$/
BOOLEAN_TRUE_RE =3D /^[1tTyY]+/ # e.g. 1, true, True, yes, Yes

# Types of declarations possible for field names.
:FIELD_NAMES
:FIELD_REGULAR_EXPRESSIONS

#
# Conversion for field values.
#
NAME_TYPES =3D 0
NAMES =3D 1
CONVERSION_BLOCK =3D 2
CONVERSIONS =3D [

# The following fields have time values that are the number
# of seconds past the epoch.
[
# Types of names listed.
[ :FIELD_NAMES ],
# Field name declarations.
['last_state_change', 'last_hard_state_change',
'last_time_ok', 'last_time_warning', 'last_time_unknown',
'last_time_critical', 'last_check', 'next_check',
'last_notification', 'next_notification', 'last_update'],
# Code to convert from a String to whatever this is.
lambda { |seconds_string|
return Time.at(seconds_string.to_i)
}
],

# The following appear to be boolean fields.
[
[ :FIELD_NAMES, :FIELD_REGULAR_EXPRESSIONS ],
['modified_attributes', 'has_been_checked', 'should_be_scheduled'=
,
'no_more_notifications',
/\w+_enabled$/, # all field names ending in _enabled
'problem_has_been_acknowledged', 'process_performance_data',
'obsess_over_service', 'is_flapping'],
lambda { |boolean_string|
if boolean_string =3D~ BOOLEAN_TRUE_RE
true
else
false
end
}
]
]

HOST_NAME_PROPERTY =3D 'host_name'

def convert_field(name, value)
CONVERSIONS.each { |conv_set|
name_types =3D conv_set[NAME_TYPES]
names =3D conv_set[NAMES]
conversion_block =3D conv_set[CONVERSION_BLOCK]

if name_types.include?(:FIELD_REGULAR_EXPRESSIONS)
names.each { |name_dec|
case
when name_dec.class=3D=3DString
if name =3D=3D name_dec
return conversion_block.call(value)
end
when name_dec.class=3D=3DRegexp
if name =3D~ name_dec
return conversion_block.call(value)
end
else
fail "Don't know what a #{name_dec.class} field name is"
end
}
end
if name_types.include?(:FIELD_NAMES)
if names.include?(name)
return conversion_block.call(value)
end
end
}

# Try implicit conversions.
case value
when INTEGER_RE
return Integer(value)
when FLOAT_RE
return Float(value)
end

return String(value)
end

def initialize(filename)
super
contents =3D File.open(filename).read
contents.scan(SERVER_RE) { |value_ary|
values =3D value_ary[0]
host_name =3D ""
service =3D OpenStruct.new
values.scan(VALUE_RE) { |name, value|
converted =3D convert_field(name, value)
dumped =3D Marshal.dump(converted)
service.instance_eval(
"self.#{name} =3D Marshal.load('#{dumped}')")
host_name=3Dvalue if name =3D=3D HOST_NAME_PROPERTY
}
self[host_name] =3D service
}
end
end

services =3D Services.new('nagio.txt')
services.each_pair{ |service, properties|
puts "Host: #{service}"
puts "\t has_been_checked: #{properties.has_been_checked}"
puts "\t next_check: #{properties.next_check}"
puts "\tnotifications_enabled: #{properties.notifications_enabled}"
}

if services['www.bob.com'].obsess_over_service
puts "Someone is obsessing over Bob!"
else
puts "No one is obsessing over Bob."
end

if services['www.test.com'].obsess_over_service
puts "Someone is obsessing over Test!"
else
puts "No one is obsessing over Test."
end


-- =

Using Opera's revolutionary e-mail client: http://www.opera...

John Johnson

8/22/2006 4:45:00 PM

0

On Sat, 19 Aug 2006 20:59:15 -0400, John Johnson <johnatl@mac.com> wrote:

> On Sat, 19 Aug 2006 14:17:11 -0400, Bob Norfolk
> <punkrockgeekboy@yahoo.com> wrote:
>
>> I'm working on a ruby script to read Nagios's status.dat and output it's
>> data.
> Bob,
>
> See if this works for you.
>
> Regards,
> JJ
>

So, did it work?

--
Using Opera's revolutionary e-mail client: http://www.opera...

Bob Norfolk

8/22/2006 8:01:00 PM

0

John Johnson wrote:
> On Sat, 19 Aug 2006 20:59:15 -0400, John Johnson <johnatl@mac.com>
> wrote:
>
>> JJ
>>
>
> So, did it work?

Actually, I was just working on debugging this error that the script
above gives :


nagiostest3.rb:111:in `initialize': (eval):1:in `initialize': compile
error (SyntaxError)
(eval):1: unterminated string meets end of file
(eval):1: parse error, unexpected $, expecting ')'
íelf.last_time_critical = Marshal.load(u: Time
^
from nagiostest3.rb:108:in `initialize'
from nagiostest3.rb:104:in `initialize'
from nagiostest3.rb:119

--
Posted via http://www.ruby-....

John Johnson

8/23/2006 2:30:00 AM

0

On Tue, 22 Aug 2006 16:00:37 -0400, Bob Norfolk
<punkrockgeekboy@yahoo.com> wrote:

> John Johnson wrote:
>> On Sat, 19 Aug 2006 20:59:15 -0400, John Johnson <johnatl@mac.com>
>> wrote:
>>
>>> JJ
>>>
>>
>> So, did it work?
>
> Actually, I was just working on debugging this error that the script
> above gives :
>
>
> nagiostest3.rb:111:in `initialize': (eval):1:in `initialize': compile
> error (SyntaxError)
> (eval):1: unterminated string meets end of file
> (eval):1: parse error, unexpected $, expecting ')'
> íelf.last_time_critical = Marshal.load(u: Time
> ^
> from nagiostest3.rb:108:in `initialize'
> from nagiostest3.rb:104:in `initialize'
> from nagiostest3.rb:119
>

Hm, probably a ' in the dumped data.
Try this instead:

def initialize(filename)
super
contents = File.open(filename).read
contents.scan(SERVER_RE) { |value_ary|
values = value_ary[0]
host_name = ""
service = OpenStruct.new
values.scan(VALUE_RE) { |name, value|
converted = convert_field(name, value)
dumped = Marshal.dump(converted)
dumped = dumped.unpack("H*")
service.instance_eval(
"self.#{name} =
Marshal.load(['#{dumped}'].pack('H*'))")
host_name=value if name == HOST_NAME_PROPERTY
}
self[host_name] = service
}
end
end

It converts the dumped data to a hex string, then back, eliminating the
need for escaping characters, etc.

Regards,
JJ

--
Using Opera's revolutionary e-mail client: http://www.opera...