Skip to content

Instantly share code, notes, and snippets.

@nono
Created December 30, 2011 11:07
Show Gist options
  • Select an option

  • Save nono/1539335 to your computer and use it in GitHub Desktop.

Select an option

Save nono/1539335 to your computer and use it in GitHub Desktop.

Revisions

  1. nono created this gist Dec 30, 2011.
    111 changes: 111 additions & 0 deletions rails_log_stathat.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    #!/usr/bin/env ruby

    require 'net/http/persistent'
    require 'uri'
    require 'thread'

    USAGE = <<EOS
    Parse a Rails log file and send metrics to stathat
    export EMAIL=email
    export PREFIX=prefix
    tail -f logfile | #{$0}
    - logfile is the path to the Rails logfile (example: log/production.log)
    - email is the email of the stathat account (mandatory)
    - prefix is the prefix for the stats name (optional, blank by default)
    WARNING: need ruby 1.9 and the net-http-persistent gem
    EOS

    $verbose = false
    $exit = false
    $uri = URI "http://api.stathat.com/ez"
    $queue = Queue.new
    $email = ENV['EMAIL']
    $prefix = ENV['PREFIX']
    if %w(-h --help).include?(ARGV[0]) || $email.nil?
    puts USAGE
    exit 0
    end

    module REGEXP
    PROCESSING = /^ Processing by (?<controller>\w+)#(?<action>\w+) as (?<format>\w+)$/
    COMPLETED = /^Completed (?<code>\d+) .* in (?<time>\d+)/
    MONGODB = /^MONGODB/
    RENDERED = /^Rendered (?<template>\w+)/
    STARTED = /^Started (?<verb>\w+) "(?<url>.+)" for (?<ip>[0-9.]+)/
    end


    def count(stat, value)
    stat = "#{$prefix} - #{stat}" if $prefix
    $queue << [stat, value]
    end

    def incr(stat)
    count stat, 1
    end

    def processing(line)
    data = line.match(REGEXP::PROCESSING)
    return unless data
    incr data['controller']
    incr "#{data['controller']}##{data['action']}"
    incr "as #{data['format']}"
    end

    def completed(line)
    data = line.match(REGEXP::COMPLETED)
    return unless data
    incr "Code #{data['code']}"
    count "Completed in", data['time'].to_i
    end

    def mongodb(line)
    incr "MongoDB" if line =~ REGEXP::MONGODB
    end

    def rendered(line)
    data = line.match(REGEXP::RENDERED)
    return unless data
    incr "Rendering total"
    incr "Rendering #{data['template']}"
    end

    def started(line)
    data = line.match(REGEXP::STARTED)
    return unless data
    incr "Requests"
    incr "#{data['verb']} requests"
    incr "URL #{data['url']}"
    incr "IP #{data['ip']}"
    end

    $threads = []
    8.times do
    $threads << Thread.new do
    http = Net::HTTP::Persistent.new $0
    until $exit
    stat, count = *$queue.pop
    post = Net::HTTP::Post.new $uri.path
    post.set_form_data stat: stat, count: count, email: $email
    http.request $uri, post
    puts "count #{stat} -> #{count}" if $verbose
    end
    http.shutdown
    end
    end

    ARGF.each do |line|
    case line[0]
    when ' ' then processing line
    when 'C' then completed line
    when 'M' then mongodb line
    when 'R' then rendered line
    when 'S' then started line
    end
    end

    Thread.pass until $queue.empty?
    $exit = true
    $threads.each {|t| t.join }