columbo 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2012, Jerome Touffe-Blin
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name of Jerome Touffe-Blin nor the names of its contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Columbo
2
+
3
+ The *columbo* gem goal is to include a middleware
4
+ that captures users browsing sessions for Rack applications.
5
+
6
+ Tribute to [Inspector Columbo](http://www.imdb.com/title/tt1466074/)
7
+
8
+ ## Using with Rack application
9
+
10
+ *Columbo* can be used with any Rack application,
11
+ for example with a **Sinatra** application.
12
+ If your application includes a rackup file
13
+ or uses *Rack::Builder* to construct the application pipeline,
14
+ simply require and use as follows:
15
+
16
+ require 'rack/capture'
17
+ use Rack::Capture
18
+ run app
19
+
20
+ ## Using with Rails 3
21
+
22
+ In order to use, include the following in a Rails application
23
+ *Gemfile* file:
24
+
25
+ gem 'columbo'
26
+
27
+ *config/application.rb* file:
28
+
29
+ require 'rack/capture'
30
+ config.middleware.insert_before ActionDispatch::ShowExceptions, Columbo::Capture, {capture: Rails.env.production?}
31
+
32
+ Check the Rack configuration:
33
+
34
+ rake middleware
35
+
36
+ ## Disclaimer
37
+
38
+ This is an alpha release and it is untested with Sinatra, it is tested with Rails 3 only.
39
+ UI to explore sessions will be completed later (ETA: 2013'Q2).
40
+
41
+ ## Author
42
+
43
+ Jerome Touffe-Blin, [@jtblin](https://twitter.com/jtlbin), [http://www.linkedin.com/in/jtblin](http://www.linkedin.com/in/jtblin)
44
+
45
+ ## License
46
+
47
+ Columbo is copyright 2012 Jerome Touffe-Blin and contributors. It is licensed under the BSD license. See the include LICENSE file for details.
48
+
@@ -0,0 +1,67 @@
1
+ require 'columbo'
2
+ require 'rack/utils'
3
+ require 'rack/logger'
4
+
5
+ module Columbo
6
+ class Capture
7
+ include Rack::Utils
8
+
9
+ FORMAT = %{[Columbo #{Columbo::VERSION}] %s - [%s] %s "%s%s %s"\n}
10
+
11
+ def initialize(app, opts={})
12
+ @app = app
13
+ @capture = opts[:capture] || false
14
+ @bench = (opts[:capture] && opts[:bench]) || false
15
+ @logger = opts[:logger]
16
+ @inspector = Columbo::Inspector.new
17
+ end
18
+
19
+ def call(env)
20
+ dup._call(env)
21
+ end
22
+
23
+ def _call(env)
24
+ start_processing = Time.now
25
+ status, headers, response = @app.call(env)
26
+ stop_processing = Time.now
27
+
28
+ start = Time.now if @bench
29
+
30
+ headers = HeaderHash.new(headers) # Is it required?
31
+
32
+ if !STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
33
+ !headers['transfer-encoding'] &&
34
+ headers['content-type'] &&
35
+ headers['content-type'].include?("text/html")
36
+
37
+ Thread.new { @inspector.investigate env, status, headers, response, start_processing, stop_processing if @capture }
38
+
39
+ end
40
+
41
+ if @bench
42
+ stop = Time.now
43
+ log(env, (stop-start).seconds)
44
+ headers['Columbo'] = "version #{Columbo::VERSION}, time #{(stop-start).seconds}s"
45
+ end
46
+
47
+ [status, headers, response]
48
+ end
49
+
50
+ private
51
+
52
+ def log(env, time)
53
+ now = Time.now
54
+ logger = @logger || env['rack.errors']
55
+
56
+ logger.write FORMAT % [
57
+ "Time: #{time}s",
58
+ now.strftime("%d-%b-%Y %H:%M:%S"),
59
+ env["REQUEST_METHOD"],
60
+ env["PATH_INFO"],
61
+ env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
62
+ env["HTTP_VERSION"]
63
+ ]
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,39 @@
1
+ require 'mongo'
2
+
3
+ module Columbo
4
+ class DbClient
5
+ include Mongo
6
+
7
+ attr_accessor :coll
8
+
9
+ def initialize
10
+ client = Mongo::MongoClient.from_uri(Columbo::MONGO_URI)
11
+ db = client[Columbo::MONGO_DB]
12
+ @coll = db[Columbo::MONGO_COLLECTION]
13
+ end
14
+
15
+ def insert(*args)
16
+ coll.insert *args
17
+ end
18
+
19
+ def save(*args)
20
+ coll.findOne *args
21
+ end
22
+
23
+ def find(*args)
24
+ coll.find *args
25
+ end
26
+
27
+ def find_one(*args)
28
+ coll.find_one *args
29
+ end
30
+
31
+ def remove(*args)
32
+ coll.remove *args
33
+ end
34
+
35
+ def update(*args)
36
+ coll.update *args
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,71 @@
1
+ require 'rack/request'
2
+ require 'rack/response'
3
+ require 'nokogiri'
4
+ require 'html_mini'
5
+
6
+ module Columbo
7
+ class Inspector
8
+
9
+ def initialize
10
+ end
11
+
12
+ def investigate(env, status, headers, body, start, stop)
13
+ # Lazy connection to MongoDB
14
+ client = Columbo::DbClient.new
15
+ # Normalise request from env
16
+ request = Rack::Request.new(env)
17
+ html = ''
18
+ body.each { |part| html += part }
19
+ # Retrieve plain text body for full text search
20
+ text, title = to_plain_text(html)
21
+ # Get request headers
22
+ request_headers = {}
23
+ request.env.each { |key, value| request_headers[key.sub(/^HTTP_/, '').downcase] = value if key.start_with? 'HTTP_'}
24
+ # Convert MIME types into String
25
+ formats = request.env['action_dispatch.request.formats'].collect {|format| format.to_s}
26
+ data = {
27
+ request: {
28
+ params: request.params,
29
+ remote_ip: request.ip,
30
+ user_agent: request.user_agent,
31
+ method: request.env['REQUEST_METHOD'],
32
+ uri: request.env['REQUEST_URI'],
33
+ script: request.env['SCRIPT_NAME'],
34
+ path: request.env['PATH_INFO'],
35
+ query_string: request.env['QUERY_STRING'],
36
+ protocol: request.env['rack.url_scheme'],
37
+ server_name: request.env['SERVER_NAME'],
38
+ server_port: request.env['SERVER_PORT'],
39
+ http: request.env['SERVER_PROTOCOL'],
40
+ session: request.env['rack.session'],
41
+ cookie: request.env['rack.request.cookie_hash'],
42
+ formats: formats,
43
+ path_parameters: request.env['action_dispatch.request.path_parameters'],
44
+ headers: request_headers
45
+ },
46
+ status: status,
47
+ headers: headers,
48
+ length: html.length,
49
+ body: HtmlMini.minify(html),
50
+ text: text,
51
+ title: title,
52
+ start: start,
53
+ stop: stop,
54
+ time: stop-start
55
+ }
56
+ # Insert data in MongoDB
57
+ client.insert data
58
+ end
59
+
60
+ def to_plain_text(html)
61
+ html_doc = Nokogiri::HTML(html)
62
+ html_doc.xpath('//script').each {|node| node.remove}
63
+ html_doc.xpath('//style').each {|node| node.remove}
64
+ text = ""
65
+ html_doc.xpath('//body').each {|node| text += node.text.gsub(/\s{2,}/, ' ')}
66
+ title = html_doc.xpath('//title').first.text
67
+ [text, title]
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module Columbo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'sinatra/base'
2
+
3
+ module Columbo
4
+ class Web < Sinatra::Base
5
+
6
+ end
7
+ end
data/lib/columbo.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'columbo/version'
2
+ require 'columbo/db_client'
3
+ require 'columbo/inspector'
4
+
5
+ module Columbo
6
+ MONGO_URI = "mongodb://columbo:inspector@linus.mongohq.com:10025/columbo_test".freeze
7
+ MONGO_DB = "columbo_test".freeze
8
+ MONGO_COLLECTION = "tests".freeze
9
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: columbo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jerome Touffe-Blin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: nokogiri
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.5.9
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.5.9
46
+ - !ruby/object:Gem::Dependency
47
+ name: html_mini
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.2
62
+ - !ruby/object:Gem::Dependency
63
+ name: mongo
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.6.1
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.6.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: bson_ext
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 1.6.1
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 1.6.1
94
+ description: ! 'A Ruby client library for Columbo: a Customer Experience Management
95
+ tool'
96
+ email: jtblin@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files:
100
+ - LICENSE
101
+ - README.md
102
+ files:
103
+ - lib/columbo/capture.rb
104
+ - lib/columbo/db_client.rb
105
+ - lib/columbo/inspector.rb
106
+ - lib/columbo/version.rb
107
+ - lib/columbo/web.rb
108
+ - lib/columbo.rb
109
+ - LICENSE
110
+ - README.md
111
+ homepage: http://github.com/jtblin/columbo-rb
112
+ licenses: []
113
+ post_install_message:
114
+ rdoc_options:
115
+ - --charset=UTF-8
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: 1.3.6
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.25
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: A Ruby client library for Inspector Columbo
136
+ test_files: []