haproxy_log_parser 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f019630e3a37d631615874f51d00936ade7a58a2
4
- data.tar.gz: c95c16a28cfc263e3b5f5b3310836b4afbf30094
3
+ metadata.gz: bdee7790396094ba841e7a79fda38388fddd31a6
4
+ data.tar.gz: 77f1cfd3fbe289140fe605dc8092ac38def83fb0
5
5
  SHA512:
6
- metadata.gz: 1d9567c587f66a274e8fa1d829e59c42cb07969094061c0fe5cde805ca322114880c71d62ff18a88f9494f779fc04d4f132105d425d5c22aff3de6e8b95bfef8
7
- data.tar.gz: 5d1d021bef436b3651e362a89ca555c1b3a8e3912bec57030a1bd3c76ad54d93f5fd5560df38460f9181bd36d232084e9020d28e254e0b319436735605d7d98b
6
+ metadata.gz: 92830fae50828e5422a120884f24c7ce5c64c2e8904fd3c6f3846e1e3d5224e028b89243abffe28913ed78773a70cbd4c68816efdbac8b794078ea408ffa50a1
7
+ data.tar.gz: 64254fac5285600842b6dd81b480f3ad5e8428558e7d92ef231b2b5ef4c0ad9e41e91c9b67196b65980242b880235e7dbb4fb4fbfe730257fc8056000f48b1c1
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ haproxy_log_parser-*.gem
2
+ /.bundle
3
+ /Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # haproxy\_log\_parser
2
2
 
3
3
  haproxy\_log\_parser is a gem that parses logs in HAProxy's HTTP log format.
4
+ Use `HAProxyLogParser.parse` to parse a line; this will return an
5
+ `HAProxyLogParser::Entry` for normal lines and `HAProxyLogParser::ErrorEntry`
6
+ for connection error lines.
4
7
 
5
8
  Example:
6
9
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 2.0.0
@@ -11,11 +11,6 @@ Gem::Specification.new do |s|
11
11
 
12
12
  s.add_development_dependency 'rspec', '~> 3.5.0'
13
13
 
14
- s.files = Dir.glob('lib/**/*') + [
15
- 'LICENSE',
16
- 'README.md',
17
- 'VERSION',
18
- 'haproxy_log_parser.gemspec'
19
- ]
20
- s.test_files = Dir.glob('spec/**/*')
14
+ s.files = `git ls-files`.split($/)
15
+ s.test_files = s.files.grep(%r{\Aspec/})
21
16
  end
@@ -0,0 +1,24 @@
1
+ module HAProxyLogParser
2
+ # An instance of this class represents a connection error line of an HAProxy
3
+ # log. See the "Logging > Log formats > Error log format" section in
4
+ # HAProxy's configuration.txt for documentation of fields.
5
+ class ErrorEntry
6
+ # @return [String]
7
+ attr_accessor :client_ip
8
+
9
+ # @return [Integer]
10
+ attr_accessor :client_port
11
+
12
+ # @return [Time]
13
+ attr_accessor :accept_date
14
+
15
+ # @return [String]
16
+ attr_accessor :frontend_name
17
+
18
+ # @return [String]
19
+ attr_accessor :bind_name
20
+
21
+ # @return [String]
22
+ attr_accessor :message
23
+ end
24
+ end
@@ -4,6 +4,11 @@ module HAProxyLogParser
4
4
  syslog_portion:([^\[]+ '[' integer ']: ')
5
5
  client_ip:ip4_address ':' client_port:integer ' '
6
6
  '[' accept_date '] '
7
+ suffix:(normal_suffix / error_suffix)
8
+ "\n"?
9
+ end
10
+
11
+ rule normal_suffix
7
12
  frontend_name:proxy_name transport_mode:'~'? ' '
8
13
  backend_name:proxy_name '/' server_name ' '
9
14
  tq:integer '/' tw:integer '/' tc:integer '/' tr:integer '/' tt:integer ' '
@@ -18,7 +23,11 @@ module HAProxyLogParser
18
23
  captured_request_headers:('{' headers:captured_headers '} ')?
19
24
  captured_response_headers:('{' headers:captured_headers '} ')?
20
25
  '"' http_request:[^"]+ '"'
21
- "\n"?
26
+ end
27
+
28
+ rule error_suffix
29
+ frontend_name:proxy_name '/' bind_name ': '
30
+ message:[^\n]+
22
31
  end
23
32
 
24
33
  rule integer
@@ -52,5 +61,9 @@ module HAProxyLogParser
52
61
  rule captured_headers
53
62
  [^}]*
54
63
  end
64
+
65
+ rule bind_name
66
+ [-_A-Za-z0-9.]+
67
+ end
55
68
  end
56
69
  end
@@ -1,6 +1,7 @@
1
1
  require 'treetop'
2
2
 
3
3
  require 'haproxy_log_parser/entry'
4
+ require 'haproxy_log_parser/error_entry'
4
5
  require 'haproxy_log_parser/line'
5
6
 
6
7
  module HAProxyLogParser
@@ -10,11 +11,11 @@ module HAProxyLogParser
10
11
  class ParseError < ::StandardError; end
11
12
 
12
13
  class << self
13
- # Returns an Entry object resulting from the given HAProxy HTTP-format log
14
- # +line+.
14
+ # Returns an Entry or ErrorEntry object resulting from the given HAProxy
15
+ # HTTP-format log +line+.
15
16
  #
16
17
  # @param line [String] a line from an HAProxy log
17
- # @return [Entry]
18
+ # @return [Entry, ErrorEntry]
18
19
  # @raise [ParseError] if the line was not parsed successfully
19
20
  def parse(line)
20
21
  parser = LineParser.new
@@ -24,39 +25,15 @@ module HAProxyLogParser
24
25
  raise ParseError, parser.failure_reason
25
26
  end
26
27
 
27
- entry = Entry.new
28
- [
29
- :client_ip, :frontend_name, :transport_mode,
30
- :backend_name, :server_name, :termination_state
31
- ].each do |field|
32
- entry.send("#{field}=", result.send(field).text_value)
33
- end
34
- [
35
- :client_port, :tq, :tw, :tc, :tr, :tt, :status_code, :bytes_read,
36
- :actconn, :feconn, :beconn, :srv_conn, :retries, :srv_queue,
37
- :backend_queue
38
- ].each do |field|
39
- entry.send("#{field}=", result.send(field).text_value.to_i)
40
- end
41
-
42
- entry.accept_date = parse_accept_date(result.accept_date.text_value)
43
- [:captured_request_cookie, :captured_response_cookie].each do |field|
44
- cookie = decode_captured_cookie(result.send(field).text_value)
45
- entry.send("#{field}=", cookie)
46
- end
47
-
48
- [:captured_request_headers, :captured_response_headers].each do |field|
49
- if result.send(field).respond_to?(:headers)
50
- headers = decode_captured_headers(
51
- result.send(field).headers.text_value
52
- )
28
+ entry =
29
+ if result.suffix.respond_to?(:http_request)
30
+ create_normal_entry(result.suffix)
53
31
  else
54
- headers = []
32
+ create_error_entry(result.suffix)
55
33
  end
56
- entry.send("#{field}=", headers)
57
- end
58
-
59
- entry.http_request = unescape(result.http_request.text_value)
34
+ entry.client_ip = result.client_ip.text_value
35
+ entry.client_port = result.client_port.text_value.to_i
36
+ entry.accept_date = parse_accept_date(result.accept_date.text_value)
60
37
 
61
38
  entry
62
39
  end
@@ -103,5 +80,58 @@ module HAProxyLogParser
103
80
  def decode_captured_headers(string)
104
81
  string.split('|', -1).map! { |header| unescape(header) }
105
82
  end
83
+
84
+ private
85
+
86
+ # @param result [Treetop::Runtime::SyntaxNode]
87
+ # @return [Entry]
88
+ def create_normal_entry(result)
89
+ entry = Entry.new
90
+
91
+ %i(
92
+ frontend_name transport_mode
93
+ backend_name server_name termination_state
94
+ ).each do |field|
95
+ entry.send("#{field}=", result.send(field).text_value)
96
+ end
97
+
98
+ %i(
99
+ tq tw tc tr tt status_code bytes_read
100
+ actconn feconn beconn srv_conn retries srv_queue backend_queue
101
+ ).each do |field|
102
+ entry.send("#{field}=", result.send(field).text_value.to_i)
103
+ end
104
+
105
+ %i(captured_request_cookie captured_response_cookie).each do |field|
106
+ cookie = decode_captured_cookie(result.send(field).text_value)
107
+ entry.send("#{field}=", cookie)
108
+ end
109
+
110
+ %i(captured_request_headers captured_response_headers).each do |field|
111
+ if result.send(field).respond_to?(:headers)
112
+ headers = decode_captured_headers(
113
+ result.send(field).headers.text_value
114
+ )
115
+ else
116
+ headers = []
117
+ end
118
+ entry.send("#{field}=", headers)
119
+ end
120
+
121
+ entry.http_request = unescape(result.http_request.text_value)
122
+ entry
123
+ end
124
+
125
+ # @param result [Treetop::Runtime::SyntaxNode]
126
+ # @return [ErrorEntry]
127
+ def create_error_entry(result)
128
+ entry = ErrorEntry.new
129
+
130
+ %i(frontend_name bind_name message).each do |field|
131
+ entry.send("#{field}=", result.send(field).text_value)
132
+ end
133
+
134
+ entry
135
+ end
106
136
  end
107
137
  end
@@ -1,12 +1,14 @@
1
1
  require 'haproxy_log_parser'
2
2
 
3
3
  RSpec.describe HAProxyLogParser do
4
- # TODO Use something better instead of LINES[0], LINES[1], ...
5
- LINES = IO.readlines(File.join(File.dirname(__FILE__), 'sample.log'))
4
+ LINES = Hash[
5
+ IO.readlines(File.join(File.dirname(__FILE__), 'sample.log')).
6
+ map { |line| line.split(',', 2) }
7
+ ]
6
8
 
7
9
  describe '.parse' do
8
- it 'parses LINE[0] correctly' do
9
- entry = HAProxyLogParser.parse(LINES[0])
10
+ it 'parses the good1 case correctly' do
11
+ entry = HAProxyLogParser.parse(LINES['good1'])
10
12
  expect(entry.client_ip).to eq('10.0.8.2')
11
13
  expect(entry.client_port).to eq(34028)
12
14
  expect(entry.accept_date).to eq(Time.local(2011, 8, 9, 20, 30, 46, 429))
@@ -36,8 +38,8 @@ RSpec.describe HAProxyLogParser do
36
38
  expect(entry.http_request).to eq('GET / HTTP/1.1')
37
39
  end
38
40
 
39
- it 'parses LINES[1] correctly' do
40
- entry = HAProxyLogParser.parse(LINES[1])
41
+ it 'parses the good2 case correctly' do
42
+ entry = HAProxyLogParser.parse(LINES['good2'])
41
43
  expect(entry.client_ip).to eq('192.168.1.215')
42
44
  expect(entry.client_port).to eq(50679)
43
45
  expect(entry.accept_date).to eq(Time.local(2012, 5, 21, 1, 35, 46, 146))
@@ -67,6 +69,16 @@ RSpec.describe HAProxyLogParser do
67
69
  expect(entry.http_request).to eq('GET /images/image.gif HTTP/1.1')
68
70
  end
69
71
 
72
+ it 'parses connection error lines correctly' do
73
+ entry = HAProxyLogParser.parse(LINES['error1'])
74
+ expect(entry.client_ip).to eq('127.0.0.1')
75
+ expect(entry.client_port).to eq(56059)
76
+ expect(entry.accept_date).to eq(Time.local(2012, 12, 3, 17, 35, 10, 380))
77
+ expect(entry.frontend_name).to eq('frt')
78
+ expect(entry.bind_name).to eq('f1')
79
+ expect(entry.message).to eq('Connection error during SSL handshake')
80
+ end
81
+
70
82
  it 'raises ParseError if the line is invalid' do
71
83
  line = 'Aug 9 20:30:46 localhost haproxy[2022]: '
72
84
  expect { HAProxyLogParser.parse(line) }.
data/spec/sample.log CHANGED
@@ -1,2 +1,3 @@
1
- Aug 9 20:30:46 localhost haproxy[2022]: 10.0.8.2:34028 [09/Aug/2011:20:30:46.429] proxy-out~ proxy-out/cache1 1/0/2/126/+128 301 +223 - - LR-- 617/523/336/168/0 0/0 {www.sytadin.equipement.gouv.fr||http://trafic.1wt.eu/} {Apache|230|||http://www.sytadin.} "GET / HTTP/1.1"
2
- May 21 01:35:46 10.18.237.5 haproxy[26747]: 192.168.1.215:50679 [21/May/2012:01:35:46.146] webapp webapp_backend/web09 27/0/1/0/217 200 1367 session=abc session=xyz ---- 600/529/336/158/0 0/0 {#7C#7C #7B5F41#7D|http://google.com/|} "GET /images/image.gif HTTP/1.1"
1
+ good1,Aug 9 20:30:46 localhost haproxy[2022]: 10.0.8.2:34028 [09/Aug/2011:20:30:46.429] proxy-out~ proxy-out/cache1 1/0/2/126/+128 301 +223 - - LR-- 617/523/336/168/0 0/0 {www.sytadin.equipement.gouv.fr||http://trafic.1wt.eu/} {Apache|230|||http://www.sytadin.} "GET / HTTP/1.1"
2
+ good2,May 21 01:35:46 10.18.237.5 haproxy[26747]: 192.168.1.215:50679 [21/May/2012:01:35:46.146] webapp webapp_backend/web09 27/0/1/0/217 200 1367 session=abc session=xyz ---- 600/529/336/158/0 0/0 {#7C#7C #7B5F41#7D|http://google.com/|} "GET /images/image.gif HTTP/1.1"
3
+ error1,Dec 3 18:27:14 localhost haproxy[6103]: 127.0.0.1:56059 [03/Dec/2012:17:35:10.380] frt/f1: Connection error during SSL handshake
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haproxy_log_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toby Hsieh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-03 00:00:00.000000000 Z
11
+ date: 2017-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
@@ -44,12 +44,15 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - ".gitignore"
48
+ - Gemfile
47
49
  - LICENSE
48
50
  - README.md
49
51
  - VERSION
50
52
  - haproxy_log_parser.gemspec
51
53
  - lib/haproxy_log_parser.rb
52
54
  - lib/haproxy_log_parser/entry.rb
55
+ - lib/haproxy_log_parser/error_entry.rb
53
56
  - lib/haproxy_log_parser/line.treetop
54
57
  - spec/haproxy_log_parser_spec.rb
55
58
  - spec/sample.log
@@ -73,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
76
  version: '0'
74
77
  requirements: []
75
78
  rubyforge_project:
76
- rubygems_version: 2.5.1
79
+ rubygems_version: 2.6.8
77
80
  signing_key:
78
81
  specification_version: 4
79
82
  summary: Parser for HAProxy logs in the HTTP log format