ccdk 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ README.markdown
2
+ Manifest.txt
3
+ bin/cc_track_user
4
+ lib/ccdk.rb
5
+ lib/ccdk/log_file.rb
6
+ lib/ccdk/tdump.rb
7
+ lib/ccdk/version.rb
@@ -0,0 +1,54 @@
1
+ # CCDK
2
+
3
+ The Crystal Commerce Debugging Kit
4
+
5
+ ## Description
6
+
7
+ CCDK is a set of tools made to ease development of Rails applications
8
+ developed at [Crystal Commerce](http://www.crystalcommerce.com). It
9
+ includes both executable scripts and modules that can be mixed into
10
+ classes to help debug. The code herein is not designed to be run as
11
+ part of a production application, just for use while building one.
12
+
13
+ ## Included Executables
14
+
15
+ * `cc_track_user`
16
+
17
+ ## `cc_track_user`
18
+
19
+ `cc_track_user` is a script that will search a Rails log file for a
20
+ specific IP address and display the actions that the user has
21
+ performed. This can be helpful in tracking the steps a user took to
22
+ get their session into a particular state.
23
+
24
+ ### Usage
25
+
26
+ `cc_track_user IP_ADDR FILE [FILE ...]`
27
+
28
+ * IP_ADDR is the ip address to track
29
+ * FILE is a a file (or list of files) to search across
30
+
31
+ If any the file names passed to `cc_track_user` end in `.gz`,
32
+ `cc_track_user` will assume that they have been gzipped when it opens
33
+ them. This makes it easy to follow a user's actions across several
34
+ days of logs without having to unzip the file first.
35
+
36
+ It is suggested to pass the files to `cc_track_user` from oldest to
37
+ newest so the output is chronological.
38
+
39
+ ## Included Modules
40
+
41
+ * `Ccdk::TDump`
42
+
43
+ ## `Ccdk::TDump`
44
+
45
+ `TDump` is a module that allows you to display a templated
46
+ representation of a record using the `#tdump` method. It can be passed
47
+ a filename, a string template, an erb object, or an IO (really
48
+ anything that responds to `#read`).
49
+
50
+ ### Examples
51
+
52
+ car.tdump('I have a <%= year %> <%= make %> <%= model %>')
53
+
54
+ product.tdump('path/to/product_template.erb')
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ccdk/log_file'
3
+
4
+ class ActionCounter
5
+ attr_reader :ignore_domain, :counts
6
+
7
+ def initialize(ignore_domain = false)
8
+ @counts = {}
9
+ @ignore_domain = ignore_domain
10
+ end
11
+
12
+ def count(file_name)
13
+ log = Ccdk::LogFile.open(file_name)
14
+
15
+ log.each_block do |blk|
16
+ a = get_action(blk)
17
+
18
+ if a
19
+ counts[a] ||= 0
20
+ counts[a] += 1
21
+ end
22
+ end
23
+ end
24
+
25
+ def print_results
26
+ counts.sort{ |a, b| b[1] <=> a[1] }.each do |(action, count)|
27
+ printf("%6d: %s\n", count, action)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def get_action(block)
34
+ url = block.match(/\[http(s?):\/\/([^\/?]+(\/[^?]+))(\?.*)?\]/)
35
+ return nil unless url
36
+
37
+ if ignore_domain
38
+ url[3]
39
+ else
40
+ url[2]
41
+ end
42
+ end
43
+ end
44
+
45
+ if ARGV.size < 1
46
+ puts "Usage: cc_count_actions [--ignore-domain] FILE [FILE ...]"
47
+ exit 1
48
+ elsif ARGV[0] == "--ignore-domain"
49
+ counter = ActionCounter.new(true)
50
+ ARGV.shift
51
+ else
52
+ counter = ActionCounter.new
53
+ end
54
+
55
+ ARGV.each do |file_name|
56
+ counter.count(file_name)
57
+ end
58
+
59
+ begin
60
+ counter.print_results
61
+ rescue Errno::EPIPE, Interrupt
62
+ # Allow the output to be passed to head etc
63
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ccdk/log_file'
3
+
4
+ class Tracker
5
+ def initialize(ip_address)
6
+ @ip_address = ip_address
7
+ end
8
+
9
+ def track(file_name)
10
+ log = Ccdk::LogFile.open(file_name)
11
+
12
+ log.each_block do |blk|
13
+ display(blk) if blk =~ /for #{@ip_address}/
14
+ end
15
+
16
+ log.close
17
+ end
18
+
19
+ def display(block)
20
+ timestamp_method = block.match(/at (.+)\) \[(\w+)\]/)
21
+ timestamp, method = timestamp_method[1], timestamp_method[2]
22
+ url = block.match(/\[(http(s?):\/\/.+\/.*)\]/)
23
+ params = block.match(/Parameters: (\{.*\})/)
24
+
25
+ if url && timestamp && method && params
26
+ puts timestamp
27
+ puts " #{method} #{url[1]}"
28
+ puts " #{params[1]}"
29
+ puts
30
+ end
31
+ end
32
+ end
33
+
34
+ if ARGV.size < 2
35
+ puts "Usage: cc_track_user IP_ADDR FILE [FILE ...]"
36
+ exit 1
37
+ end
38
+
39
+ tracker = Tracker.new(ARGV.shift)
40
+ ARGV.each do |file_name|
41
+ tracker.track(file_name)
42
+ end
@@ -0,0 +1,19 @@
1
+ module Ccdk
2
+ MODULES = {
3
+ :tdump => 'ccdk/tdump'
4
+ }
5
+
6
+ class << self
7
+ def load_all!
8
+ MODULES.values.each do |lib|
9
+ Kernel.require lib
10
+ end
11
+ end
12
+
13
+ def load(*sym)
14
+ sym.each do |sym|
15
+ Kernel.require MODULES[sym]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,105 @@
1
+ require 'zlib'
2
+
3
+ module Ccdk #:nodoc:
4
+
5
+ # A class for reading Rails log files. Provides a way to step through the log
6
+ # by assuming the format of the output conforms to the Rails defaul.
7
+ class LogFile
8
+
9
+ class << self
10
+
11
+ # Open a LogFile with the provided name. If the file name ends in '.gz'
12
+ # assume that the file is gzipped
13
+ #
14
+ # ==== Parameters
15
+ #
16
+ # * +file_name+ - The name of the log file to open
17
+ #
18
+ # ==== Examples
19
+ # # Open the log file 'log/production.log'
20
+ # LogFile.open('log/production.log')
21
+ #
22
+ # # Open the gzipped log file 'log/old/production.log.1.gz'
23
+ # LogFile.open('log/old/production.log.1.gz')
24
+ def open(file_name)
25
+ if file_name =~ /\.gz$/
26
+ GzipLogFile.new(file_name)
27
+ else
28
+ LogFile.new(file_name)
29
+ end
30
+ end
31
+ end
32
+
33
+ # Create a new LogFile
34
+ #
35
+ # ==== Parameters
36
+ #
37
+ # * +name+ - The name of the file to open
38
+ def initialize(name)
39
+ @fh = File.open(name, 'r')
40
+ end
41
+
42
+ # execute code on each block of the log file. A block is defined as starting
43
+ # with Processing and ending with a blank line
44
+ #
45
+ # ==== Examples
46
+ # log.each_block{ |b| puts b if b =~ ApplicationController }
47
+ def each_block
48
+ while !@fh.eof?
49
+ yield next_block
50
+ end
51
+ end
52
+
53
+ # Read the next block from the log file
54
+ #
55
+ # TODO: please refactor me
56
+ def next_block
57
+ lines = []
58
+
59
+ line = @fh.gets
60
+ while !start_of_block?(line)
61
+ line = @fh.gets
62
+ return "" if @fh.eof?
63
+ end
64
+
65
+ while(!@fh.eof? && !end_of_block?(line))
66
+ lines << line.chomp
67
+ line = @fh.gets
68
+ end
69
+
70
+ lines.join("\n")
71
+ end
72
+
73
+ # Close the log file
74
+ def close
75
+ @fh.close
76
+ end
77
+
78
+ private
79
+
80
+ def start_of_block?(line)
81
+ line && line =~ /^Processing/
82
+ end
83
+
84
+ def end_of_block?(line)
85
+ line.nil? || line =~ /^$/ ||
86
+ line =~ /^Starting the New Relic/ ||
87
+ line =~ /^\*\* \[Hoptoad\]/
88
+ end
89
+ end
90
+
91
+ # A Gzipped version of the log file
92
+ # All behavior is the same as a standard log file except it assumes the
93
+ # content has been gzipped
94
+ class GzipLogFile < LogFile
95
+
96
+ # Create a new GzipLogFile. The file name passed must be gzipped
97
+ #
98
+ # ==== Parameters
99
+ #
100
+ # * +file_name+ - The name of the gzipped log file to open
101
+ def initialize(file_name)
102
+ @fh = Zlib::GzipReader.new(File.open(file_name, 'r'))
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,62 @@
1
+ require 'erb'
2
+
3
+ module Ccdk #:nodoc:
4
+
5
+ # Create a templated representation of the object. This module can be useful
6
+ # For debugging objects by dumping them out to a template of your choosing.
7
+ # Similar in use to <tt>pp</tt>, but more flexible so that you can display
8
+ # only the information that you care about.
9
+ module TDump
10
+
11
+ # Convert the object to a <tt>String</tt> based on the provided template.
12
+ # Templates can be specified in several ways
13
+ #
14
+ # * A <tt>String</tt> representation of the template.
15
+ # * A <tt>String</tt> path to a template file
16
+ # * An <tt>Erb</tt> object of the template
17
+ # * An <tt>IO<tt> object that can be read to retrieve a template
18
+ # (Really anything that responds to <tt>#read</tt>)
19
+ #
20
+ # ==== Parameters
21
+ #
22
+ # * +template+ - The template to use for formatting the object
23
+ #
24
+ # ==== Examples
25
+ # # Output information to a templating string
26
+ # car.tdump('I have a <%= year %> <%= make %> <%= model %>')
27
+ #
28
+ # # Use the path to an erb template file
29
+ # product.tdump('path/to/product_template.erb')
30
+ def tdump(template)
31
+ if template.is_a? ERB
32
+ tdump_erb(template)
33
+ elsif template.respond_to?(:read)
34
+ tdump_io(template)
35
+ elsif template.is_a? String
36
+ tdump_string(template)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def tdump_erb(erb)
43
+ erb.result(binding)
44
+ end
45
+
46
+ def tdump_string(string)
47
+ if File.exist?(string)
48
+ tdump_erb(ERB.new(File.read(string)))
49
+ else
50
+ tdump_erb(ERB.new(string))
51
+ end
52
+ end
53
+
54
+ def tdump_io(io)
55
+ tdump_erb(ERB.new(io.read))
56
+ end
57
+ end
58
+ end
59
+
60
+ class Object
61
+ include Ccdk::TDump
62
+ end
@@ -0,0 +1,3 @@
1
+ module Ccdk
2
+ VERSION = "0.2.0"
3
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ccdk
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Burrows
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-19 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: " Ccdk is a set of extensions and scripts helpful to debugging and development\n"
36
+ email: rhburrows@crystalcommerce.com
37
+ executables:
38
+ - cc_track_user
39
+ - cc_count_actions
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - README.markdown
46
+ - Manifest.txt
47
+ - bin/cc_track_user
48
+ - lib/ccdk.rb
49
+ - lib/ccdk/log_file.rb
50
+ - lib/ccdk/tdump.rb
51
+ - lib/ccdk/version.rb
52
+ - bin/cc_count_actions
53
+ has_rdoc: true
54
+ homepage: http://www.crystalcommerce.com
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 23
77
+ segments:
78
+ - 1
79
+ - 3
80
+ - 6
81
+ version: 1.3.6
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.3.7
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Crystal Commerce's Debugging Kit
89
+ test_files: []
90
+