haproxy2rpm 0.0.10 → 0.1.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v 0.1.0
4
+
5
+ * Make Syslog parsing independent from haproxy
6
+ * Examples on how to use it with node.js and connect including a simple
7
+ node.js profiler
8
+
3
9
  ## v 0.0.10
4
10
 
5
11
  * Do not crash when an exception occurs during URI parsing (Knut
data/README.md CHANGED
@@ -27,6 +27,10 @@ Tell haproxy to log to syslog. e.g:
27
27
 
28
28
  Check the examples folder
29
29
 
30
+ ## Node.js support
31
+
32
+ Check the examples folder
33
+
30
34
  ## Supported RPM features
31
35
 
32
36
  * Response times in application server
@@ -46,6 +50,7 @@ Tested in production
46
50
 
47
51
  Passing manual integration test with test logs
48
52
 
53
+ * mri-1.9.3
49
54
  * mri-1.9.2-p180
50
55
  * ree-1.8.7-2011.03
51
56
  * mri-1.8.7-p33
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Profile the duration of a request.
3
+ *
4
+ * Example Output:
5
+ *
6
+ * GET / 200 2
7
+ *
8
+ *
9
+ * Example usage:
10
+ *
11
+ * npm install ain2
12
+ *
13
+ * var SysLogger = require('ain2');
14
+ * var profiler = require('./connect_middleware.js');
15
+ * app.use(profiler(new SysLogger({ tag : "newrelic", facility : 'local0' })));
16
+ *
17
+ *
18
+ * @api public
19
+ */
20
+ module.exports = function profiler(_logger){
21
+ return function(req, res, next){
22
+ var end = res.end
23
+ , start = new Date()
24
+ , logger = _logger || console;
25
+
26
+ // proxy res.end()
27
+ res.end = function(data, encoding){
28
+ res.end = end;
29
+ res.end(data, encoding);
30
+ logger.log(req.method, req.url, res.statusCode, ((new Date) - start));
31
+ };
32
+
33
+ next();
34
+ }
35
+ };
@@ -0,0 +1,72 @@
1
+ #
2
+ # Expected format: Method Uri Status Time
3
+ #
4
+ # GET /test 200 2
5
+ #
6
+ class NodeJsLineParser
7
+
8
+ def initialize(line)
9
+ @parts = line.split("\s")
10
+ end
11
+
12
+ def response_time
13
+ @response_time ||= @parts[3].to_i
14
+ end
15
+
16
+
17
+ def status_code
18
+ @status_code ||= @parts[2].to_i
19
+ end
20
+
21
+ def http_method
22
+ @http_method ||= @parts[0]
23
+ end
24
+
25
+ def uri
26
+ @uri ||= URI.parse(@parts[1])
27
+ end
28
+
29
+ def http_path
30
+ uri.path
31
+ end
32
+
33
+ def http_query
34
+ uri.query
35
+ end
36
+
37
+ def is_error?
38
+ status_code >= 500
39
+ end
40
+
41
+ end
42
+
43
+ config.message_parser = lambda do |line|
44
+ NodeJsLineParser.new(line)
45
+ end
46
+
47
+ config.request_recorder = lambda do |request|
48
+ rpm_number_unit = 1000.0
49
+ params = {
50
+ 'metric' => "Controller#{route_for(request.http_path)}"
51
+ }
52
+
53
+ if request.is_error?
54
+ params['is_error'] = true
55
+ params['error_message'] = "#{request.uri} : Status code #{request.status_code}"
56
+ end
57
+
58
+ record_transaction(request.response_time / rpm_number_unit, params)
59
+ Haproxy2Rpm.logger.debug "RECORDING (transaction) #{request.http_path}: #{params.inspect}"
60
+ end
61
+
62
+ config.routes = [
63
+ {
64
+ :pattern => %r{^/$},
65
+ :target => '/index'
66
+ },
67
+ {
68
+ :pattern => %r{(\.[a-zA-Z_]{2,4})$},
69
+ :target => '/static'
70
+ }
71
+ ]
72
+
@@ -2,13 +2,7 @@ module Haproxy2Rpm
2
2
  class LineParser
3
3
 
4
4
  def initialize(line)
5
- @line = line
6
-
7
- if @line.match "haproxy"
8
- @parts = @line.split("haproxy")[1].split("\s")
9
- else
10
- @parts = @line.split("\s")
11
- end
5
+ @parts = line.split("\s")
12
6
  end
13
7
 
14
8
  def tq
@@ -32,16 +26,16 @@ module Haproxy2Rpm
32
26
  end
33
27
 
34
28
  def status_code
35
- @status_code ||= @parts[6].to_i
29
+ @status_code ||= @parts[5].to_i
36
30
  end
37
31
 
38
32
  # we need to chop \"
39
33
  def http_method
40
- @http_method ||= @parts[13][1..-1]
34
+ @http_method ||= @parts[12][1..-1]
41
35
  end
42
36
 
43
37
  def uri
44
- @uri ||= URI.parse(@parts[14])
38
+ @uri ||= URI.parse(@parts[13])
45
39
  end
46
40
 
47
41
  def http_path
@@ -59,7 +53,7 @@ module Haproxy2Rpm
59
53
  private
60
54
 
61
55
  def response_times
62
- @response_times ||= @parts[5].split("/")
56
+ @response_times ||= @parts[4].split("/")
63
57
  end
64
58
  end
65
59
  end
@@ -1,12 +1,45 @@
1
1
  # Taken from
2
2
  # https://raw.github.com/jordansissel/experiments/master/ruby/eventmachine-speed/basic.rb
3
+ #
3
4
  module Haproxy2Rpm
4
5
  class SyslogHandler < EventMachine::Connection
6
+
7
+ def initialize(*args)
8
+ # The syslog parsing stuff here taken from the 'logporter' gem.
9
+ pri = "(?:<(?<pri>[0-9]{1,3})>)?"
10
+ month = "(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"
11
+ day = "(?: [1-9]|[12][0-9]|3[01])"
12
+ hour = "(?:[01][0-9]|2[0-4])"
13
+ minute = "(?:[0-5][0-9])"
14
+ second = "(?:[0-5][0-9])"
15
+ time = [hour, minute, second].join(":")
16
+ timestamp = "(?<timestamp>#{month} #{day} #{time})"
17
+ hostname = "(?<hostname>[A-Za-z0-9_.:]+)"
18
+ header = timestamp + " " + hostname
19
+ tag = '(?<tag>[a-zA-Z_\-\/\.0-9\[\]]+)'
20
+ message = "(?<message>[ -~]+)" # ascii 32 to 126
21
+ re = "^#{pri}#{header} #{tag}:\s*#{message}"
22
+
23
+ if RUBY_VERSION =~ /^1\.8/
24
+ # Ruby 1.8 doesn't support named captures
25
+ # replace (?<foo> with (
26
+ re = re.gsub(/\(\?<[^>]+>/, "(")
27
+ end
28
+
29
+ @syslog3164_re = Regexp.new(re)
30
+ end
31
+
5
32
  def receive_data(data)
6
- message_start_index = data.index('haproxy')
7
- message = data[message_start_index..-1]
8
- Haproxy2Rpm.logger.debug "RECEIVED (syslog): #{message}"
33
+ match = parse_data(data)
34
+ puts match.inspect
35
+ message = match ? match[5] : ""
36
+ Haproxy2Rpm.logger.debug "RECEIVED (syslog): #{data}"
9
37
  Haproxy2Rpm.rpm.process_and_send(message)
10
38
  end
39
+
40
+ def parse_data(data)
41
+ @syslog3164_re.match(data)
42
+ end
43
+
11
44
  end
12
45
  end
@@ -1,3 +1,3 @@
1
1
  module Haproxy2Rpm
2
- VERSION = "0.0.10"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,33 @@
1
+ $LOAD_PATH.unshift( File.dirname(__FILE__) )
2
+
3
+ require 'test_helper'
4
+
5
+ FIXTURE_SYSLOG_MESSAGE = "<12>Jan 3 16:18:58 rechenschieber.local nodejs[36180]: message"
6
+
7
+ class RpmTest < Test::Unit::TestCase
8
+ context 'regex maching' do
9
+ setup do
10
+ @match = Haproxy2Rpm::SyslogHandler.new(self).parse_data(FIXTURE_SYSLOG_MESSAGE)
11
+ end
12
+
13
+ should 'match the priority' do
14
+ assert_equal '12', @match[1]
15
+ end
16
+
17
+ should 'match timestamp' do
18
+ assert_equal "Jan 3 16:18:58", @match[2]
19
+ end
20
+
21
+ should 'match the hostname' do
22
+ assert_equal "rechenschieber.local", @match[3]
23
+ end
24
+
25
+ should 'match the tag name' do
26
+ assert_equal 'nodejs[36180]', @match[4]
27
+ end
28
+
29
+ should 'match the message' do
30
+ assert_equal 'message', @match[5]
31
+ end
32
+ end
33
+ end
data/test/test_helper.rb CHANGED
@@ -17,7 +17,7 @@ class DummyLogger
17
17
  end
18
18
  Haproxy2Rpm.logger = DummyLogger.new
19
19
 
20
- def log_entry(options = {})
20
+ def syslog_entry(options = {})
21
21
  defaults = {
22
22
  :tq => 6559,
23
23
  :tw => 100,
@@ -34,3 +34,21 @@ def log_entry(options = {})
34
34
  Aug 1 15:28:03 ip-10-58-122-30.eu-west-1.compute.internal haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 #{defaults[:tq]}/#{defaults[:tw]}/#{defaults[:tc]}/#{defaults[:tr]}/#{defaults[:tt]} #{defaults[:status_code]} 243 - - ---- 1/3/5 0/0 "#{defaults[:http_method]} #{defaults[:http_path]}#{defaults[:http_query] ? "?#{defaults[:http_query]}" : ''} HTTP/1.0"
35
35
  LOG_LINE
36
36
  end
37
+
38
+ def log_entry(options = {})
39
+ defaults = {
40
+ :tq => 6559,
41
+ :tw => 100,
42
+ :tc => 7,
43
+ :tr => 147,
44
+ :tt => 6723,
45
+ :status_code => 200,
46
+ :http_path => '/',
47
+ :http_method => 'GET',
48
+ :http_query => 'example_param=test',
49
+ }
50
+ defaults.merge!(options)
51
+ log_line = <<LOG_LINE
52
+ 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 #{defaults[:tq]}/#{defaults[:tw]}/#{defaults[:tc]}/#{defaults[:tr]}/#{defaults[:tt]} #{defaults[:status_code]} 243 - - ---- 1/3/5 0/0 "#{defaults[:http_method]} #{defaults[:http_path]}#{defaults[:http_query] ? "?#{defaults[:http_query]}" : ''} HTTP/1.0"
53
+ LOG_LINE
54
+ end
metadata CHANGED
@@ -1,81 +1,105 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: haproxy2rpm
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.10
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Patrick Huesler
9
14
  - Martin Rehfeld
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2011-09-02 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2012-01-03 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
16
23
  name: newrelic_rpm
17
- requirement: &70241929478900 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
18
26
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
23
34
  type: :runtime
24
- prerelease: false
25
- version_requirements: *70241929478900
26
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
27
37
  name: eventmachine-tail
28
- requirement: &70241929476180 !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
29
40
  none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
34
48
  type: :runtime
35
- prerelease: false
36
- version_requirements: *70241929476180
37
- - !ruby/object:Gem::Dependency
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
38
51
  name: rake
39
- requirement: &70241929470660 !ruby/object:Gem::Requirement
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
40
54
  none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: '0'
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
45
62
  type: :development
46
- prerelease: false
47
- version_requirements: *70241929470660
48
- - !ruby/object:Gem::Dependency
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
49
65
  name: shoulda-context
50
- requirement: &70241929468160 !ruby/object:Gem::Requirement
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
51
68
  none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0'
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
56
76
  type: :development
57
- prerelease: false
58
- version_requirements: *70241929468160
59
- - !ruby/object:Gem::Dependency
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
60
79
  name: mocha
61
- requirement: &70241929467720 !ruby/object:Gem::Requirement
80
+ prerelease: false
81
+ requirement: &id005 !ruby/object:Gem::Requirement
62
82
  none: false
63
- requirements:
64
- - - ! '>='
65
- - !ruby/object:Gem::Version
66
- version: '0'
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
67
90
  type: :development
68
- prerelease: false
69
- version_requirements: *70241929467720
91
+ version_requirements: *id005
70
92
  description: Sending haproxy logs to new relic rpm
71
- email:
93
+ email:
72
94
  - patrick.huesler@wooga.com
73
95
  - martin.rehfeld@wooga.com
74
- executables:
96
+ executables:
75
97
  - haproxy2rpm
76
98
  extensions: []
99
+
77
100
  extra_rdoc_files: []
78
- files:
101
+
102
+ files:
79
103
  - .gitignore
80
104
  - .travis.yml
81
105
  - CHANGELOG.md
@@ -85,6 +109,8 @@ files:
85
109
  - Research.md
86
110
  - bin/haproxy2rpm
87
111
  - config/newrelic.yml.example
112
+ - examples/connect_middleware.js
113
+ - examples/connect_middleware_config.rb
88
114
  - examples/haproxy2rpm.monitrc
89
115
  - examples/routes.rb
90
116
  - examples/simple_config.rb
@@ -98,33 +124,45 @@ files:
98
124
  - test/fixtures/config.rb
99
125
  - test/haproxy2pm_test.rb
100
126
  - test/rpm_test.rb
127
+ - test/syslog_test.rb
101
128
  - test/test_helper.rb
129
+ has_rdoc: true
102
130
  homepage: https://github.com/wooga/haproxy2rpm
103
131
  licenses: []
132
+
104
133
  post_install_message:
105
134
  rdoc_options: []
106
- require_paths:
135
+
136
+ require_paths:
107
137
  - lib
108
- required_ruby_version: !ruby/object:Gem::Requirement
138
+ required_ruby_version: !ruby/object:Gem::Requirement
109
139
  none: false
110
- requirements:
111
- - - ! '>='
112
- - !ruby/object:Gem::Version
113
- version: '0'
114
- required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ hash: 3
144
+ segments:
145
+ - 0
146
+ version: "0"
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
148
  none: false
116
- requirements:
117
- - - ! '>='
118
- - !ruby/object:Gem::Version
119
- version: '0'
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ hash: 3
153
+ segments:
154
+ - 0
155
+ version: "0"
120
156
  requirements: []
157
+
121
158
  rubyforge_project:
122
- rubygems_version: 1.8.6
159
+ rubygems_version: 1.6.2
123
160
  signing_key:
124
161
  specification_version: 3
125
162
  summary: Sending haproxy logs to new relic rpm
126
- test_files:
163
+ test_files:
127
164
  - test/fixtures/config.rb
128
165
  - test/haproxy2pm_test.rb
129
166
  - test/rpm_test.rb
167
+ - test/syslog_test.rb
130
168
  - test/test_helper.rb