logfile_interval 2.1.5 → 2.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d2744d333999683078bcd1e6251df9f4a77592ba
4
- data.tar.gz: 39977126f145556de0e49a5bcd75fae80c862dc3
3
+ metadata.gz: c7f2e7cabde319d9e316d67b25f41786d30a3a65
4
+ data.tar.gz: 31af6fa687dbd9368e13faa64154ce778d27f3a2
5
5
  SHA512:
6
- metadata.gz: 9e23e0e91fb21f9fb39e40fc9ca002fbafec454914de10f98951f42b39c9c8e19339d8db508ae86d6489c4aff810f118952af673b1e5cd799f8783c44bb82cf9
7
- data.tar.gz: f3e73d0ddd1d07611bfe8476a823dcc5eed323d866404ee782f10afc217389e96f5b7ec8109c4781a11dbb06b888f2d4ebda9050cbf82f0c8a89c000399c6d4e
6
+ metadata.gz: bafa4a0527c1c2b33479ce61276830c39ca588648c95a22e39660e3c26ec410dcdeaf9c47453902619347e6f7b15dcdb40d0dfb8ef8a6fb8e2584882a3b77ffc
7
+ data.tar.gz: 0dcafb906ba7c9ad3e2e88733858e8e54cfa9a54ae8e9f94a3e3acc6d4a14b87c4193541d1af98620bdac73ebd2ad3721815b56fa4ecf282e6bcb93d46be1855
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
3
  - 2.0.0
5
4
  - 2.1.2
5
+ - 2.4.3
6
+ - 2.5.0
6
7
  script: bundle exec rspec spec
data/README.md CHANGED
@@ -33,6 +33,8 @@ class AccessLog < LogfileInterval::ParsedLine::Base
33
33
  add_column :name => 'code', :pos => 4, :aggregator => :count
34
34
  add_column :name => 'code_by_ip', :pos => 4, :aggregator => :count, :group_by => 'ip'
35
35
 
36
+ skip :pos => 3, :regex => /firefox/
37
+
36
38
  def time
37
39
  DateTime.strptime(self.timestamp, '%d/%b/%Y:%H:%M:%S %z').to_time
38
40
  end
@@ -97,6 +99,8 @@ class AccessLog < LogfileInterval::ParsedLine::Base
97
99
  add_column :name => 'length', :pos => 5, :aggregator => :average, :conversion => :integer
98
100
  add_column :name => 'length_by_ip', :pos => 5, :aggregator => :average, :group_by => 'ip', :conversion => :integer
99
101
 
102
+ skip :pos => 3, :regex => /firefox/
103
+
100
104
  def time
101
105
  Time.strptime(self.timestamp, '%d/%b/%Y:%H:%M:%S %z')
102
106
  end
@@ -105,6 +109,7 @@ end
105
109
  #### The parser must define:
106
110
  * A regex that extracts the fields out of each line.
107
111
  * A set of columns that will to be parsed and aggregated in time intervals.
112
+ * 0 or more column that will be skipped if the column value matches the specified regex
108
113
  * A 'time' method that converts the mandatory timestamp field of a line into a Time object.
109
114
 
110
115
  #### Attributes of a column:
@@ -18,9 +18,9 @@ class AccessLogParsedLine < LogfileInterval::ParsedLine::Base
18
18
 
19
19
  add_column :name => 'ip', :pos => 1, :aggregator => :count
20
20
  add_column :name => 'timestamp', :pos => 2, :aggregator => :timestamp
21
- add_column :name => 'code_by_ip', :pos => 4, :aggregator => :count, :group_by => 'ip'
22
- add_column :name => 'length', :pos => 5, :aggregator => :average, :conversion => :integer
23
- add_column :name => 'length_by_ip', :pos => 5, :aggregator => :average, :group_by => 'ip', :conversion => :integer
21
+ add_column :name => 'code_by_ip', :pos => 4, :aggregator => :count, :group_by => :ip
22
+ add_column :name => 'length', :pos => 5, :aggregator => :average, :conversion => :integer
23
+ add_column :name => 'length_by_ip', :pos => 5, :aggregator => :average, :group_by => :ip, :conversion => :integer
24
24
  add_column :name => 'referer', :pos => 6, :aggregator => :count
25
25
  add_column :name => 'referer_by_ip', :pos => 6, :aggregator => :count, :group_by => :ip
26
26
 
@@ -40,4 +40,3 @@ builder.each_interval do |interval|
40
40
  pp interval[:referer_by_ip]
41
41
  STDIN.gets
42
42
  end
43
-
@@ -12,6 +12,8 @@ module LogfileInterval
12
12
  def add(record)
13
13
  @parser_columns.each do |name, options|
14
14
  next unless @aggregators[name]
15
+ next unless options[:noskip] || !record.skip_with_exceptions?
16
+
15
17
  group_by_value = record[options[:group_by]] if options[:group_by]
16
18
  @aggregators[name].add(record[name], group_by_value)
17
19
  end
@@ -20,9 +20,8 @@ module LogfileInterval
20
20
 
21
21
  case order
22
22
  when :asc then self.extend Ascending
23
- when :desc then self.extend Descending
24
- when :empty then nil
25
- else raise ArgumentError, "Can't determine parsed_lines_enum sort order"
23
+ else
24
+ self.extend Descending
26
25
  end
27
26
  end
28
27
 
@@ -43,7 +43,7 @@ module LogfileInterval
43
43
  return enum_for(:each_parsed_line) unless block_given?
44
44
  each_line do |line|
45
45
  record = parser.create_record(line)
46
- yield record if record
46
+ yield record if record && !record.skip?
47
47
  end
48
48
  end
49
49
  alias_method :each, :each_parsed_line
@@ -10,12 +10,22 @@ module LogfileInterval
10
10
  def initialize(line)
11
11
  @data = self.class.parse(line)
12
12
  @valid = @data ? true : false
13
+ @skip = @data ? @data[:skip] : false
14
+ @skip_with_exceptions = @data ? @data[:skip_with_exceptions] : false
13
15
  end
14
16
 
15
17
  def valid?
16
18
  @valid
17
19
  end
18
20
 
21
+ def skip?
22
+ @skip
23
+ end
24
+
25
+ def skip_with_exceptions?
26
+ @skip_with_exceptions
27
+ end
28
+
19
29
  def time
20
30
  raise NotImplemented
21
31
  end
@@ -26,6 +36,3 @@ module LogfileInterval
26
36
  end
27
37
  end
28
38
  end
29
-
30
-
31
-
@@ -3,95 +3,132 @@ module LogfileInterval
3
3
  class ConfigurationError < StandardError; end
4
4
 
5
5
  module Parser
6
- attr_reader :regex
7
- def columns
8
- @columns ||= {}
9
- end
10
-
11
- def set_regex(regex)
12
- @regex = regex
13
- end
6
+ attr_reader :regex
14
7
 
15
- def add_column(options)
16
- validate_column_options(options)
17
- options = sanitize_column_options(options)
8
+ def columns
9
+ @columns ||= {}
10
+ end
18
11
 
19
- name = options[:name]
20
- columns[name] = options
12
+ def skip_columns
13
+ @skip_columns ||= []
14
+ end
21
15
 
22
- define_method(name) do
23
- @data[name]
24
- end
25
- end
16
+ def skip_columns_with_exceptions
17
+ @skip_columns_with_exceptions ||= []
18
+ end
26
19
 
27
- def parse(line)
28
- raise ConfigurationError, 'There must be at least 1 configured column' unless columns.any?
29
- raise ConfigurationError, 'A regex must be set' unless regex
20
+ def set_regex(regex)
21
+ @regex = regex
22
+ end
30
23
 
31
- match_data = regex.match(line)
32
- return nil unless match_data
24
+ def add_column(options)
25
+ validate_column_options(options)
26
+ options = sanitize_column_options(options)
33
27
 
34
- data = {}
35
- columns.each do |name, options|
36
- val = match_data[options[:pos]]
37
- data[name] = convert(val, options[:conversion])
38
- end
39
- data
40
- end
28
+ name = options[:name]
29
+ columns[name] = options
41
30
 
42
- def create_record(line)
43
- record = new(line)
44
- return record if record.valid?
45
- return nil
31
+ define_method(name) do
32
+ @data[name]
46
33
  end
34
+ end
47
35
 
48
- def set_column_custom_options(column_name, options)
49
- raise ArgumentError, "Invalid column name: #{column_name}" unless columns.has_key?(column_name)
50
- columns[column_name][:custom_options] = options
36
+ def skip(options)
37
+ unless options[:pos] && options[:regex]
38
+ raise ConfigurationError, "skip option must include pos and regex"
51
39
  end
52
40
 
41
+ skip_columns << { pos: options[:pos], regex: options[:regex] }
42
+ end
53
43
 
54
- def each(&block)
55
- columns.each(&block)
44
+ def skip_with_exceptions(options)
45
+ unless options[:pos] && options[:regex]
46
+ raise ConfigurationError, "skip option must include pos and regex"
56
47
  end
57
48
 
58
- private
49
+ skip_columns_with_exceptions << { pos: options[:pos], regex: options[:regex] }
50
+ end
59
51
 
60
- def validate_column_options(options)
61
- validate_option(options, :name)
62
- validate_option(options, :pos)
63
- validate_option(options, :aggregator)
64
- unless Aggregator::Base.exist?(options[:aggregator]) || options[:aggregator] == :timestamp
65
- raise ConfigurationError, "aggregator must be one of #{Aggregator::Base.all.join(', ')}"
66
- end
67
- end
52
+ def parse(line)
53
+ raise ConfigurationError, 'There must be at least 1 configured column' unless columns.any?
54
+ raise ConfigurationError, 'A regex must be set' unless regex
55
+
56
+ match_data = regex.match(line)
57
+ return nil unless match_data
68
58
 
69
- def validate_option(options, key, errmsg = nil)
70
- raise ConfigurationError, errmsg || "#{key} is a mandatory column option" unless options.has_key?(key)
59
+ data = { skip: false }
60
+ columns.each do |name, options|
61
+ val = match_data[options[:pos]]
62
+ data[name] = convert(val, options[:conversion])
71
63
  end
72
64
 
73
- def sanitize_column_options(options)
74
- options[:name] = options[:name].to_sym
75
- if options.has_key?(:group_by)
76
- if options[:group_by].to_sym != options[:name]
77
- options[:group_by] = options[:group_by].to_sym
78
- else
79
- options.delete(:group_by)
80
- end
65
+ skip_columns.each do |options|
66
+ val = match_data[options[:pos]]
67
+ if val =~ options[:regex]
68
+ data[:skip] = true
69
+ break
81
70
  end
82
- options[:conversion] = options.fetch(:conversion, :string)
83
- options[:aggregator_class] = Aggregator::Base.klass(options[:aggregator])
84
- options.delete(:aggregator)
85
- options
86
71
  end
87
72
 
88
- def convert(val, conversion)
89
- case conversion
90
- when :integer then val.to_i
91
- when :float then val.to_f
92
- else val
73
+ data
74
+ end
75
+
76
+ def create_record(line)
77
+ record = new(line)
78
+ return record if record.valid?
79
+ return nil
80
+ end
81
+
82
+ def set_column_custom_options(column_name, options)
83
+ raise ArgumentError, "Invalid column name: #{column_name}" unless columns.has_key?(column_name)
84
+ columns[column_name][:custom_options] = options
85
+ end
86
+
87
+
88
+ def each(&block)
89
+ columns.each(&block)
90
+ end
91
+
92
+ private
93
+
94
+ def validate_column_options(options)
95
+ validate_option(options, :name)
96
+ validate_option(options, :pos)
97
+ validate_option(options, :aggregator)
98
+ if options[:name].to_s == 'skip'
99
+ raise ConfigurationError, "'skip' is a reserved column name"
100
+ end
101
+ unless Aggregator::Base.exist?(options[:aggregator]) || options[:aggregator] == :timestamp
102
+ raise ConfigurationError, "aggregator must be one of #{Aggregator::Base.all.join(', ')}"
103
+ end
104
+ end
105
+
106
+ def validate_option(options, key, errmsg = nil)
107
+ raise ConfigurationError, errmsg || "#{key} is a mandatory column option" unless options.has_key?(key)
108
+ end
109
+
110
+ def sanitize_column_options(options)
111
+ options[:name] = options[:name].to_sym
112
+ if options.has_key?(:group_by)
113
+ if options[:group_by].to_sym != options[:name]
114
+ options[:group_by] = options[:group_by].to_sym
115
+ else
116
+ options.delete(:group_by)
93
117
  end
94
118
  end
119
+ options[:conversion] = options.fetch(:conversion, :string)
120
+ options[:aggregator_class] = Aggregator::Base.klass(options[:aggregator])
121
+ options.delete(:aggregator)
122
+ options
123
+ end
124
+
125
+ def convert(val, conversion)
126
+ case conversion
127
+ when :integer then val.to_i
128
+ when :float then val.to_f
129
+ else val
130
+ end
131
+ end
95
132
  end
96
133
  end
97
134
  end
@@ -1,3 +1,3 @@
1
1
  module LogfileInterval
2
- VERSION = "2.1.5"
2
+ VERSION = "2.2.1"
3
3
  end
@@ -78,6 +78,15 @@ module LogfileInterval
78
78
  records.last.length_by_ip.should == 185
79
79
  end
80
80
 
81
+ it 'skips lines matching skip options' do
82
+ records = []
83
+ @alf.each_parsed_line do |record|
84
+ records << record
85
+ end
86
+
87
+ records.size.should == 6
88
+ end
89
+
81
90
  context 'without a block' do
82
91
  it 'should return an enumerator' do
83
92
  e = @alf.each_parsed_line
@@ -15,6 +15,8 @@ module LogfileInterval
15
15
  add_column :name => 'length', :pos => 5, :aggregator => :average, :conversion => :integer
16
16
  add_column :name => 'length_by_ip', :pos => 5, :aggregator => :average, :conversion => :integer, :group_by => 'ip'
17
17
 
18
+ skip :pos => 7, :regex => /Spinn3r/
19
+
18
20
  def time
19
21
  Time.strptime(self.timestamp, '%d/%b/%Y:%H:%M:%S %z')
20
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logfile_interval
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.5
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philippe Le Rohellec
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-12 00:00:00.000000000 Z
11
+ date: 2018-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
164
  version: '0'
165
165
  requirements: []
166
166
  rubyforge_project:
167
- rubygems_version: 2.4.5
167
+ rubygems_version: 2.6.13
168
168
  signing_key:
169
169
  specification_version: 4
170
170
  summary: Aggregate logfile data into intervals