File Coverage

blib/lib/WWW/Splunk.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             =encoding utf8
2              
3             =head1 NAME
4              
5             WWW::Splunk - Client library for Splunk log search engine
6              
7             =head1 SYNOPSIS
8              
9             use WWW::Splunk;
10              
11             my $splunk = WWW::Splunk->new({
12             host => $host,
13             port => $port,
14             login => $login,
15             password => $password,
16             unsafe_ssl => 1,
17             verbose => 0,
18             });
19              
20             my $sid = $splunk->start_search('selinux avc');
21             $splunk->poll_search($sid);
22             until ($splunk->results_read($sid)) {
23             print scalar $splunk->search_results($sid);
24             }
25             print " results found\n";
26              
27             =head1 DESCRIPTION
28              
29             This module contains utility functions for Splunk API, implementing
30             version 4.1 API, verified to work with 4.2, 4.3 and 5.0.3 versions.
31              
32             =cut
33              
34             package WWW::Splunk;
35              
36 2     2   51303 use strict;
  2         17  
  2         51  
37 2     2   10 use warnings;
  2         4  
  2         78  
38              
39             our $VERSION = '2.08';
40              
41 2     2   559 use WWW::Splunk::API;
  0            
  0            
42             use Carp;
43             use Date::Manip;
44              
45             use base qw/WWW::Splunk::API/;
46              
47             =head2 B (F) [(F)] [(F)]
48              
49             Initiate a search, return a SID (Search ID) string.
50              
51             =cut
52              
53             sub start_search {
54             my ($self, $string, $since, $until) = @_;
55              
56             delete $self->{last_read};
57              
58             # Format dates
59             ($since, $until) = map { defined $_ ? scalar UnixDate (ParseDate ($_) || $_, '%O') || $_ : undef }
60             ($since, $until);
61              
62             $self->{results_consumed} = 0;
63             my $response = $self->post ('/search/jobs', {
64             search => "search $string",
65             (defined $since ? (earliest_time => $since) : ()),
66             (defined $until ? (latest_time => $until) : ()),
67             });
68             die 'Unexpected response format '
69             unless $response and ref $response eq 'XML::LibXML::Document';
70             my $sid = $response->findvalue ('/response/sid');
71             croak 'Bad response' unless defined $sid;
72              
73             return $sid;
74             }
75              
76             =head2 B (F) (F) [(F)] [(F)]
77              
78             Initiate a real-time search, calling a callback for each line matched.
79              
80             Finishes only if connection terminates (potentially never), returning number of
81             results consumed.
82              
83             =cut
84              
85             sub rt_search {
86             my ($self, $string, $callback, $since, $until, $counter) = @_;
87              
88             $since ||= 'rt';
89             $until ||= 'rt';
90             $counter ||= 0;
91              
92             $self->post ('/search/jobs/export', {
93             search => "search $string",
94             earliest_time => $since,
95             latest_time => $until,
96             search_mode => 'realtime',
97             }, sub {
98             $callback->(@_);
99             $counter++;
100             });
101              
102             return $counter;
103             }
104              
105             =head2 B (F)
106              
107             Return true if the search is finished.
108              
109             =cut
110              
111             sub search_done {
112             my ($self, $sid) = @_;
113              
114             my $search = $self->get ('/search/jobs/'.$sid);
115              
116             return $search->{isDone};
117             }
118              
119             =head2 B (F)
120              
121             Wait for a search to finish.
122              
123             =cut
124              
125             sub poll_search {
126             my ($self, $sid) = @_;
127              
128             until ($self->search_done ($sid)) {
129             sleep 1;
130             }
131             }
132              
133             =head2 B (F)
134              
135             Return an array of the matched events.
136             If called multiple times, it only returns events which
137             were added from the time of the last call.
138             Oh, and you can't run multiple search concurrently
139             with single L instance. Otherwise,
140             L is perfectly thread-safe.
141              
142             =cut
143              
144             sub search_results {
145             my ($self, $sid) = @_;
146              
147             my $done = $self->search_done ($sid);
148             my @results = $self->get ('/search/jobs/'.$sid.'/results?count=1024&offset='.
149             $self->{results_consumed});
150             $self->{results_consumed} += scalar @results;
151             $self->{last_read} = scalar @results if $done;
152              
153             return @results;
154             }
155              
156             =head2 B (F)
157              
158             Return true if search is finished and all there are no
159             more results to read (everything was fetched with L).
160              
161             =cut
162              
163             sub results_read {
164             my ($self, $sid) = @_;
165              
166             return undef if not defined $self->{last_read};
167             return $self->{last_read} eq 0;
168             }
169              
170             =head1 AUTHORS
171              
172             Lubomir Rintel, L<< >>,
173             Michal Josef Špaček L<< >>
174              
175             The code is hosted on GitHub L.
176             Bug fixes and feature enhancements are always welcome.
177              
178             =head1 LICENSE
179              
180             This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
181              
182             =cut
183              
184             1;