Created
November 7, 2012 09:48
-
-
Save sivagao/4030460 to your computer and use it in GitHub Desktop.
clean data, present the data with graph and chart(graphviz,scruffy) #practical ruby for system administrator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# attempting to present data without thought as to the analysis often gives rise to | |
# presentations that are nothing more than stylish gloss on a stinky foundation. | |
# 其实这一章没有太多好用的类库介绍,基本是使用。ruby的使用 | |
# 回去可以整理下。 | |
# Listing 9-8. Storing the Array of Logins in a Timestamped File for Later Retrieval | |
require "fileutils" | |
require "remote_host" | |
require "yaml" | |
FileUtiles.mkdir_p("data") | |
Dir.chdir("data") | |
hosts_to_monitor = ["fishbrain.local", "fishwife.local"] | |
hosts_to_monitor.each do |host| logins = RemoteHost.new(host).last_logins | |
dump_file = host + Time.now.strftime(".%Y%m%dT%H%M%S.yaml") | |
File.open(dump_file, "w") { |f| YAML.dump(logins, f) } | |
end | |
# Listing 9-9. Parsing Login Fields into an Event, Particularly to Coerce the Date Information | |
DAY_INDEX, NOW = {}, Time.now | |
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].each_with_index do |day, i| | |
DAY_INDEX[day] = i + 1 | |
end | |
def parse_event(login_fields, host) | |
user, device, source, date_info = login_fields | |
date_info =~ /^(...) (.){12}/ | |
wday, date = DAY_INDEX[$1], Time.parse($2) | |
while wday != date.wday or date > NOW | |
date = Time.local(date.year - 1, date.month, date.day, date.hour, date.min) | |
end | |
duration = nil | |
if date_info =~ /\((\d+\+)?(\d+):(\d+)\)$/ | |
days, hours, mins = $1, $2, $3 | |
duration = mins + hours * 60 + days.to_i * 24 * 60 | |
end | |
{:user => user, :device => device, :source => source, | |
:date => date, :duration => duration, :host => host} | |
end | |
# Listing 9-10. Assigning Events to a Unique 24-Hour Event Bin | |
def assign_event(event, bin_hash) | |
date_key = event[:date].strftime("%Y%m%d") | |
bin = (bin_hash[date_key] ||= {}) | |
event_key = event.values_at(:user, :device, :source, :date, :host).join(";") | |
bin[event_key] = event | |
end | |
#Listing 9-11. The Final Event Processing Script | |
require "yaml" | |
data_dir = (ARGV[0] || "data") | |
fail "couldn't find directory #{data_dir}" unless File.directory?(data_dir) | |
Dir.chdir(data_dir) | |
Dir.mkdir("processed") unless File.directory?("processed") | |
# code from Listings 9-9 and 9-10 would go here | |
data_files, periods = DIR["*.yaml"], {} | |
data_files.each do |file| | |
host = File.basename(file).split(".").first | |
logins = YAML.load_file(file) | |
logins.each do |login| | |
event = parse_event(login, host) | |
assign_event(event, periods) | |
end | |
end | |
periods.each do |date_string, events| | |
event_file = File.join("processed", date_string + ".yaml") | |
if File.exist?(event_file) | |
old_events = YAML.load_file(event_file) | |
events = old_events.merge(events) | |
end File.open(event_file, "w") { |f| YAML.dump(events, f) } | |
end | |
File.delete(data_files) | |
#Listing 9-12. Summarizing the Total Session Duration Amounts by User and Then by Date | |
require "yaml" | |
source_dir = ARGV[0] | |
fail "couldn't find directory #{source_dir}" unless File.directory?(source_dir) | |
users = {} | |
Dir[File.join(source_dir, "*")].each do |file| | |
date_string = File.basename(file, ".yaml") | |
events = YAML.load_file(file) | |
events.each do |key, event| | |
duration = event[:duration].to_i | |
next unless duration > 0 | |
user = (users[event[:user]] ||= Hash.new(0)) | |
user[date_string] += duration | |
end | |
end | |
# using Scruffy Charts | |
# SVG Format | |
# For rendering a graph, scruffy relies upon the RMagick library (itself a Ruby interface to the ImageMagick library). | |
require "scruffy" | |
include Scruffy | |
graph = Graph.new(:title => "Average Flatulence per Capita") | |
graph.add(:line, "Cows", [150, 200, 250, 240]) | |
graph.add(:area, "Sheep", [100, 110, 120, 140]) | |
graph.add(:bar, "Man", [50, 65, 78, 66]) | |
graph.render(:as => "PNG", :size => [500, 400], :to => "/tmp/flatulence.png") | |
require "scruffy" | |
include Scruffy | |
# code from Listing 9-12 would go here | |
exit if users.empty? | |
all_dates = users.map { |user, dates| dates.keys }.flatten.uniq.sort | |
graph = Graph.new(:point_markers => all_dates) | |
graph.title = "Total Login Minutes per User" | |
users.each do |user, dates| | |
all_values = all_dates.map { |date| dates[date].to_i } | |
graph.add(:line, user, all_values) | |
end | |
graph.render(:as => "PNG", :width => 1024, :to => "/tmp/user_accounting.png") | |
# CSS Charts in Rails | |
# The CSS box model allows for doing pretty basic rectangular drawing, including background, border, and alignment facilities. | |
# $ script/plugin install http://topfunky.net/svn/plugins/css_graphs | |
# $ script/generate css_graphs | |
# edit rhtml templates using the following pattern: | |
=begin | |
<h2>Horizontal Bar Chart (Complex)</h2> | |
<%= complex_bar_graph(["Mail", 58], ["Web", 38], ["FTP", 29], ["P2P", 25], ["Other", 24]) %> | |
=end | |
# Graph | |
# Using graphviz language - dot | |
# the Ruby wrapper - ruby-graphviz | |
$ tar -xzf ruby-graphviz_0.6.0.tar.gz | |
$ cd ruby-graphviz | |
$ ruby extconf.rb | |
require "graphviz" | |
# code from Listing 9-12 modified as discussed (for indexing by host) would go here | |
exit if users.empty? | |
graph = Graphviz.new("G") | |
users.each do |user, hosts| | |
graph.add_node(user) | |
hosts.each do |host, usage| | |
graph.add_node(host) | |
graph.add_edge(user, host, "weight" => usage) | |
end | |
end | |
graph.output("output" => "png", "file" => "/tmp/user_relationships.png") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment