haproxy2rpm 0.0.2 → 0.0.3

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/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Push haproxy logs to newrelic rpm
2
2
  This is useful for languages where newrelic does not provide an agent,
3
- such as erlang or node.js based applications
3
+ such as erlang or node.js based applications.
4
+
5
+ It runs in syslog mode or tail a log file.
4
6
 
5
7
  ## Installation
6
8
 
@@ -9,26 +11,22 @@ gem install haproxy2rpm or clone it
9
11
  * copy your newrelic.yml file to $HOME/.newrelic/newrelic.yml
10
12
  * or set $NRCONFIG to point to your newrelic.yml file
11
13
 
12
- ## Running it
13
- haproxy2rpm /path/to/logfile or ./bin/haproxy2rpm /path/to/log/file
14
-
15
- ## Analyzing it
16
-
17
- At the moment, it only works with custom views
14
+ Tell haproxy to log to syslog. e.g:
18
15
 
19
- <verbatim>
20
- <h3>Charts</h3>
21
- <table width='100%'>
22
- <tr>
23
- <td>line_chart {% line_chart value:'average_value' title:'Test' metric:'Custom/HAProxy/response_times' %}</td>
24
- </tr>
16
+ # /etc/haproxy/haproxy.cfg
17
+ global
18
+ log 127.0.0.1:3333 daemon
25
19
 
26
- </table>
27
- </verbatim/>
28
-
29
-
30
- ## Roadmap
31
-
32
- * daemonize option
33
- * syslog (udp maybe tcp) server with https://github.com/loggly/logporter and then point HaProxy to that port. Why touch the disk if we don't have to?
34
- * Figure out how to report rpms and response times so that they show up inside the newrelic application view and not only as a custom metric
20
+ ## Running it
21
+ haproxy2rpm /path/to/logfile
22
+ haproxy2rpm --syslog
23
+ haproxy2rpm --syslog --daemonize
24
+
25
+ ## Supported RPM features
26
+
27
+ * Response times in application server
28
+ * Error rate
29
+ * Queue time
30
+ * Apdex
31
+ * Histogram
32
+ * Web transactions
data/Rakefile CHANGED
@@ -11,4 +11,14 @@ namespace :test do
11
11
 
12
12
  t.verbose = true
13
13
  end
14
+
15
+ desc 'send udp log lines for testing purposes'
16
+ task :send_udp_log_lines do
17
+ port = ENV['port'] || 3333
18
+ status_code = ENV['status_code'] || 200
19
+ uri = ENV['uri'] || '/'
20
+ puts 'make sure the udp server is running'
21
+
22
+ `yes '<13>May 19 18:30:17 localhost haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 6559/100/7/147/6723 #{status_code} 243 - - ---- 1/3/5 0/0 "PUT #{uri} HTTP/1.0"' | nc -u -i 1 localhost #{port}`
23
+ end
14
24
  end
data/Research.md ADDED
@@ -0,0 +1,57 @@
1
+ # Agent#record_transaction
2
+ # lib/new_relic/agent.rb
3
+ # NewRelic::Agent.record_transaction( params['value'].to_f, params )
4
+ # lib/new_relic/rack.rb
5
+ # test/rpm_agent_test.rb
6
+ # NewRelic::Agent.record_transaction 0.5, 'uri' => "/users/create?foo=bar"
7
+
8
+ # NewRelic::Agent.record_transaction rand(100) / 100.0, {'metric' => 'Controller/josef'}
9
+ # stat = NewRelic::Agent.agent.stats_engine.get_stats_no_scope 'WebFrontend/QueueTime'
10
+ # stat.record_data_point(0.5)
11
+
12
+ module NewRelic
13
+ module Metrics
14
+ CONTROLLER = "Controller"
15
+ DISPATCHER = "HttpDispatcher"
16
+ ACTIVE_RECORD = "ActiveRecord"
17
+ USER_TIME = "CPU/User Time"
18
+ MEMORY = "Memory/Physical"
19
+ end
20
+ end
21
+
22
+ def record_transaction(duration_seconds, options={})
23
+ is_error = options['is_error'] || options['error_message'] ||
24
+ options['exception']
25
+ metric = options['metric']
26
+ metric ||= options['uri'] # normalize this with url rules
27
+ raise "metric or uri arguments required" unless metric
28
+ metric_info =
29
+ NewRelic::MetricParser::MetricParser.for_metric_named(metric)
30
+
31
+ if metric_info.is_web_transaction?
32
+ NewRelic::Agent::Instrumentation::MetricFrame.record_apdex(metric_info,
33
+ duration_seconds, duration_seconds, is_error)
34
+ histogram.process(duration_seconds)
35
+ end
36
+ metrics = metric_info.summary_metrics
37
+
38
+ metrics << metric
39
+ metrics.each do |name|
40
+ stats = stats_engine.get_stats_no_scope(name)
41
+ stats.record_data_point(duration_seconds)
42
+ end
43
+
44
+ if is_error
45
+ if options['exception']
46
+ e = options['exception']
47
+ elsif options['error_message']
48
+ e = Exception.new options['error_message']
49
+ else
50
+ e = Exception.new 'Unknown Error'
51
+ end
52
+ error_collector.notice_error e, :uri => options['uri'],
53
+ :metric => metric
54
+ end
55
+ # busy time ?
56
+ end
57
+
data/bin/haproxy2rpm CHANGED
@@ -10,23 +10,49 @@ NEW_RELIC_CONFIG_PATH = File.join(ENV['HOME'], '.newrelic', 'newrelic.yml')
10
10
  help = <<HELP
11
11
  haproxy2rpm
12
12
 
13
- Basic Command Line Usage:
14
- haproxy2rpm <haproxy log file to parse>
15
-
16
- Coniguration for newrelic is read from #{NEW_RELIC_CONFIG_PATH}
13
+ Coniguration for newrelic is read from #{NEW_RELIC_CONFIG_PATH}
17
14
  HELP
18
15
 
19
- options = { :daemonize => false, :version => false, :syslog => false }
16
+ options = {
17
+ :daemonize => false,
18
+ :version => false,
19
+ :syslog => false,
20
+ :port => 3333,
21
+ :listen => '0.0.0.0'
22
+ }
20
23
 
21
24
  opts = OptionParser.new do |opts|
22
- opts.banner = help
25
+ # opts.banner = help
23
26
  opts.on("-D", "--daemonize", "Daemonize") do
24
27
  options[:daemonize] = true
25
28
  end
26
29
 
27
30
  opts.on("-s", "--syslog", "Run syslog server") do
28
31
  options[:syslog] = true
29
- end
32
+ end
33
+
34
+ opts.on("-lIP", "--listen IP", "Set IP to listen on") do |ip|
35
+ options[:listen] = ip
36
+ end
37
+
38
+ opts.on("-pPORT", "--port PORT", "Set port to listen on") do |port|
39
+ options[:port] = port
40
+ end
41
+
42
+ opts.on("-nAPP_NAME", "--app_name APP_NAME", "Set application name") do |app_name|
43
+ options[:app_name] = app_name
44
+ end
45
+
46
+ opts.on("-eENVIRONMENT", "--environment ENVIRONMENT", "Set Newrelic agent env") do |env|
47
+ options[:env] = env
48
+ end
49
+
50
+ opts.on_tail("-h", "--help", "Show this message") do
51
+ puts opts.banner
52
+ puts opts
53
+ exit
54
+ end
55
+
30
56
  opts.on("-v", "--version", "Print the version number and exit") do
31
57
  options[:version] = true
32
58
  end
@@ -47,6 +73,7 @@ unless options[:syslog] || File.exists?(log_file)
47
73
  puts 'please proivde a valid path to a haproxy log file'
48
74
  puts ''
49
75
  puts help
76
+ puts opts
50
77
  exit(1)
51
78
  end
52
79
 
data/lib/haproxy2rpm.rb CHANGED
@@ -11,7 +11,7 @@ require "haproxy2rpm/rpm"
11
11
 
12
12
  module Haproxy2Rpm
13
13
  def self.run(log_file, options)
14
- @rpm = Rpm.new
14
+ @rpm = Rpm.new(options)
15
15
  if(options[:daemonize])
16
16
  puts 'daemonizing'
17
17
  run_daemonized(log_file, options)
@@ -28,14 +28,13 @@ module Haproxy2Rpm
28
28
  puts 'stopping new relic agent'
29
29
  NewRelic::Agent.shutdown
30
30
  end
31
-
31
+
32
32
  def self.run_syslog_server(options)
33
- NewRelic::Agent.manual_start
34
33
  EventMachine::run do
35
- EventMachine.start_server("0.0.0.0", 3333, SyslogHandler)
36
- end
34
+ EventMachine::open_datagram_socket(options[:listen], options[:port], SyslogHandler)
35
+ end
37
36
  end
38
-
37
+
39
38
  def self.default_run(log_file,options)
40
39
  EventMachine.run do
41
40
  EventMachine::file_tail(log_file) do |filetail, line|
@@ -69,4 +68,4 @@ module Haproxy2Rpm
69
68
 
70
69
  exit
71
70
  end
72
- end
71
+ end
@@ -36,7 +36,19 @@ module Haproxy2Rpm
36
36
  end
37
37
 
38
38
  def uri
39
- @uri ||= @parts[14]
39
+ @uri ||= URI.parse(@parts[14])
40
+ end
41
+
42
+ def http_path
43
+ uri.path
44
+ end
45
+
46
+ def http_query
47
+ uri.query
48
+ end
49
+
50
+ def is_error?
51
+ status_code >= 500
40
52
  end
41
53
 
42
54
  private
@@ -1,13 +1,23 @@
1
1
  module Haproxy2Rpm
2
2
  class Rpm
3
- def initialize()
4
- NewRelic::Agent.manual_start
3
+ def initialize(options = {})
4
+ agent_options = {}
5
+ agent_options[:app_name] = options[:app_name] if options[:app_name]
6
+ agent_options[:env] = options[:env] if options[:env]
7
+ NewRelic::Agent.manual_start agent_options
5
8
  @stats_engine = NewRelic::Agent.agent.stats_engine
9
+ @qt_stat = @stats_engine.get_stats_no_scope('WebFrontend/QueueTime')
6
10
  end
7
-
11
+
8
12
  def send(line)
9
13
  request = LineParser.new(line)
10
- @stats_engine.get_stats('Custom/HAProxy/response_times',false).record_data_point(request.tr)
14
+ NewRelic::Agent.record_transaction(
15
+ request.tr / 1000.0,
16
+ 'metric' => "Controller#{request.path}",
17
+ 'is_error' => request.is_error?,
18
+ 'error_message' => "#{request.uri} : Status code #{request.status_code}"
19
+ )
20
+ @qt_stat.record_data_point(request.tw / 1000.0)
11
21
  end
12
22
  end
13
- end
23
+ end
@@ -29,22 +29,12 @@ module Haproxy2Rpm
29
29
  end
30
30
 
31
31
  @syslog3164_re = Regexp.new(re)
32
- end # def initialize
32
+ end
33
33
 
34
34
  def receive_data(data)
35
- # In jruby+netty, we probaby should use the DelimiterBasedFrameDecoder
36
- # But for the sake of simplicity, we'll use EM's BufferedTokenizer for
37
- # all implementations.
38
- @buffer.extract(data).each do |line|
39
- receive_line(line.chomp)
40
- end
41
- end # def receive_event
42
-
43
- def receive_line(line)
44
- @count += 1
45
- # Just try matching, don't need to do anything with it for this benchmark.
46
- m = @syslog3164_re.match(line)
35
+ puts data
36
+ m = @syslog3164_re.match(data)
47
37
  @rpm.send(m[:message])
48
38
  end
49
39
  end
50
- end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module Haproxy2Rpm
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -2,11 +2,28 @@ $LOAD_PATH.unshift( File.dirname(__FILE__) )
2
2
 
3
3
  require 'test_helper'
4
4
 
5
+ def log_entry(options = {})
6
+ defaults = {
7
+ :tq => 6559,
8
+ :tw => 100,
9
+ :tc => 7,
10
+ :tr => 147,
11
+ :tt => 6723,
12
+ :status_code => 200,
13
+ :http_path => '/',
14
+ :http_method => 'GET',
15
+ :http_query => 'example_param=test',
16
+ }
17
+ defaults.merge!(options)
18
+ log_line = <<LOG_LINE
19
+ 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"
20
+ LOG_LINE
21
+ end
22
+
5
23
  class Haproxy2RpmTest < Test::Unit::TestCase
6
24
  context 'parsing of haproxy files' do
7
25
  setup do
8
- @line = File.open(File.join(File.dirname(__FILE__), 'fixtures', 'haproxy.log')){|f| f.readlines}.first
9
- @result = Haproxy2Rpm::LineParser.new(@line)
26
+ @result = Haproxy2Rpm::LineParser.new(log_entry)
10
27
  end
11
28
 
12
29
  should 'parse the Tq (total time in ms spent waiting for client)' do
@@ -15,7 +32,7 @@ class Haproxy2RpmTest < Test::Unit::TestCase
15
32
 
16
33
  # this is the time waiting in the global queue
17
34
  should 'parse the Tw (total time in ms spent waiting in queue)' do
18
- assert_equal 0, @result.tw
35
+ assert_equal 100, @result.tw
19
36
  end
20
37
 
21
38
  should 'parse the Tc (total time in ms spent waiting for the connection to the final server' do
@@ -36,11 +53,34 @@ class Haproxy2RpmTest < Test::Unit::TestCase
36
53
  end
37
54
 
38
55
  should 'parse the http method' do
39
- assert_equal 'HEAD', @result.http_method
56
+ assert_equal 'GET', @result.http_method
40
57
  end
41
58
 
42
59
  should 'parse the uri' do
43
- assert_equal '/', @result.uri
60
+ assert_equal '/', @result.http_path
61
+ end
62
+
63
+ should 'parse the GET params' do
64
+ assert_equal 'example_param=test', @result.http_query
65
+ end
66
+ end
67
+
68
+ context 'is_error' do
69
+ should 'return false for redirects' do
70
+ assert !Haproxy2Rpm::LineParser.new(log_entry(:status_code => 302)).is_error?
44
71
  end
72
+
73
+ should 'return false for 200 OK' do
74
+ assert !Haproxy2Rpm::LineParser.new(log_entry(:status_code => 200)).is_error?
75
+ end
76
+
77
+ should 'return false for 404' do
78
+ assert !Haproxy2Rpm::LineParser.new(log_entry(:status_code => 404)).is_error?
79
+ end
80
+
81
+ should 'return for 500 and above' do
82
+ assert Haproxy2Rpm::LineParser.new(log_entry(:status_code => 500)).is_error?
83
+ end
84
+
45
85
  end
46
86
  end
metadata CHANGED
@@ -1,76 +1,74 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: haproxy2rpm
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
4
5
  prerelease:
5
- version: 0.0.2
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Patrick Huesler
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-07-09 00:00:00 +02:00
12
+ date: 2011-07-11 00:00:00.000000000 +02:00
14
13
  default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
17
16
  name: newrelic_rpm
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &2153806900 !ruby/object:Gem::Requirement
20
18
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
25
23
  type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: eventmachine-tail
29
24
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *2153806900
26
+ - !ruby/object:Gem::Dependency
27
+ name: eventmachine-tail
28
+ requirement: &2153806480 !ruby/object:Gem::Requirement
31
29
  none: false
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: "0"
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
36
34
  type: :runtime
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: rake
40
35
  prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
36
+ version_requirements: *2153806480
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ requirement: &2153806060 !ruby/object:Gem::Requirement
42
40
  none: false
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: "0"
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
47
45
  type: :development
48
- version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
50
- name: shoulda-context
51
46
  prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
47
+ version_requirements: *2153806060
48
+ - !ruby/object:Gem::Dependency
49
+ name: shoulda-context
50
+ requirement: &2153805640 !ruby/object:Gem::Requirement
53
51
  none: false
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: "0"
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
58
56
  type: :development
59
- version_requirements: *id004
57
+ prerelease: false
58
+ version_requirements: *2153805640
60
59
  description: Sending haproxy logs to new relic rpm
61
- email:
60
+ email:
62
61
  - patrick.huesler@gmail.com
63
- executables:
62
+ executables:
64
63
  - haproxy2rpm
65
64
  extensions: []
66
-
67
65
  extra_rdoc_files: []
68
-
69
- files:
66
+ files:
70
67
  - .gitignore
71
68
  - Gemfile
72
69
  - README.md
73
70
  - Rakefile
71
+ - Research.md
74
72
  - bin/haproxy2rpm
75
73
  - haproxy2rpm.gemspec
76
74
  - lib/haproxy2rpm.rb
@@ -79,38 +77,33 @@ files:
79
77
  - lib/haproxy2rpm/rpm.rb
80
78
  - lib/haproxy2rpm/syslog.rb
81
79
  - lib/haproxy2rpm/version.rb
82
- - test/fixtures/haproxy.log
83
80
  - test/haproxy2pm_test.rb
84
81
  - test/test_helper.rb
85
82
  has_rdoc: true
86
- homepage: ""
83
+ homepage: ''
87
84
  licenses: []
88
-
89
85
  post_install_message:
90
86
  rdoc_options: []
91
-
92
- require_paths:
87
+ require_paths:
93
88
  - lib
94
- required_ruby_version: !ruby/object:Gem::Requirement
89
+ required_ruby_version: !ruby/object:Gem::Requirement
95
90
  none: false
96
- requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- version: "0"
100
- required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
96
  none: false
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: "0"
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
106
101
  requirements: []
107
-
108
102
  rubyforge_project:
109
103
  rubygems_version: 1.6.2
110
104
  signing_key:
111
105
  specification_version: 3
112
106
  summary: Sending haproxy logs to new relic rpm
113
- test_files:
114
- - test/fixtures/haproxy.log
107
+ test_files:
115
108
  - test/haproxy2pm_test.rb
116
109
  - test/test_helper.rb
@@ -1 +0,0 @@
1
- haproxy[674]: 127.0.0.1:33319 [15/Oct/2003:08:31:57] relais-http Srv1 6559/0/7/147/6723 200 243 - - ---- 1/3/5 0/0 "HEAD / HTTP/1.0"