log2mail 0.0.1.pre3 → 0.0.1.pre4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{INSTALL → INSTALL.md} +2 -0
- data/README.md +1 -1
- data/features/log2mail_configurations/config_1 +1 -1
- data/lib/ext/string.rb +6 -0
- data/lib/ext/symbol.rb +7 -0
- data/lib/log2mail.rb +1 -1
- data/lib/log2mail/config.rb +9 -210
- data/lib/log2mail/config/attribute.rb +21 -0
- data/lib/log2mail/config/config.rb +45 -0
- data/lib/log2mail/config/config_file_handler.rb +142 -0
- data/lib/log2mail/config/config_file_snippet.rb +17 -0
- data/lib/log2mail/config/old_config_file_handler.rb +220 -0
- data/lib/log2mail/config/parser.rb +144 -0
- data/lib/log2mail/config/section.rb +70 -0
- data/lib/log2mail/console/commands.rb +1 -1
- data/lib/log2mail/main.rb +2 -2
- data/lib/log2mail/version.rb +1 -1
- data/lib/log2mail/watcher.rb +1 -1
- data/log2mail.gemspec +1 -0
- data/man/log2mail.1 +1 -1
- data/man/log2mail.1.ronn +1 -1
- data/spec/factories.rb +126 -29
- data/spec/log2mail/{config_spec.rb → config/config_file_handler_spec.rb} +49 -3
- data/spec/log2mail/config/parser_spec.rb +467 -0
- data/spec/spec_helper.rb +1 -0
- metadata +29 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdf651d2af53d14c8f36ea64233f8db4116c055d
|
4
|
+
data.tar.gz: 1c35a2f8dc2df19d6635b66d24c279029bcff909
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cba00ca0b65e5f87f434450f44bbef5e17e94fdfb8c144e4f73ce002648425e96ba39f5a2d63ba9c7eac0d82df28ba3e15be46576629a4053818ccfd12d60a13
|
7
|
+
data.tar.gz: 5e640a298954ebf3fae7745f86ea478f9f4ff8f56e0d71bd8284f5ddd8feef13c1e530d2735ef8b8395e9f2a21f99f2c6e417f143adcce5152dd132d396f2889
|
data/{INSTALL → INSTALL.md}
RENAMED
@@ -4,6 +4,7 @@ log2mail.rb Installation
|
|
4
4
|
Requirements
|
5
5
|
------------
|
6
6
|
|
7
|
+
* Linux
|
7
8
|
* Ruby 1.9.3
|
8
9
|
|
9
10
|
Debian 7 (and higher)
|
@@ -25,6 +26,7 @@ Create a configuration file, e.g. at `/usr/local/etc/log2mail.conf`:
|
|
25
26
|
|
26
27
|
cat > /usr/local/etc/log2mail.conf <<EOF
|
27
28
|
defaults
|
29
|
+
sendmail = /usr/sbin/sendmail
|
28
30
|
mailto = your@mail.address
|
29
31
|
file = /tmp/test.log
|
30
32
|
pattern = test
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ log2mail.rb(1) -- monitors (log) files for patterns and reports hits by mail
|
|
9
9
|
|
10
10
|
`log2mail.rb` helps having an eye on your systems' log files. It efficiently monitors multiple files and reports as soon as specified (regular expression) patterns match.
|
11
11
|
|
12
|
-
On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`).
|
12
|
+
On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`). Matched patterns are reported to the configured mail address(es) (see `mailto` configuration option).
|
13
13
|
|
14
14
|
Log files are reopened automatically when rotated.
|
15
15
|
|
data/lib/ext/string.rb
CHANGED
data/lib/ext/symbol.rb
ADDED
data/lib/log2mail.rb
CHANGED
data/lib/log2mail/config.rb
CHANGED
@@ -1,216 +1,15 @@
|
|
1
1
|
module Log2mail
|
2
|
-
|
3
|
-
|
4
|
-
class <<self
|
5
|
-
def parse_config(config_path)
|
6
|
-
Log2mail::Config.new(config_path)
|
7
|
-
# pp config.config
|
8
|
-
# config.files.each do |f|
|
9
|
-
# puts "File: #{f}"
|
10
|
-
# config.patterns_for_file(f).each do |pattern|
|
11
|
-
# puts " Pattern: #{pattern}; mailto: " + config.mailtos_for_pattern( f, pattern ).join(', ')
|
12
|
-
# end
|
13
|
-
# end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# attr_reader :config
|
18
|
-
|
2
|
+
module Config
|
19
3
|
INT_OPTIONS = [:sendtime, :resendtime, :maxlines]
|
20
4
|
STR_OPTIONS = [:fromaddr, :sendmail]
|
21
5
|
PATH_OPTIONS = [:template]
|
22
|
-
|
23
|
-
def initialize(config_paths)
|
24
|
-
$logger.debug "Reading configuration from #{config_paths}"
|
25
|
-
@config_paths = Array(config_paths)
|
26
|
-
expand_paths
|
27
|
-
read_configuration
|
28
|
-
validate_configuration
|
29
|
-
end
|
30
|
-
|
31
|
-
# returns all the paths of all files needed to be watched
|
32
|
-
def files
|
33
|
-
@config.keys - [:defaults]
|
34
|
-
end
|
35
|
-
|
36
|
-
def file_patterns
|
37
|
-
h = {}
|
38
|
-
files.each do |file|
|
39
|
-
h[file] = patterns_for_file(file)
|
40
|
-
end
|
41
|
-
h
|
42
|
-
end
|
43
|
-
|
44
|
-
def patterns_for_file( file )
|
45
|
-
Hash(@config[file][:patterns]).keys + \
|
46
|
-
Hash(defaults[:patterns]).keys
|
47
|
-
end
|
48
|
-
|
49
|
-
def mailtos_for_pattern( file, pattern )
|
50
|
-
m = []
|
51
|
-
m.concat Hash( config_file_pattern(file, pattern)[:mailtos] ).keys
|
52
|
-
m.concat Hash(Hash(Hash(defaults[:patterns])[pattern])[:mailtos]).keys
|
53
|
-
m.concat Array(defaults[:mailtos]) if m.empty?
|
54
|
-
m.uniq
|
55
|
-
end
|
56
|
-
|
57
|
-
def settings_for_mailto( file, pattern, mailto )
|
58
|
-
h = defaults.reject {|k,v| k==:mailtos}
|
59
|
-
h.merge config_file_mailto(file, pattern, mailto)
|
60
|
-
end
|
61
|
-
|
62
|
-
def defaults
|
63
|
-
Hash(@config[:defaults])
|
64
|
-
end
|
65
|
-
|
66
|
-
def formatted( show_effective )
|
67
|
-
Terminal::Table.new do |t|
|
68
|
-
settings_header = show_effective ? 'Effective Settings' : 'Settings'
|
69
|
-
t << ['File', 'Pattern', 'Recipient', settings_header]
|
70
|
-
t << :separator
|
71
|
-
files.each do |file|
|
72
|
-
patterns_for_file(file).each do |pattern|
|
73
|
-
mailtos_for_pattern(file, pattern).each do |mailto|
|
74
|
-
settings = []
|
75
|
-
if show_effective
|
76
|
-
settings_for_mailto(file, pattern, mailto).each_pair \
|
77
|
-
{ |k,v| settings << '%s=%s' % [k,v] }
|
78
|
-
else
|
79
|
-
config_file_mailto(file, pattern, mailto).each_pair \
|
80
|
-
{ |k,v| settings << '%s=%s' % [k,v] }
|
81
|
-
end
|
82
|
-
t.add_row [file, pattern, mailto, settings.join($/)]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def config_file(file)
|
92
|
-
Hash(@config[file])
|
93
|
-
end
|
94
|
-
|
95
|
-
def config_file_pattern(file, pattern)
|
96
|
-
Hash( Hash( config_file(file)[:patterns] )[pattern] )
|
97
|
-
end
|
98
|
-
|
99
|
-
def config_file_mailtos(file, pattern)
|
100
|
-
Hash( config_file_pattern(file, pattern)[:mailtos] )
|
101
|
-
end
|
102
|
-
|
103
|
-
def config_file_mailto(file, pattern, mailto)
|
104
|
-
Hash( config_file_mailtos(file, pattern)[mailto] )
|
105
|
-
end
|
106
|
-
|
107
|
-
def expand_paths
|
108
|
-
expanded_paths = []
|
109
|
-
@config_paths.each do |path|
|
110
|
-
if ::File.directory?(path)
|
111
|
-
expanded_paths.concat Dir.glob( ::File.join( path, '*[^~#]' ) )
|
112
|
-
else
|
113
|
-
expanded_paths << path
|
114
|
-
end
|
115
|
-
end
|
116
|
-
@config_paths = expanded_paths
|
117
|
-
end
|
118
|
-
|
119
|
-
# tries to follow original code at https://github.com/lordlamer/log2mail/blob/master/config.cc#L192
|
120
|
-
def read_configuration
|
121
|
-
@config = {}
|
122
|
-
@config_paths.each do |file|
|
123
|
-
@section = nil; @pattern = nil; @mailto = nil
|
124
|
-
# section, pattern, mailto are reset for every file (but not when included by 'include')
|
125
|
-
parse_file( file )
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def parse_file( filename )
|
130
|
-
IO.readlines(filename).each_with_index do |line, lineno|
|
131
|
-
parse(filename, line, lineno + 1)
|
132
|
-
end
|
133
|
-
rescue Errno::ENOENT
|
134
|
-
fail Error, "Configuration file or directory not found (or not readable): #{filename}"
|
135
|
-
end
|
136
|
-
|
137
|
-
def parse(file, line, lineno)
|
138
|
-
line.strip!
|
139
|
-
return if line =~ /^#/
|
140
|
-
return if line =~ /^$/
|
141
|
-
line =~ /^(\S+)\s*=?\s*"?(.*?)"?(\s*#.*)?$/ # drop double quotes on right hand side; drop comments
|
142
|
-
key, value = $1.to_sym, $2.strip
|
143
|
-
if key == :include # include shall work everywhere
|
144
|
-
parse_file( ::File.join(Pathname(file).parent, value) )
|
145
|
-
return
|
146
|
-
end
|
147
|
-
if key == :defaults and value.empty? # section: specifies top level; must be 'defaults' or 'file'
|
148
|
-
@section = key
|
149
|
-
@pattern = nil; @mailto = nil
|
150
|
-
fail Error, "Invalid section. Section 'defaults' already specified." if @config[@section]
|
151
|
-
@config[@section] = {}
|
152
|
-
elsif key == :file
|
153
|
-
@section = value
|
154
|
-
@pattern = nil; @mailto = nil
|
155
|
-
@config[@section] ||= {}
|
156
|
-
elsif key == :pattern # must come inside 'file' (or 'defaults')
|
157
|
-
# fail "Invalid section. All statements must appear after 'defaults' or 'file=...'" unless @section
|
158
|
-
@pattern = value; @mailto = nil
|
159
|
-
@config[@section][:patterns] ||= {}
|
160
|
-
warning { "Redefining pattern section '#{value}' which has been defined already for '#{@section}'." } \
|
161
|
-
if @config[@section][:patterns][value]
|
162
|
-
@config[@section][:patterns][value] = {}
|
163
|
-
elsif key == :mailto and @section != :defaults # must come inside 'pattern' (or 'defaults')
|
164
|
-
fail Error, "'mailto' statements only allowed inside 'pattern' or 'defaults'." unless @pattern
|
165
|
-
@mailto = value
|
166
|
-
@config[@section][:patterns][@pattern][:mailtos] ||= {}
|
167
|
-
warning { "Redefining mailto section '#{value}' which has been defined already for '#{@section}'." } \
|
168
|
-
if @config[@section][:patterns][@pattern][:mailtos][value]
|
169
|
-
@config[@section][:patterns][@pattern][:mailtos][value] = {}
|
170
|
-
else # everything else must come inside 'defaults' or 'mailto'
|
171
|
-
fail Error, "'#{key}' must be set within 'defaults' or 'mailto'." unless @section == :defaults or @mailto
|
172
|
-
if INT_OPTIONS.include?(key)
|
173
|
-
value = value.to_i
|
174
|
-
elsif STR_OPTIONS.include?(key)
|
175
|
-
elsif PATH_OPTIONS.include?(key)
|
176
|
-
value = ::File.expand_path( value, Pathname(file).parent ) unless Pathname(value).absolute?
|
177
|
-
elsif key == :mailto # special handling for 'mailto' in 'defaults' section
|
178
|
-
@config[:defaults][:mailtos] ||= []
|
179
|
-
@config[:defaults][:mailtos] << value
|
180
|
-
return # skip the 'mailto' entry itself
|
181
|
-
else
|
182
|
-
fail Error, "'#{key}' is an unknown configuration statement."
|
183
|
-
end
|
184
|
-
if @section == :defaults and !@pattern and !@mailto
|
185
|
-
warning { "Redefining value for '#{key}'." } if @config[@section][key]
|
186
|
-
@config[@section][key] = value
|
187
|
-
else
|
188
|
-
warning { "Redefining value for '#{key}'." } \
|
189
|
-
if @config[@section][:patterns][@pattern][:mailtos][@mailto][key]
|
190
|
-
@config[@section][:patterns][@pattern][:mailtos][@mailto][key] = value
|
191
|
-
end
|
192
|
-
end
|
193
|
-
rescue
|
194
|
-
fail Error, "#{file} (line #{lineno}): #{$!.message}#$/[#{$!.class} at #{$!.backtrace.first}]"
|
195
|
-
end
|
196
|
-
|
197
|
-
def validate_configuration
|
198
|
-
files.each do |file|
|
199
|
-
patterns_for_file(file).each do |pattern|
|
200
|
-
mailtos = mailtos_for_pattern(file, pattern)
|
201
|
-
$logger.warn "Pattern #{file}:#{pattern} has no recipients." if mailtos.empty?
|
202
|
-
end
|
203
|
-
end
|
204
|
-
# FIXME: empty configuration should cause FATAL error
|
205
|
-
# TODO: illegal regexp pattern should cause ERROR
|
206
|
-
end
|
207
|
-
|
208
|
-
def warning(&block)
|
209
|
-
file = block.binding.eval('file')
|
210
|
-
lineno = block.binding.eval('lineno')
|
211
|
-
message = block.call
|
212
|
-
$logger.warn "#{file} (line #{lineno}): #{message}#$/[at #{caller.first}]"
|
213
|
-
end
|
214
|
-
|
6
|
+
ATTRIBUTES = INT_OPTIONS + STR_OPTIONS + PATH_OPTIONS
|
215
7
|
end
|
216
8
|
end
|
9
|
+
|
10
|
+
require_relative 'config/config'
|
11
|
+
require_relative 'config/attribute'
|
12
|
+
require_relative 'config/section'
|
13
|
+
require_relative 'config/parser'
|
14
|
+
require_relative 'config/config_file_snippet'
|
15
|
+
require_relative 'config/config_file_handler'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class Attribute
|
4
|
+
attr_reader :name, :value
|
5
|
+
def initialize( name, value )
|
6
|
+
@name = name.to_sym
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
def ==(other)
|
10
|
+
self.name == other.name and self.value == other.value
|
11
|
+
end
|
12
|
+
def inspect
|
13
|
+
'Attribute %s = %s' % [@name.inspect, @value.inspect]
|
14
|
+
end
|
15
|
+
def tree
|
16
|
+
{self.name => self.value}
|
17
|
+
# self.value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class Config
|
4
|
+
attr_reader :sections
|
5
|
+
def initialize( sections = [] )
|
6
|
+
@sections = merge sections
|
7
|
+
end
|
8
|
+
def ==(other)
|
9
|
+
return false unless other.instance_of?(self.class)
|
10
|
+
self.sections == other.sections
|
11
|
+
end
|
12
|
+
def inspect
|
13
|
+
'Config: %s' % [@sections.inspect]
|
14
|
+
end
|
15
|
+
def tree
|
16
|
+
h = {}
|
17
|
+
@sections.inject(h) do |h, a|
|
18
|
+
if a.name==:defaults
|
19
|
+
h[:defaults] = a.tree
|
20
|
+
else
|
21
|
+
a.tree.each_pair {|k,v| ( h[a.name.pluralize.to_sym] ||= {} )[k] = v }
|
22
|
+
end
|
23
|
+
h
|
24
|
+
end
|
25
|
+
h
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# FIXME: needs specing
|
31
|
+
def merge( sections )
|
32
|
+
sections = sections.compact.find_all{ |s| s.respond_to?(:name) }
|
33
|
+
names = sections.map(&:name).uniq
|
34
|
+
names.map do |name|
|
35
|
+
secs_with_same_name = sections.find_all{ |sec| sec.name == name }
|
36
|
+
their_uniq_values = secs_with_same_name.map(&:value).uniq
|
37
|
+
their_uniq_values.map{ |val| secs_with_same_name.find_all{ |s| s.value == val }.reduce(:+) }
|
38
|
+
end.flatten(1)
|
39
|
+
rescue NoMethodError
|
40
|
+
fail "Invalid configuration: #{$!.inspect}"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Log2mail
|
2
|
+
module Config
|
3
|
+
class ConfigFileHandler
|
4
|
+
|
5
|
+
class <<self
|
6
|
+
def parse_config(config_path)
|
7
|
+
new(config_path)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config_paths)
|
12
|
+
$logger.debug "Reading configuration from #{config_paths}"
|
13
|
+
@config_paths = Array(config_paths)
|
14
|
+
expand_paths
|
15
|
+
@config = Parser.new.parse_snippets( raw ).tree
|
16
|
+
validate_configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def expand_paths
|
20
|
+
expanded_paths = []
|
21
|
+
@config_paths.each do |path|
|
22
|
+
if ::File.directory?(path)
|
23
|
+
expanded_paths.concat Dir.glob( ::File.join( path, '*[^~#]' ) )
|
24
|
+
else
|
25
|
+
expanded_paths << path
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@config_paths = expanded_paths
|
29
|
+
end
|
30
|
+
|
31
|
+
def raw
|
32
|
+
@config_paths.map do |file|
|
33
|
+
ConfigFileSnippet.new( IO.read(file), file )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# returns all the paths of all files needed to be watched
|
38
|
+
def files
|
39
|
+
Hash(@config[:files]).keys
|
40
|
+
end
|
41
|
+
|
42
|
+
# FIXME: specs
|
43
|
+
def file_patterns
|
44
|
+
h = {}
|
45
|
+
files.each do |file|
|
46
|
+
h[file] = patterns_for_file(file)
|
47
|
+
end
|
48
|
+
h
|
49
|
+
end
|
50
|
+
|
51
|
+
# returns the default settings
|
52
|
+
def defaults
|
53
|
+
Hash(@config[:defaults])
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns all patterns for file
|
57
|
+
def patterns_for_file( file )
|
58
|
+
Hash(config_file(file)[:patterns]).keys + \
|
59
|
+
Hash(defaults[:patterns]).keys
|
60
|
+
end
|
61
|
+
|
62
|
+
def mailtos_for_pattern( file, pattern )
|
63
|
+
m = []
|
64
|
+
m.concat Hash( config_file_pattern(file, pattern)[:mailtos] ).keys
|
65
|
+
m.concat Hash(Hash(Hash(defaults[:patterns])[pattern])[:mailtos]).keys
|
66
|
+
m.concat Hash(defaults[:mailtos]).keys if m.empty?
|
67
|
+
m.uniq
|
68
|
+
end
|
69
|
+
|
70
|
+
def settings_for_mailto( file, pattern, mailto )
|
71
|
+
h = defaults.reject {|k,v| k==:mailtos}
|
72
|
+
h.merge config_file_mailto(file, pattern, mailto)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
def formatted( show_effective = false )
|
78
|
+
Terminal::Table.new do |t|
|
79
|
+
settings_header = show_effective ? 'Effective Settings' : 'Settings'
|
80
|
+
t << ['File', 'Pattern', 'Recipient', settings_header]
|
81
|
+
t << :separator
|
82
|
+
files.each do |file|
|
83
|
+
patterns_for_file(file).each do |pattern|
|
84
|
+
mailtos_for_pattern(file, pattern).each do |mailto|
|
85
|
+
settings = []
|
86
|
+
if show_effective
|
87
|
+
settings_for_mailto(file, pattern, mailto).each_pair \
|
88
|
+
{ |k,v| settings << '%s=%s' % [k,v] }
|
89
|
+
else
|
90
|
+
config_file_mailto(file, pattern, mailto).each_pair \
|
91
|
+
{ |k,v| settings << '%s=%s' % [k,v] }
|
92
|
+
end
|
93
|
+
t.add_row [file, pattern, mailto, settings.join($/)]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def config_file(file)
|
105
|
+
Hash(Hash(@config[:files])[file])
|
106
|
+
end
|
107
|
+
|
108
|
+
def config_file_pattern(file, pattern)
|
109
|
+
Hash( Hash( config_file(file)[:patterns] )[pattern] )
|
110
|
+
end
|
111
|
+
|
112
|
+
def config_file_mailtos(file, pattern)
|
113
|
+
config_file_pattern(file, pattern)[:mailtos] || {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def config_file_mailto(file, pattern, mailto)
|
117
|
+
config_file_mailtos(file, pattern)[mailto] || {}
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def validate_configuration
|
122
|
+
files.each do |file|
|
123
|
+
patterns_for_file(file).each do |pattern|
|
124
|
+
mailtos = mailtos_for_pattern(file, pattern)
|
125
|
+
$logger.warn "Pattern #{file}:#{pattern} has no recipients." if mailtos.empty?
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
$logger.warn "Attributes for a global default recipient specified. This may or may not be what you want. Consult `gem man log2mail` if unsure." \
|
130
|
+
if !defaults[:mailtos].nil? and defaults[:mailtos].any?{|k,v| !v.empty? }
|
131
|
+
|
132
|
+
$logger.warn "Attributes for a global default pattern specified. This may or may not be what you want. Consult `gem man log2mail` if unsure." \
|
133
|
+
if !defaults[:patterns].nil? and defaults[:patterns].any?{|k,v| !v.empty? }
|
134
|
+
|
135
|
+
# FIXME: empty configuration should cause FATAL error
|
136
|
+
# TODO: illegal regexp pattern should cause ERROR
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|