line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Search::ESsearcher; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
67359
|
use 5.006; |
|
1
|
|
|
|
|
4
|
|
4
|
1
|
|
|
1
|
|
6
|
use base Error::Helper; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
504
|
|
5
|
1
|
|
|
1
|
|
812
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
6
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
7
|
1
|
|
|
1
|
|
767
|
use Getopt::Long; |
|
1
|
|
|
|
|
12883
|
|
|
1
|
|
|
|
|
6
|
|
8
|
1
|
|
|
1
|
|
818
|
use JSON; |
|
1
|
|
|
|
|
10475
|
|
|
1
|
|
|
|
|
5
|
|
9
|
1
|
|
|
1
|
|
620
|
use Template; |
|
1
|
|
|
|
|
19579
|
|
|
1
|
|
|
|
|
34
|
|
10
|
1
|
|
|
1
|
|
506
|
use Search::Elasticsearch; |
|
1
|
|
|
|
|
58799
|
|
|
1
|
|
|
|
|
35
|
|
11
|
1
|
|
|
1
|
|
1436
|
use Term::ANSIColor; |
|
1
|
|
|
|
|
8521
|
|
|
1
|
|
|
|
|
67
|
|
12
|
1
|
|
|
1
|
|
566
|
use Time::ParseDate; |
|
1
|
|
|
|
|
11180
|
|
|
1
|
|
|
|
|
4158
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Search::ESsearcher - Provides a handy system for doing templated elasticsearch searches. |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 VERSION |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
Version 0.4.4 |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=cut |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our $VERSION = '0.4.4'; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Search::ESsearcher; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $ess = Search::ESsearcher->new(); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 METHODS |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head2 new |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
This initiates the object. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
my $ss=Search::ESsearcher->new; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=cut |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub new{ |
44
|
|
|
|
|
|
|
|
45
|
0
|
|
|
0
|
1
|
|
my $self = { |
46
|
|
|
|
|
|
|
perror=>undef, |
47
|
|
|
|
|
|
|
error=>undef, |
48
|
|
|
|
|
|
|
errorString=>"", |
49
|
|
|
|
|
|
|
base=>undef, |
50
|
|
|
|
|
|
|
search=>'syslog', |
51
|
|
|
|
|
|
|
search_template=>undef, |
52
|
|
|
|
|
|
|
search_filled_in=>undef, |
53
|
|
|
|
|
|
|
search_usable=>undef, |
54
|
|
|
|
|
|
|
output=>'syslog', |
55
|
|
|
|
|
|
|
output_template=>undef, |
56
|
|
|
|
|
|
|
options=>'syslog', |
57
|
|
|
|
|
|
|
options_array=>undef, |
58
|
|
|
|
|
|
|
elastic=>'default', |
59
|
|
|
|
|
|
|
elastic_hash=>{ |
60
|
|
|
|
|
|
|
nodes => [ |
61
|
|
|
|
|
|
|
'127.0.0.1:9200' |
62
|
|
|
|
|
|
|
] |
63
|
|
|
|
|
|
|
}, |
64
|
|
|
|
|
|
|
errorExtra=>{ |
65
|
|
|
|
|
|
|
flags=>{ |
66
|
|
|
|
|
|
|
'1'=>'IOerror', |
67
|
|
|
|
|
|
|
'2'=>'NOfile', |
68
|
|
|
|
|
|
|
'3'=>'nameInvalid', |
69
|
|
|
|
|
|
|
'4'=>'searchNotUsable', |
70
|
|
|
|
|
|
|
'5'=>'elasticNotLoadable', |
71
|
|
|
|
|
|
|
'6'=>'notResults', |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
}, |
74
|
|
|
|
|
|
|
}; |
75
|
0
|
|
|
|
|
|
bless $self; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# finds the etc base to use |
78
|
0
|
0
|
|
|
|
|
if ( -d '/usr/local/etc/essearch/' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$self->{base}='/usr/local/etc/essearch/'; |
80
|
|
|
|
|
|
|
} elsif ( -d '/etc/essearch/' ) { |
81
|
0
|
|
|
|
|
|
$self->{base}='/etc/essearch/'; |
82
|
|
|
|
|
|
|
} elsif ( $0 =~ /bin\/essearcher$/ ) { |
83
|
0
|
|
|
|
|
|
$self->{base}=$0; |
84
|
0
|
|
|
|
|
|
$self->{base}=~s/\/bin\/essearcher$/\/etc\/essearch\//; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# inits Template |
88
|
0
|
|
|
|
|
|
$self->{t}=Template->new({ |
89
|
|
|
|
|
|
|
EVAL_PERL=>1, |
90
|
|
|
|
|
|
|
INTERPOLATE=>1, |
91
|
|
|
|
|
|
|
POST_CHOMP=>1, |
92
|
|
|
|
|
|
|
}); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# inits JSON |
95
|
0
|
|
|
|
|
|
$self->{j}=JSON->new; |
96
|
0
|
|
|
|
|
|
$self->{j}->pretty(1); # make the output sanely human readable |
97
|
0
|
|
|
|
|
|
$self->{j}->relaxed(1); # make writing search templates a bit easier |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
return $self; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head elastic_get |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
This returns what Elasticsearch config will be used. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $elastic=$ess->elastic_get; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=cut |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub elastic_get{ |
111
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
112
|
0
|
|
|
|
|
|
my $name=$_[1]; |
113
|
|
|
|
|
|
|
|
114
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
115
|
0
|
|
|
|
|
|
return undef; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
return $self->{elastic}; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head elastic_set |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
This sets the name of the config file to use. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
One option is taken and name of the config file to load. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Undef sets it back to the default, "default". |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$ess->elastic_set('foo'); |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
$ess->elastic_set(undef); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=cut |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub elastic_set{ |
136
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
137
|
0
|
|
|
|
|
|
my $name=$_[1]; |
138
|
|
|
|
|
|
|
|
139
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
140
|
0
|
|
|
|
|
|
return undef; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
0
|
0
|
|
|
|
|
if (! $self->name_validate( $name ) ){ |
144
|
0
|
|
|
|
|
|
$self->{error}=3; |
145
|
0
|
|
|
|
|
|
$self->{errorString}='"'.$name.'" is not a valid name'; |
146
|
0
|
|
|
|
|
|
$self->warn; |
147
|
0
|
|
|
|
|
|
return undef; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
0
|
0
|
|
|
|
|
if( !defined( $name ) ){ |
151
|
0
|
|
|
|
|
|
$name='default'; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
$self->{elastic}=$name; |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
return 1; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head2 fetch_help |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
This fetches the help for the current search and returns it. |
162
|
|
|
|
|
|
|
Failsure to find one, results in a empty message being returned. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $help=$ess->fetch_help; |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=cut |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub fetch_help{ |
169
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
170
|
|
|
|
|
|
|
|
171
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
172
|
0
|
|
|
|
|
|
return undef; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
my $file=undef; |
176
|
0
|
|
|
|
|
|
my $data=undef; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# ~/ -> etc -> module -> error |
179
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
0
|
|
|
|
|
180
|
|
|
|
|
|
|
( defined( $ENV{'HOME'} ) ) && |
181
|
|
|
|
|
|
|
( -f $ENV{'HOME'}.'/.config/essearcher/help/'.$self->{search} ) |
182
|
|
|
|
|
|
|
) { |
183
|
0
|
|
|
|
|
|
$file=$ENV{'HOME'}.'/.config/essearcher/help/'.$self->{search}; |
184
|
|
|
|
|
|
|
} elsif ( |
185
|
|
|
|
|
|
|
( defined( $self->{base} ) ) && |
186
|
|
|
|
|
|
|
( -f $self->{base}.'/etc/essearcher/help/'.$self->{search} ) |
187
|
|
|
|
|
|
|
) { |
188
|
0
|
|
|
|
|
|
$file=$self->{base}.'/etc/essearcher/help/'.$self->{search}; |
189
|
|
|
|
|
|
|
} else { |
190
|
|
|
|
|
|
|
# do a quick check of making sure we have a valid name before trying a module... |
191
|
|
|
|
|
|
|
# not all valid names are perl module name valid, but it will prevent arbitrary code execution |
192
|
0
|
0
|
|
|
|
|
if ( $self->name_validate( $self->{search} ) ) { |
193
|
|
|
|
|
|
|
my $to_eval='use Search::ESsearcher::Templates::'.$self->{search}. |
194
|
0
|
|
|
|
|
|
'; $data=Search::ESsearcher::Templates::'.$self->{search}.'->help;'; |
195
|
0
|
|
|
|
|
|
eval( $to_eval ); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
# if undefined, it means the eval failed |
198
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ) { |
199
|
0
|
|
|
|
|
|
$self->{error}=2; |
200
|
0
|
|
|
|
|
|
$self->{errorString}='No help file with the name "'.$self->{search}.'" was found'; |
201
|
0
|
|
|
|
|
|
$self->warn; |
202
|
0
|
|
|
|
|
|
return ''; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ) { |
207
|
0
|
|
|
|
|
|
my $fh; |
208
|
0
|
0
|
|
|
|
|
if (! open($fh, '<', $file ) ) { |
209
|
0
|
|
|
|
|
|
$self->{error}=1; |
210
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to open "'.$file.'"', |
211
|
|
|
|
|
|
|
$self->warn; |
212
|
0
|
|
|
|
|
|
return ''; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
# if it is larger than 2M bytes, something is wrong as the template |
215
|
|
|
|
|
|
|
# it takes is literally longer than all HHGTTG books combined |
216
|
0
|
0
|
|
|
|
|
if (! read($fh, $data, 200000000 )) { |
217
|
0
|
|
|
|
|
|
$self->{error}=1; |
218
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to read "'.$file.'"', |
219
|
|
|
|
|
|
|
$self->warn; |
220
|
0
|
|
|
|
|
|
return ''; |
221
|
|
|
|
|
|
|
} |
222
|
0
|
|
|
|
|
|
close($fh); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
return $data; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 get_options |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
This fetches the options for use later |
231
|
|
|
|
|
|
|
when filling in the search template. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$ess->get_options; |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=cut |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub get_options{ |
238
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
239
|
|
|
|
|
|
|
|
240
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
241
|
0
|
|
|
|
|
|
return undef; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
my %parsed_options; |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
|
GetOptions( \%parsed_options, @{ $self->{options_array} } ); |
|
0
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
$self->{parsed_options}=\%parsed_options; |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
return 1; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 load_options |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
This loads the currently set options. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
$ess->load_options; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=cut |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub load_options{ |
263
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
264
|
|
|
|
|
|
|
|
265
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
266
|
0
|
|
|
|
|
|
return undef; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
my $file; |
270
|
|
|
|
|
|
|
my $data; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# ~/ -> etc -> module -> error |
273
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
0
|
|
|
|
|
274
|
|
|
|
|
|
|
( defined( $ENV{'HOME'} ) ) && |
275
|
|
|
|
|
|
|
( -f $ENV{'HOME'}.'/.config/essearcher/options/'.$self->{options} ) |
276
|
|
|
|
|
|
|
) { |
277
|
0
|
|
|
|
|
|
$file=$ENV{'HOME'}.'/.config/essearcher/options/'.$self->{options}; |
278
|
|
|
|
|
|
|
} elsif ( |
279
|
|
|
|
|
|
|
( defined( $self->{base} ) ) && |
280
|
|
|
|
|
|
|
( -f $self->{base}.'/etc/essearcher/options/'.$self->{options} ) |
281
|
|
|
|
|
|
|
) { |
282
|
0
|
|
|
|
|
|
$file=$self->{base}.'/etc/essearcher/options/'.$self->{options}; |
283
|
|
|
|
|
|
|
} else { |
284
|
|
|
|
|
|
|
# do a quick check of making sure we have a valid name before trying a module... |
285
|
|
|
|
|
|
|
# not all valid names are perl module name valid, but it will prevent arbitrary code execution |
286
|
0
|
0
|
|
|
|
|
if ( $self->name_validate( $self->{options} ) ){ |
287
|
|
|
|
|
|
|
my $to_eval='use Search::ESsearcher::Templates::'.$self->{options}. |
288
|
0
|
|
|
|
|
|
'; $data=Search::ESsearcher::Templates::'.$self->{options}.'->options;'; |
289
|
0
|
|
|
|
|
|
eval( $to_eval ); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
# if undefined, it means the eval failed |
292
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ){ |
293
|
0
|
|
|
|
|
|
$self->{error}=2; |
294
|
0
|
|
|
|
|
|
$self->{errorString}='No options file or module with the name "'.$self->{options}.'" was found'; |
295
|
0
|
|
|
|
|
|
$self->warn; |
296
|
0
|
|
|
|
|
|
return undef; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
0
|
0
|
|
|
|
|
if ( defined( $file ) ) { |
301
|
0
|
|
|
|
|
|
my $fh; |
302
|
0
|
0
|
|
|
|
|
if (! open($fh, '<', $file ) ) { |
303
|
0
|
|
|
|
|
|
$self->{error}=1; |
304
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to open "'.$file.'"', |
305
|
|
|
|
|
|
|
$self->warn; |
306
|
0
|
|
|
|
|
|
return undef; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
# if it is larger than 2M bytes, something is wrong as the options |
309
|
|
|
|
|
|
|
# it takes is literally longer than all HHGTTG books combined |
310
|
0
|
0
|
|
|
|
|
if (! read($fh, $data, 200000000 )) { |
311
|
0
|
|
|
|
|
|
$self->{error}=1; |
312
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to read "'.$file.'"', |
313
|
|
|
|
|
|
|
$self->warn; |
314
|
0
|
|
|
|
|
|
return undef; |
315
|
|
|
|
|
|
|
} |
316
|
0
|
|
|
|
|
|
close($fh); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# split it appart and remove comments and blank lines |
320
|
0
|
|
|
|
|
|
my @options=split(/\n/,$data); |
321
|
0
|
|
|
|
|
|
@options=grep(!/^#/, @options); |
322
|
0
|
|
|
|
|
|
@options=grep(!/^$/, @options); |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# we have now completed with out error, so save it |
325
|
0
|
|
|
|
|
|
$self->{options_array}=\@options; |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
|
return 1; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=head2 load_elastic |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
This loads the currently specified config file |
333
|
|
|
|
|
|
|
containing the Elasticsearch config JSON. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
$ess->load_elastic; |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=cut |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub load_elastic{ |
340
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
341
|
|
|
|
|
|
|
|
342
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
343
|
0
|
|
|
|
|
|
return undef; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
my $file=undef; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# ~/ -> etc -> error |
349
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
0
|
|
|
|
|
350
|
|
|
|
|
|
|
( defined( $ENV{'HOME'} ) ) && |
351
|
|
|
|
|
|
|
( -f $ENV{'HOME'}.'/.config/essearcher/elastic/'.$self->{elastic} ) |
352
|
|
|
|
|
|
|
) { |
353
|
0
|
|
|
|
|
|
$file=$ENV{'HOME'}.'/.config/essearcher/elastic/'.$self->{elastic}; |
354
|
|
|
|
|
|
|
} elsif ( |
355
|
|
|
|
|
|
|
( defined( $self->{base} ) ) && |
356
|
|
|
|
|
|
|
( -f $self->{base}.'/etc/essearcher/elastic/'.$self->{elastic} ) |
357
|
|
|
|
|
|
|
) { |
358
|
0
|
|
|
|
|
|
$file=$self->{base}.'/etc/essearcher/elastic/'.$self->{elastic}; |
359
|
|
|
|
|
|
|
} else { |
360
|
|
|
|
|
|
|
$self->{elastic_hash}={ |
361
|
0
|
|
|
|
|
|
nodes => [ |
362
|
|
|
|
|
|
|
'127.0.0.1:9200' |
363
|
|
|
|
|
|
|
] |
364
|
|
|
|
|
|
|
}; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
0
|
0
|
|
|
|
|
if (defined( $file )) { |
368
|
0
|
|
|
|
|
|
my $fh; |
369
|
0
|
0
|
|
|
|
|
if (! open($fh, '<', $file ) ) { |
370
|
0
|
|
|
|
|
|
$self->{error}=1; |
371
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to open "'.$file.'"', |
372
|
|
|
|
|
|
|
$self->warn; |
373
|
0
|
|
|
|
|
|
return undef; |
374
|
|
|
|
|
|
|
} |
375
|
0
|
|
|
|
|
|
my $data; |
376
|
|
|
|
|
|
|
# if it is larger than 2M bytes, something is wrong as the template |
377
|
|
|
|
|
|
|
# it takes is literally longer than all HHGTTG books combined |
378
|
0
|
0
|
|
|
|
|
if (! read($fh, $data, 200000000 )) { |
379
|
0
|
|
|
|
|
|
$self->{error}=1; |
380
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to read "'.$file.'"', |
381
|
|
|
|
|
|
|
$self->warn; |
382
|
0
|
|
|
|
|
|
return undef; |
383
|
|
|
|
|
|
|
} |
384
|
0
|
|
|
|
|
|
close($fh); |
385
|
|
|
|
|
|
|
|
386
|
0
|
|
|
|
|
|
eval { |
387
|
0
|
|
|
|
|
|
my $decoded=$self->{j}->decode( $data ); |
388
|
0
|
|
|
|
|
|
$self->{elastic_hash}=$decoded; |
389
|
|
|
|
|
|
|
}; |
390
|
0
|
0
|
|
|
|
|
if ( $@ ){ |
391
|
0
|
|
|
|
|
|
$self->{error}=5; |
392
|
0
|
|
|
|
|
|
$self->{errorString}=$@; |
393
|
0
|
|
|
|
|
|
$self->warn; |
394
|
0
|
|
|
|
|
|
return undef; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
eval{ |
400
|
0
|
|
|
|
|
|
$self->{es}=Search::Elasticsearch->new( $self->{elastic_hash} ); |
401
|
|
|
|
|
|
|
}; |
402
|
0
|
0
|
|
|
|
|
if ( $@ ){ |
403
|
0
|
|
|
|
|
|
$self->{error}=5; |
404
|
0
|
|
|
|
|
|
$self->{errorString}=$@; |
405
|
0
|
|
|
|
|
|
$self->warn; |
406
|
0
|
|
|
|
|
|
return undef; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
return 1; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 load_output |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
This loads the currently specified output template. |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
While this is save internally, the template is also |
417
|
|
|
|
|
|
|
returned as a string. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
my $outpot_template=$ess->load_output; |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=cut |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub load_output{ |
424
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
425
|
|
|
|
|
|
|
|
426
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
427
|
0
|
|
|
|
|
|
return undef; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
0
|
|
|
|
|
|
my $file=undef; |
431
|
0
|
|
|
|
|
|
my $data=undef; |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
# ~/ -> etc -> module -> error |
434
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
0
|
|
|
|
|
435
|
|
|
|
|
|
|
( defined( $ENV{'HOME'} ) ) && |
436
|
|
|
|
|
|
|
( -f $ENV{'HOME'}.'/.config/essearcher/output/'.$self->{output} ) |
437
|
|
|
|
|
|
|
) { |
438
|
0
|
|
|
|
|
|
$file=$ENV{'HOME'}.'/.config/essearcher/output/'.$self->{output}; |
439
|
|
|
|
|
|
|
} elsif ( |
440
|
|
|
|
|
|
|
( defined( $self->{base} ) ) && |
441
|
|
|
|
|
|
|
( -f $self->{base}.'/etc/essearcher/output/'.$self->{output} ) |
442
|
|
|
|
|
|
|
) { |
443
|
0
|
|
|
|
|
|
$file=$self->{base}.'/etc/essearcher/outpot/'.$self->{output}; |
444
|
|
|
|
|
|
|
} else { |
445
|
|
|
|
|
|
|
# do a quick check of making sure we have a valid name before trying a module... |
446
|
|
|
|
|
|
|
# not all valid names are perl module name valid, but it will prevent arbitrary code execution |
447
|
0
|
0
|
|
|
|
|
if ( $self->name_validate( $self->{options} ) ) { |
448
|
|
|
|
|
|
|
my $to_eval='use Search::ESsearcher::Templates::'.$self->{output}. |
449
|
0
|
|
|
|
|
|
'; $data=Search::ESsearcher::Templates::'.$self->{output}.'->output;'; |
450
|
0
|
|
|
|
|
|
eval( $to_eval ); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
# if undefined, it means the eval failed |
453
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ) { |
454
|
0
|
|
|
|
|
|
$self->{error}=2; |
455
|
0
|
|
|
|
|
|
$self->{errorString}='No options file with the name "'.$self->{output}.'" was found'; |
456
|
0
|
|
|
|
|
|
$self->warn; |
457
|
0
|
|
|
|
|
|
return ''; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ) { |
462
|
0
|
|
|
|
|
|
my $fh; |
463
|
0
|
0
|
|
|
|
|
if (! open($fh, '<', $file ) ) { |
464
|
0
|
|
|
|
|
|
$self->{error}=1; |
465
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to open "'.$file.'"', |
466
|
|
|
|
|
|
|
$self->warn; |
467
|
0
|
|
|
|
|
|
return ''; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
# if it is larger than 2M bytes, something is wrong as the template |
470
|
|
|
|
|
|
|
# it takes is literally longer than all HHGTTG books combined |
471
|
0
|
0
|
|
|
|
|
if (! read($fh, $data, 200000000 )) { |
472
|
0
|
|
|
|
|
|
$self->{error}=1; |
473
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to read "'.$file.'"', |
474
|
|
|
|
|
|
|
$self->warn; |
475
|
0
|
|
|
|
|
|
return ''; |
476
|
|
|
|
|
|
|
} |
477
|
0
|
|
|
|
|
|
close($fh); |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# we have now completed with out error, so save it |
481
|
0
|
|
|
|
|
|
$self->{output_template}=$data; |
482
|
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
|
return $data; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head2 load_search |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
This loads the currently specified search template. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
While this is save internally, the template is also |
491
|
|
|
|
|
|
|
returned as a string. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
my $search_template=$ess->load_search; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=cut |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub load_search{ |
498
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
499
|
|
|
|
|
|
|
|
500
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
501
|
0
|
|
|
|
|
|
return undef; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
0
|
|
|
|
|
|
my $file=undef; |
505
|
0
|
|
|
|
|
|
my $data; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# ~/ -> etc -> module -> error |
508
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
0
|
0
|
|
|
|
|
509
|
|
|
|
|
|
|
( defined( $ENV{'HOME'} ) ) && |
510
|
|
|
|
|
|
|
( -f $ENV{'HOME'}.'/.config/essearcher/search/'.$self->{search} ) |
511
|
|
|
|
|
|
|
) { |
512
|
0
|
|
|
|
|
|
$file=$ENV{'HOME'}.'/.config/essearcher/search/'.$self->{search}; |
513
|
|
|
|
|
|
|
} elsif ( |
514
|
|
|
|
|
|
|
( defined( $self->{base} ) ) && |
515
|
|
|
|
|
|
|
( -f $self->{base}.'/etc/essearcher/search/'.$self->{search} ) |
516
|
|
|
|
|
|
|
) { |
517
|
0
|
|
|
|
|
|
$file=$self->{base}.'/etc/essearcher/search/'.$self->{search}; |
518
|
|
|
|
|
|
|
} else { |
519
|
|
|
|
|
|
|
# do a quick check of making sure we have a valid name before trying a module... |
520
|
|
|
|
|
|
|
# not all valid names are perl module name valid, but it will prevent arbitrary code execution |
521
|
0
|
0
|
|
|
|
|
if ( $self->name_validate( $self->{options} ) ){ |
522
|
|
|
|
|
|
|
my $to_eval='use Search::ESsearcher::Templates::'.$self->{options}. |
523
|
0
|
|
|
|
|
|
'; $data=Search::ESsearcher::Templates::'.$self->{options}.'->search;'; |
524
|
0
|
|
|
|
|
|
eval( $to_eval ); |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
# if undefined, it means the eval failed |
527
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ){ |
528
|
0
|
|
|
|
|
|
$self->{error}=2; |
529
|
0
|
|
|
|
|
|
$self->{errorString}='No template file with the name "'.$self->{search}.'" was found'; |
530
|
0
|
|
|
|
|
|
$self->warn; |
531
|
0
|
|
|
|
|
|
return undef; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
0
|
0
|
|
|
|
|
if ( ! defined( $data ) ) { |
536
|
0
|
|
|
|
|
|
my $fh; |
537
|
0
|
0
|
|
|
|
|
if (! open($fh, '<', $file ) ) { |
538
|
0
|
|
|
|
|
|
$self->{error}=1; |
539
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to open "'.$file.'"', |
540
|
|
|
|
|
|
|
$self->warn; |
541
|
0
|
|
|
|
|
|
return undef; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
# if it is larger than 2M bytes, something is wrong as the template |
544
|
|
|
|
|
|
|
# it takes is literally longer than all HHGTTG books combined |
545
|
0
|
0
|
|
|
|
|
if (! read($fh, $data, 200000000 )) { |
546
|
0
|
|
|
|
|
|
$self->{error}=1; |
547
|
0
|
|
|
|
|
|
$self->{errorString}='Failed to read "'.$file.'"', |
548
|
|
|
|
|
|
|
$self->warn; |
549
|
0
|
|
|
|
|
|
return undef; |
550
|
|
|
|
|
|
|
} |
551
|
0
|
|
|
|
|
|
close($fh); |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
# we have now completed with out error, so save it |
555
|
0
|
|
|
|
|
|
$self->{search_template}=$data; |
556
|
|
|
|
|
|
|
|
557
|
0
|
|
|
|
|
|
return 1; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=head2 name_valide |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
This validates a config name. |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
One option is taken and that is the name to valid. |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
The returned value is a perl boolean based on if it |
567
|
|
|
|
|
|
|
it is valid or not. |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
if ( ! $ess->name_validate( $name ) ){ |
570
|
|
|
|
|
|
|
print "Name is not valid.\n"; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub name_validate{ |
576
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
577
|
0
|
|
|
|
|
|
my $name=$_[1]; |
578
|
|
|
|
|
|
|
|
579
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
580
|
0
|
|
|
|
|
|
return undef; |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
|
583
|
0
|
0
|
|
|
|
|
if (! defined( $name ) ){ |
584
|
0
|
|
|
|
|
|
return 1; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
$name=~s/[A-Z0-9a-z\:\-\=\_+\ ]+//; |
588
|
|
|
|
|
|
|
|
589
|
0
|
0
|
|
|
|
|
if ( $name !~ /^$/ ){ |
590
|
0
|
|
|
|
|
|
return undef; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
0
|
|
|
|
|
|
return 1; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=head options_get |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
This returns the currently set options |
599
|
|
|
|
|
|
|
config name. |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
my $options=$ess->options_get; |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=cut |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub options_get{ |
606
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
607
|
|
|
|
|
|
|
|
608
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
609
|
0
|
|
|
|
|
|
return undef; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
0
|
|
|
|
|
|
return $self->{options}; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=head options_set |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
This sets the options config name to use. |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
One option is taken and this is the config name. |
620
|
|
|
|
|
|
|
If it is undefiend, then the default is used. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
$ess->options_set( $name ); |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=cut |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub options_set{ |
627
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
628
|
0
|
|
|
|
|
|
my $name=$_[1]; |
629
|
|
|
|
|
|
|
|
630
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
631
|
0
|
|
|
|
|
|
return undef; |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
|
634
|
0
|
0
|
|
|
|
|
if (! $self->name_validate( $name ) ){ |
635
|
0
|
|
|
|
|
|
$self->{error}=3; |
636
|
0
|
|
|
|
|
|
$self->{errorString}='"'.$name.'" is not a valid name'; |
637
|
0
|
|
|
|
|
|
$self->warn; |
638
|
0
|
|
|
|
|
|
return undef; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
0
|
0
|
|
|
|
|
if( !defined( $name ) ){ |
642
|
0
|
|
|
|
|
|
$name='syslog'; |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
0
|
|
|
|
|
|
$self->{options}=$name; |
646
|
|
|
|
|
|
|
|
647
|
0
|
|
|
|
|
|
return 1; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=head output_get |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
This returns the currently set output |
653
|
|
|
|
|
|
|
template name. |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
my $output=$ess->output_get; |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=cut |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
sub output_get{ |
660
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
661
|
0
|
|
|
|
|
|
my $name=$_[1]; |
662
|
|
|
|
|
|
|
|
663
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
664
|
0
|
|
|
|
|
|
return undef; |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
|
667
|
0
|
|
|
|
|
|
return $self->{output}; |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=head output_set |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
This sets the output template name to use. |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
One option is taken and this is the template name. |
676
|
|
|
|
|
|
|
If it is undefiend, then the default is used. |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
$ess->output_set( $name ); |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=cut |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
sub output_set{ |
683
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
684
|
0
|
|
|
|
|
|
my $name=$_[1]; |
685
|
|
|
|
|
|
|
|
686
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
687
|
0
|
|
|
|
|
|
return undef; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
0
|
0
|
|
|
|
|
if (! $self->name_validate( $name ) ){ |
691
|
0
|
|
|
|
|
|
$self->{error}=3; |
692
|
0
|
|
|
|
|
|
$self->{errorString}='"'.$name.'" is not a valid name'; |
693
|
0
|
|
|
|
|
|
$self->warn; |
694
|
0
|
|
|
|
|
|
return undef; |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
0
|
0
|
|
|
|
|
if( !defined( $name ) ){ |
698
|
0
|
|
|
|
|
|
$name='syslog'; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
0
|
|
|
|
|
|
$self->{output}=$name; |
702
|
|
|
|
|
|
|
|
703
|
0
|
|
|
|
|
|
return 1; |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=head2 results_process |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
This processes the results from search_run. |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
One option is taken and that is the return from search_run. |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
The returned value from this is array of each document found |
713
|
|
|
|
|
|
|
after it has been formated using the set output template. |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
my $results=$ess->search_run; |
716
|
|
|
|
|
|
|
my @formated=$ess->results_process( $results ); |
717
|
|
|
|
|
|
|
@formated=reverse(@formated); |
718
|
|
|
|
|
|
|
print join("\n", @formated)."\n"; |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=cut |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
sub results_process{ |
723
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
724
|
0
|
|
|
|
|
|
my $results=$_[1]; |
725
|
|
|
|
|
|
|
|
726
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
727
|
0
|
|
|
|
|
|
return undef; |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
#make sure we have a sane object passed to us |
731
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
|
0
|
|
|
|
|
732
|
|
|
|
|
|
|
( ref( $results ) ne 'HASH' ) || |
733
|
|
|
|
|
|
|
( !defined( $results->{hits} ) )|| |
734
|
|
|
|
|
|
|
( !defined( $results->{hits}{hits} ) ) |
735
|
|
|
|
|
|
|
){ |
736
|
0
|
|
|
|
|
|
$self->{error}=6; |
737
|
0
|
|
|
|
|
|
$self->{errorString}='The passed results variable does not a appear to be a search results return'; |
738
|
0
|
|
|
|
|
|
$self->warn; |
739
|
0
|
|
|
|
|
|
return undef; |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
#use Data::Dumper; |
743
|
|
|
|
|
|
|
#print Dumper( $results->{hits}{hits} ); |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
my $vars={ |
746
|
|
|
|
|
|
|
o=>$self->{parsed_options}, |
747
|
|
|
|
|
|
|
r=>$results, |
748
|
0
|
|
|
0
|
|
|
c=>sub{ return color( $_[0] ); }, |
749
|
|
|
|
|
|
|
pd=>sub{ |
750
|
0
|
0
|
|
0
|
|
|
if( $_[0] =~ /^raw\:/ ){ |
751
|
0
|
|
|
|
|
|
$_[0] =~ s/^raw\://; |
752
|
0
|
|
|
|
|
|
return $_[0]; |
753
|
|
|
|
|
|
|
} |
754
|
0
|
|
|
|
|
|
$_[0]=~s/m$/minutes/; |
755
|
0
|
|
|
|
|
|
$_[0]=~s/M$/months/; |
756
|
0
|
|
|
|
|
|
$_[0]=~s/d$/days/; |
757
|
0
|
|
|
|
|
|
$_[0]=~s/h$/hours/; |
758
|
0
|
|
|
|
|
|
$_[0]=~s/h$/weeks/; |
759
|
0
|
|
|
|
|
|
$_[0]=~s/y$/years/; |
760
|
0
|
|
|
|
|
|
$_[0]=~s/([0123456789])$/$1seconds/; |
761
|
0
|
|
|
|
|
|
$_[0]=~s/([0123456789])s$/$1seconds/; |
762
|
0
|
|
|
|
|
|
my $secs=""; |
763
|
0
|
|
|
|
|
|
eval{ $secs=parsedate( $_[0] ); }; |
|
0
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
return $secs; |
765
|
|
|
|
|
|
|
}, |
766
|
0
|
|
|
|
|
|
}; |
767
|
|
|
|
|
|
|
|
768
|
0
|
|
|
|
|
|
my @formatted; |
769
|
0
|
|
|
|
|
|
foreach my $doc ( @{ $results->{hits}{hits} } ){ |
|
0
|
|
|
|
|
|
|
770
|
0
|
|
|
|
|
|
$vars->{doc}=$doc; |
771
|
0
|
|
|
|
|
|
$vars->{f}=$doc->{_source}; |
772
|
|
|
|
|
|
|
|
773
|
0
|
|
|
|
|
|
my $processed; |
774
|
0
|
|
|
|
|
|
$self->{t}->process( \$self->{output_template}, $vars , \$processed ); |
775
|
0
|
|
|
|
|
|
chomp($processed); |
776
|
|
|
|
|
|
|
|
777
|
0
|
|
|
|
|
|
push(@formatted,$processed); |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
0
|
|
|
|
|
|
@formatted=reverse(@formatted); |
781
|
|
|
|
|
|
|
|
782
|
0
|
|
|
|
|
|
return @formatted; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
=head search_get |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
This returns the currently set search |
788
|
|
|
|
|
|
|
template name. |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
my $search=$ess->search_get; |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
=cut |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
sub search_get{ |
796
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
797
|
0
|
|
|
|
|
|
my $name=$_[1]; |
798
|
|
|
|
|
|
|
|
799
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
800
|
0
|
|
|
|
|
|
return undef; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
0
|
|
|
|
|
|
return $self->{search}; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
=head2 search_fill_in |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
This fills in the loaded search template. |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
The results are saved internally as well as returned. |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
my $filled_in=$ess->search_fill_in; |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=cut |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
sub search_fill_in{ |
817
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
818
|
0
|
|
|
|
|
|
my $name=$_[1]; |
819
|
|
|
|
|
|
|
|
820
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
821
|
0
|
|
|
|
|
|
return undef; |
822
|
|
|
|
|
|
|
} |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
my $vars={ |
825
|
|
|
|
|
|
|
o=>$self->{parsed_options}, |
826
|
|
|
|
|
|
|
aon=>sub{ |
827
|
0
|
|
|
0
|
|
|
$_[0]=~s/\+/\ AND\ /; |
828
|
0
|
|
|
|
|
|
$_[0]=~s/\,/\ OR\ /; |
829
|
0
|
|
|
|
|
|
$_[0]=~s/\!/\ NOT\ /; |
830
|
0
|
|
|
|
|
|
return $_[0]; |
831
|
|
|
|
|
|
|
}, |
832
|
|
|
|
|
|
|
aonHost=>sub{ |
833
|
0
|
|
|
0
|
|
|
$_[0]=~s/^([A-Za-z0-9\.]+)/\/$1*\//; |
834
|
0
|
|
|
|
|
|
$_[0]=~s/\+([A-Za-z0-9\.]+)/\ AND\ \/$1*\//; |
835
|
0
|
|
|
|
|
|
$_[0]=~s/\,([A-Za-z0-9\.]+)/\ OR\ \/$1*\//; |
836
|
0
|
|
|
|
|
|
$_[0]=~s/\!([A-Za-z0-9\.]+)/\ NOT\ \/$1*\//; |
837
|
0
|
|
|
|
|
|
return $_[0]; |
838
|
|
|
|
|
|
|
}, |
839
|
|
|
|
|
|
|
pd=>sub{ |
840
|
0
|
0
|
|
0
|
|
|
if( $_[0] =~ /^u\:/ ){ |
|
|
0
|
|
|
|
|
|
841
|
0
|
|
|
|
|
|
$_[0] =~ s/^u\://; |
842
|
0
|
|
|
|
|
|
$_[0]=~s/m$/minutes/; |
843
|
0
|
|
|
|
|
|
$_[0]=~s/M$/months/; |
844
|
0
|
|
|
|
|
|
$_[0]=~s/d$/days/; |
845
|
0
|
|
|
|
|
|
$_[0]=~s/h$/hours/; |
846
|
0
|
|
|
|
|
|
$_[0]=~s/h$/weeks/; |
847
|
0
|
|
|
|
|
|
$_[0]=~s/y$/years/; |
848
|
0
|
|
|
|
|
|
$_[0]=~s/([0123456789])$/$1seconds/; |
849
|
0
|
|
|
|
|
|
$_[0]=~s/([0123456789])s$/$1seconds/; |
850
|
0
|
|
|
|
|
|
my $secs=""; |
851
|
0
|
|
|
|
|
|
eval{ $secs=parsedate( $_[0] ); }; |
|
0
|
|
|
|
|
|
|
852
|
0
|
|
|
|
|
|
return $secs; |
853
|
|
|
|
|
|
|
}elsif( $_[0] =~ /^\-/ ){ |
854
|
0
|
|
|
|
|
|
return 'now'.$_[0]; |
855
|
|
|
|
|
|
|
} |
856
|
0
|
|
|
|
|
|
return $_[0]; |
857
|
|
|
|
|
|
|
}, |
858
|
0
|
|
|
|
|
|
}; |
859
|
|
|
|
|
|
|
|
860
|
0
|
|
|
|
|
|
my $processed; |
861
|
0
|
|
|
|
|
|
$self->{t}->process( \$self->{search_template}, $vars , \$processed ); |
862
|
|
|
|
|
|
|
|
863
|
0
|
|
|
|
|
|
$self->{search_filled_in}=$processed; |
864
|
|
|
|
|
|
|
|
865
|
0
|
|
|
|
|
|
$self->{search_usable}=undef; |
866
|
|
|
|
|
|
|
|
867
|
0
|
|
|
|
|
|
eval { |
868
|
0
|
|
|
|
|
|
my $decoded=$self->{j}->decode( $processed ); |
869
|
0
|
|
|
|
|
|
$self->{search_hash}=$decoded; |
870
|
|
|
|
|
|
|
}; |
871
|
0
|
0
|
|
|
|
|
if ( $@ ){ |
872
|
0
|
|
|
|
|
|
$self->{error}=4; |
873
|
0
|
|
|
|
|
|
$self->{errorString}='The returned filled in search template does not parse as JSON... '.$@; |
874
|
0
|
|
|
|
|
|
$self->warn; |
875
|
0
|
|
|
|
|
|
return $processed; |
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
|
878
|
0
|
|
|
|
|
|
return $processed; |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
=head2 search_run |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
This is used to run the search after search_fill_in |
884
|
|
|
|
|
|
|
has been called. |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
The returned value is of the type that would be returned |
887
|
|
|
|
|
|
|
by L<Search::Elasticsearch>->search. |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
my $results=$ess->search_run; |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=cut |
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
sub search_run{ |
894
|
0
|
|
|
0
|
1
|
|
my $self=$_[0]; |
895
|
0
|
|
|
|
|
|
my $name=$_[1]; |
896
|
|
|
|
|
|
|
|
897
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
898
|
0
|
|
|
|
|
|
return undef; |
899
|
|
|
|
|
|
|
} |
900
|
|
|
|
|
|
|
|
901
|
0
|
|
|
|
|
|
my $results; |
902
|
0
|
|
|
|
|
|
eval{ |
903
|
0
|
|
|
|
|
|
$results=$self->{es}->search( $self->{search_hash} ); |
904
|
|
|
|
|
|
|
}; |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
# @timestamp can't be handled via |
907
|
0
|
0
|
0
|
|
|
|
if ( |
|
|
|
0
|
|
|
|
|
908
|
|
|
|
|
|
|
( ref( $results ) eq 'HASH' ) || |
909
|
|
|
|
|
|
|
( defined( $results->{hits} ) )|| |
910
|
|
|
|
|
|
|
( defined( $results->{hits}{hits} ) ) |
911
|
|
|
|
|
|
|
){ |
912
|
0
|
|
|
|
|
|
foreach my $item ( @{ $results->{hits}{hits} } ){ |
|
0
|
|
|
|
|
|
|
913
|
0
|
0
|
|
|
|
|
if (!defined( $item->{'_source'}{'timestamp'}) ) { |
914
|
0
|
|
|
|
|
|
$item->{'_source'}{'timestamp'}=$item->{'_source'}{'@timestamp'} |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
|
919
|
0
|
|
|
|
|
|
return $results; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
=head search_set |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
This sets the search template name to use. |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
One option is taken and this is the template name. |
927
|
|
|
|
|
|
|
If it is undefiend, then the default is used. |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
$ess->search_sets( $name ); |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
=cut |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
sub search_set{ |
934
|
0
|
|
|
0
|
0
|
|
my $self=$_[0]; |
935
|
0
|
|
|
|
|
|
my $name=$_[1]; |
936
|
|
|
|
|
|
|
|
937
|
0
|
0
|
|
|
|
|
if ( ! $self->errorblank ) { |
938
|
0
|
|
|
|
|
|
return undef; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
|
941
|
0
|
0
|
|
|
|
|
if (! $self->name_validate( $name ) ){ |
942
|
0
|
|
|
|
|
|
$self->{error}=3; |
943
|
0
|
|
|
|
|
|
$self->{errorString}='"'.$name.'" is not a valid name'; |
944
|
0
|
|
|
|
|
|
$self->warn; |
945
|
0
|
|
|
|
|
|
return undef; |
946
|
|
|
|
|
|
|
} |
947
|
|
|
|
|
|
|
|
948
|
0
|
0
|
|
|
|
|
if( !defined( $name ) ){ |
949
|
0
|
|
|
|
|
|
$name='syslog'; |
950
|
|
|
|
|
|
|
} |
951
|
|
|
|
|
|
|
|
952
|
0
|
|
|
|
|
|
$self->{search}=$name; |
953
|
|
|
|
|
|
|
|
954
|
0
|
|
|
|
|
|
return 1; |
955
|
|
|
|
|
|
|
} |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=head1 Configuration And Usage |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
Configs, help, and templates are looked for in the following manner and order, |
960
|
|
|
|
|
|
|
with the following of the elasticsearch config. |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
$ENV{HOME}."/.config/essearcher/".$item."/".$name |
963
|
|
|
|
|
|
|
$base.'/etc/essearcher/".$item."/".$name |
964
|
|
|
|
|
|
|
Search::ESsearcher::Templates::$name->$item |
965
|
|
|
|
|
|
|
ERROR |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
Item can be any of the following. |
968
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
elastic |
970
|
|
|
|
|
|
|
help |
971
|
|
|
|
|
|
|
output |
972
|
|
|
|
|
|
|
options |
973
|
|
|
|
|
|
|
search |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
The basic idea is you have matching output, options |
976
|
|
|
|
|
|
|
and search that you can use to perform queries and |
977
|
|
|
|
|
|
|
print the results. |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
Each template/config is its own file under the directory |
980
|
|
|
|
|
|
|
named after its purpose. So the options template fail2ban |
981
|
|
|
|
|
|
|
would be 'options/fail2ban'. |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=head2 elastic |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
This directory contains JSON formatted config files |
986
|
|
|
|
|
|
|
for use with connecting to the Elasticsearch server. |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
This is then read in and converted to a hash and feed |
989
|
|
|
|
|
|
|
to L<Search::Elasticsearch>->new. |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
By default it will attempt to connect to it on |
992
|
|
|
|
|
|
|
"127.0.0.1:9200". The JSON equivalent would be... |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
{ "nodes": [ "127.0.0.1:9200" ] } |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=head2 options |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
This is a file that will be used as a string for with |
999
|
|
|
|
|
|
|
L<Getopt::Long>. They will be passed to the templates |
1000
|
|
|
|
|
|
|
as a hash. |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
=head2 help |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
This contains information on the options the search uses. |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
This is just a text file containing information and is not |
1007
|
|
|
|
|
|
|
required. |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
If you are writing a module, it should definitely be present. |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=head2 search |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
This is a L<Template> template that will be filled in using |
1014
|
|
|
|
|
|
|
the data from the passed command line options and used |
1015
|
|
|
|
|
|
|
to run the search. |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
The end result should be valid JSON that can be turned |
1018
|
|
|
|
|
|
|
into a hash for feeding L<Search::Elasticsearch>->search. |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
When writing search templates, it is highly suggested |
1021
|
|
|
|
|
|
|
to use L<Template::Plugin::JSON> for when inserting variables |
1022
|
|
|
|
|
|
|
as it will automatically escape them. |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
=head2 output |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
This is a L<Template> template that will be filled in using |
1027
|
|
|
|
|
|
|
the data from the passed command line options and the returned |
1028
|
|
|
|
|
|
|
results. |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
It will be used for each returned document. bin/essearcher will |
1031
|
|
|
|
|
|
|
then join the array with "\n". |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
=head1 TEMPLATES |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
=head2 o |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
This is a hash that contains the parsed options. |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
Below is a example with the option --program and |
1040
|
|
|
|
|
|
|
transforming it a JSON save value. |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
[% USE JSON ( pretty => 1 ) %] |
1043
|
|
|
|
|
|
|
[% DEFAULT o.program = "*" %] |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
{"query_string": { |
1046
|
|
|
|
|
|
|
"default_field": "program", |
1047
|
|
|
|
|
|
|
"query": [% o.program.json %] |
1048
|
|
|
|
|
|
|
} |
1049
|
|
|
|
|
|
|
}, |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
=head2 aon |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
This is AND, OR, or NOT sub that handles |
1054
|
|
|
|
|
|
|
the following in a string, transforming them |
1055
|
|
|
|
|
|
|
from the punctuation to the logic. |
1056
|
|
|
|
|
|
|
|
1057
|
|
|
|
|
|
|
, OR |
1058
|
|
|
|
|
|
|
+ AND |
1059
|
|
|
|
|
|
|
! NOT |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
So the string "postfix,spamd" would become |
1062
|
|
|
|
|
|
|
"postfix OR spamd". |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
Can be used like below. |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
[% USE JSON ( pretty => 1 ) %] |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
[% IF o.program %] |
1069
|
|
|
|
|
|
|
{"query_string": { |
1070
|
|
|
|
|
|
|
"default_field": "program", |
1071
|
|
|
|
|
|
|
"query": [% aon( o.program ).json %] |
1072
|
|
|
|
|
|
|
} |
1073
|
|
|
|
|
|
|
}, |
1074
|
|
|
|
|
|
|
[% END %] |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
This function is only available for the search template. |
1077
|
|
|
|
|
|
|
|
1078
|
|
|
|
|
|
|
=head2 aonHost |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
This is AND, OR, or NOT sub that handles |
1081
|
|
|
|
|
|
|
the following in a string, transforming them |
1082
|
|
|
|
|
|
|
from the punctuation to the logic. |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
, OR |
1085
|
|
|
|
|
|
|
+ AND |
1086
|
|
|
|
|
|
|
! NOT |
1087
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
So the string "foo.,mail.bar." would become |
1089
|
|
|
|
|
|
|
"/foo./ OR /mail.bar./". |
1090
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
This is best used with $field.keyword. |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
Can be used like below. |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
[% USE JSON ( pretty => 1 ) %] |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
[% IF o.host %] |
1098
|
|
|
|
|
|
|
{"query_string": { |
1099
|
|
|
|
|
|
|
"default_field": "host.keyword", |
1100
|
|
|
|
|
|
|
"query": [% aonHost( o.host ).json %] |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
}, |
1103
|
|
|
|
|
|
|
[% END %] |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
This function is only available for the search template. |
1106
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
=head2 c |
1108
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
This wraps L<Term::ANSIColor>->color. |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
[% c("cyan") %][% f.timestamp %] [% c("bright_blue") %][% f.logsource %] |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
This function is only available for the output template. |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
=head2 pd |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
This is a time helper. |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
/^-/ appends "now" to it. So "-5m" becomes "now-5m". |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
/^u\:/ takes what is after ":" and uses Time::ParseDate to convert |
1122
|
|
|
|
|
|
|
it to a unix time value. |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
Any thing not matching maching any of the above will just be passed on. |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
[% IF o.dgt %] |
1127
|
|
|
|
|
|
|
{"range": { |
1128
|
|
|
|
|
|
|
"@timestamp": { |
1129
|
|
|
|
|
|
|
"gt": [% pd( o.dgt ).json %] |
1130
|
|
|
|
|
|
|
} |
1131
|
|
|
|
|
|
|
} |
1132
|
|
|
|
|
|
|
}, |
1133
|
|
|
|
|
|
|
[% END %] |
1134
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
=head1 Modules |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
Additonal modules bundling help, options, search, and output |
1139
|
|
|
|
|
|
|
can be made. The requirement for these are as below. |
1140
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
They need to exist below Search::ESsearcher::Templates. |
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
Provide the following functions that return strings. |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
help |
1146
|
|
|
|
|
|
|
options |
1147
|
|
|
|
|
|
|
search |
1148
|
|
|
|
|
|
|
output |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
Basic information as to what is required to make it work in logstash |
1151
|
|
|
|
|
|
|
or the like is also good as well. |
1152
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
=head1 ERROR CODES/FLAGS |
1154
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
All error handling is done via L<Error::Helper>. |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
=head2 1 / IOerror |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
Failed to perform some sort of file operation. |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
=head2 2 / NOfile |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
The specified template/config does not exist. |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
=head2 3 / nameIsInvalid |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
Invalid name specified. |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
=head2 4 / searchNotUsable |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
Errored while processing the template. |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
For more information on writing templates, see L<Template>. |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
=head2 5 / elasticnotloadable |
1176
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
The Elasticsearch config does not parse as JSON, preventing |
1178
|
|
|
|
|
|
|
it from being loaded. |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=head2 6 / notResults |
1181
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
The return value passed to results_process deos not appear to |
1183
|
|
|
|
|
|
|
be a results return. Most likely the search errored and returned |
1184
|
|
|
|
|
|
|
undef or a blank value. |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
=head1 AUTHOR |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
Zane C. Bowers-Hadley, C<< <vvelox at vvelox.net> >> |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
=head1 BUGS |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
Please report any bugs or feature requests to C<bug-search-essearcher at rt.cpan.org>, or through |
1193
|
|
|
|
|
|
|
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Search-ESsearcher>. I will be notified, and then you'll |
1194
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
=head1 SUPPORT |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
perldoc Search::ESsearcher |
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
You can also look for information at: |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
=over 4 |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Search-ESsearcher> |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
L<http://annocpan.org/dist/Search-ESsearcher> |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
=item * CPAN Ratings |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
L<https://cpanratings.perl.org/d/Search-ESsearcher> |
1221
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
=item * Search CPAN |
1223
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
L<https://metacpan.org/release/Search-ESsearcher> |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
=item * Repository |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
L<https://github.com/VVelox/Search-ESsearcher> |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
=back |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
1234
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
This software is Copyright (c) 2019 by Zane C. Bowers-Hadley. |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
This is free software, licensed under: |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
=cut |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
1; # End of Search::ESsearcher |