File Coverage

blib/lib/WWW/Splunk.pm
Criterion Covered Total %
statement 18 53 33.9
branch 0 16 0.0
condition 0 12 0.0
subroutine 6 13 46.1
pod 6 6 100.0
total 30 100 30.0


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   137995 use strict;
  2         5  
  2         80  
37 2     2   19 use warnings;
  2         6  
  2         141  
38              
39             our $VERSION = '2.09';
40              
41 2     2   1206 use WWW::Splunk::API;
  2         8  
  2         87  
42 2     2   16 use Carp;
  2         4  
  2         122  
43 2     2   1273 use Date::Manip;
  2         291822  
  2         458  
44              
45 2     2   22 use base qw/WWW::Splunk::API/;
  2         8  
  2         1793  
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 0     0 1   my ($self, $string, $since, $until) = @_;
55              
56 0           delete $self->{last_read};
57              
58             # Format dates
59 0 0 0       ($since, $until) = map { defined $_ ? scalar UnixDate (ParseDate ($_) || $_, '%O') || $_ : undef }
  0            
60             ($since, $until);
61              
62 0 0         if ($self->{search}) {
63 0           $string = 'search '.$string;
64             }
65              
66 0           $self->{results_consumed} = 0;
67 0 0         my $response = $self->post ('/search/jobs', {
    0          
68             search => "$string",
69             (defined $since ? (earliest_time => $since) : ()),
70             (defined $until ? (latest_time => $until) : ()),
71             });
72 0 0 0       die 'Unexpected response format '
73             unless $response and ref $response eq 'XML::LibXML::Document';
74 0           my $sid = $response->findvalue ('/response/sid');
75 0 0         croak 'Bad response' unless defined $sid;
76              
77 0           return $sid;
78             }
79              
80             =head2 B (F) (F) [(F)] [(F)]
81              
82             Initiate a real-time search, calling a callback for each line matched.
83              
84             Finishes only if connection terminates (potentially never), returning number of
85             results consumed.
86              
87             =cut
88              
89             sub rt_search {
90 0     0 1   my ($self, $string, $callback, $since, $until, $counter) = @_;
91              
92 0   0       $since ||= 'rt';
93 0   0       $until ||= 'rt';
94 0   0       $counter ||= 0;
95              
96             $self->post ('/search/jobs/export', {
97             search => "search $string",
98             earliest_time => $since,
99             latest_time => $until,
100             search_mode => 'realtime',
101             }, sub {
102 0     0     $callback->(@_);
103 0           $counter++;
104 0           });
105              
106 0           return $counter;
107             }
108              
109             =head2 B (F)
110              
111             Return true if the search is finished.
112              
113             =cut
114              
115             sub search_done {
116 0     0 1   my ($self, $sid) = @_;
117              
118 0           my $search = $self->get ('/search/jobs/'.$sid);
119              
120 0           return $search->{isDone};
121             }
122              
123             =head2 B (F)
124              
125             Wait for a search to finish.
126              
127             =cut
128              
129             sub poll_search {
130 0     0 1   my ($self, $sid) = @_;
131              
132 0           until ($self->search_done ($sid)) {
133 0           sleep 1;
134             }
135             }
136              
137             =head2 B (F)
138              
139             Return an array of the matched events.
140             If called multiple times, it only returns events which
141             were added from the time of the last call.
142             Oh, and you can't run multiple search concurrently
143             with single L instance. Otherwise,
144             L is perfectly thread-safe.
145              
146             =cut
147              
148             sub search_results {
149 0     0 1   my ($self, $sid) = @_;
150              
151 0           my $done = $self->search_done ($sid);
152             my @results = $self->get ('/search/jobs/'.$sid.'/results?count=1024&offset='.
153 0           $self->{results_consumed});
154 0           $self->{results_consumed} += scalar @results;
155 0 0         $self->{last_read} = scalar @results if $done;
156              
157 0           return @results;
158             }
159              
160             =head2 B (F)
161              
162             Return true if search is finished and all there are no
163             more results to read (everything was fetched with L).
164              
165             =cut
166              
167             sub results_read {
168 0     0 1   my ($self, $sid) = @_;
169              
170 0 0         return undef if not defined $self->{last_read};
171 0           return $self->{last_read} eq 0;
172             }
173              
174             =head1 AUTHORS
175              
176             Lubomir Rintel, L<< >>,
177             Michal Josef Špaček L<< >>
178              
179             The code is hosted on GitHub L.
180             Bug fixes and feature enhancements are always welcome.
181              
182             =head1 LICENSE
183              
184             This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
185              
186             =head1 DONATIONS
187              
188             If you use this library and find it useful, donations are greatly appreciated!
189              
190             =begin text
191              
192             Use https://liberapay.com/skim/donate
193              
194             =end text
195              
196             =begin html
197              
198            
199             Donate using Liberapay
200             src="https://liberapay.com/assets/widgets/donate.svg">
201            
202              
203             =end html
204              
205             =cut
206              
207             1;