File Coverage

blib/lib/Splunk/HEC.pm
Criterion Covered Total %
statement 21 55 38.1
branch 0 24 0.0
condition 0 12 0.0
subroutine 7 10 70.0
pod 2 2 100.0
total 30 103 29.1


line stmt bran cond sub pod time code
1             package Splunk::HEC;
2 1     1   73823 use Carp;
  1         17  
  1         67  
3 1     1   411 use JSON::XS;
  1         7346  
  1         81  
4 1     1   580 use HTTP::Tiny;
  1         46447  
  1         60  
5 1     1   492 use Splunk::Base -base;
  1         4  
  1         8  
6 1     1   368 use Splunk::HEC::Request;
  1         4  
  1         13  
7 1     1   395 use Splunk::HEC::Response;
  1         3  
  1         11  
8 1     1   9 use strict;
  1         3  
  1         1064  
9              
10             our $VERSION = '1.02';
11              
12             has url => sub { return $ENV{SPLUNK_HEC_URL} || 'http://localhost:8088/services/collector'; };
13             has token => sub { return $ENV{SPLUNK_HEC_TOKEN} || '' };
14             has agent => sub { return $ENV{SPLUNK_HEC_AGENT} || "perl-splunk-hec/$VERSION"; };
15             has timeout => sub { return $ENV{SPLUNK_HEC_TIMEOUT} || 60 };
16             has max_retries => 0;
17              
18             sub client {
19 0     0 1   my $self = shift;
20 0           my %args = @_;
21 0 0         return $self->{_client} if $self->{_client};
22              
23             my %options = (
24             agent => $args{agent} || $self->agent,
25 0   0       timeout => $args{timeout} || $self->timeout,
      0        
26             default_headers => {'Content-Type' => 'application/json'}
27             );
28              
29 0 0         Carp::croak('A valid Splunk HEC token is required for authentication') unless $self->token;
30              
31 0           $options{default_headers}->{'Authorization'} = join(' ', 'Splunk', $self->token);
32              
33 0           return $self->{_client} = HTTP::Tiny->new(%options);
34             }
35              
36             # These keys are all optional. Any key-value pairs that are not included in the event will be set to values defined for the token on the Splunk server.
37             # "time" The event time. The default time format is epoch time format, in the format .. For example, 1433188255.500 indicates 1433188255 seconds and 500 milliseconds after epoch, or Monday, June 1, 2015, at 7:50:55 PM GMT.
38             # "host" The host value to assign to the event data. This is typically the hostname of the client from which you're sending data.
39             # "source" The source value to assign to the event data. For example, if you're sending data from an app you're developing, you could set this key to the name of the app.
40             # "sourcetype" The sourcetype value to assign to the event data.
41             # "index" The name of the index by which the event data is to be indexed. The index you specify here must within the list of allowed indexes if the token has the indexes parameter set.
42             # "fields" (Not applicable to raw data.) Specifies a JSON object that contains explicit custom fields to be defined at index time. Requests containing the "fields" property must be sent to the /collector/event endpoint, or they will not be indexed. For more information, see Indexed field extractions.
43              
44             sub send {
45 0     0 1   my $self = shift;
46 0 0         Carp::croak('At least one Splunk HEC event is required.') unless @_;
47              
48             # a couple ways to call send
49             # NOTE: Only event is required
50             # HASH - (single event) send(event => {}, time => $epoch, source => 'datasource', sourcetype => '', index => 'data-index', fields...)
51             # ARRAY - (many events) send({}, {}, {})
52             # ARRAYREF - (many events) send([{}, {}, {}])
53 0           my @requests = ();
54              
55 0 0         if (@_ > 1) {
    0          
    0          
56              
57             # array of objects
58 0 0         if (ref($_[0]) eq 'HASH') {
59 0           map { push(@requests, Splunk::HEC::Request->new(%{$_})); } @_;
  0            
  0            
60             }
61             else {
62 0           push(@requests, Splunk::HEC::Request->new(@_));
63             }
64             }
65             elsif (ref($_[0]) eq 'HASH') {
66 0           push(@requests, Splunk::HEC::Request->new(%{$_[0]}));
  0            
67             }
68             elsif (ref($_[0]) eq 'ARRAY') {
69 0           map { push(@requests, Splunk::HEC::Request->new(%{$_})); } @{$_[0]};
  0            
  0            
  0            
70             }
71              
72             my $response = $self->client()->post(
73             $self->url => {
74             content => sub {
75 0 0   0     return unless @requests;
76 0           my $req = shift @requests;
77 0 0         return unless $req;
78 0           my $json = JSON::XS->new->convert_blessed(1)->encode($req);
79 0 0         return (@requests) ? $json . "\n" : $json;
80             }
81             }
82 0           );
83              
84 0 0         return Splunk::HEC::Response->new(success => 0, code => 500, reason => 'Unknown Server Error')
85             unless $response;
86              
87 0           my $content_type = $response->{headers}->{'content-type'};
88 0 0 0       if ($response && $response->{content} && $content_type =~ /json/i) {
      0        
89 0           $response->{content} = JSON::XS::decode_json($response->{content});
90             }
91              
92 0           return Splunk::HEC::Response->new(%{$response});
  0            
93             }
94              
95             1;
96              
97             =encoding utf8
98              
99             =head1 NAME
100              
101             Splunk::HEC - A simple wrapper for the Splunk HTTP Event Collector (HEC) API
102              
103             =head1 SYNOPSIS
104              
105             use Splunk::HEC;
106              
107             my $hec = Splunk::HEC->new(
108             url => 'https://mysplunkserver.example.com:8088/services/collector/event',
109             token => '12345678-1234-1234-1234-1234567890AB'
110             );
111              
112             my $res = $hec->send(event => {message => 'Something happened', severity => 'INFO'});
113             if ($res->is_success) { say $res->content }
114             elsif ($res->is_error) { say $res->reason }
115              
116             =head1 DESCRIPTION
117              
118             L is a simple HTTP client wrapper for the Splunk HEC API;
119              
120             =head1 ATTRIBUTES
121              
122             L implements the following attributes.
123              
124             =head2 url
125              
126             my $url = $hec->url;
127             $url = $hec->url('https://mysplunkserver.example.com:8088/services/collector/event');
128              
129             Full URL to Splunk HEC endpoint (required).
130              
131             =head2 token
132              
133             my $token = $hec->token;
134             $token = $hec->token('12345678-1234-1234-1234-1234567890AB');
135              
136             Splunk HEC authentication token (required)
137              
138             =head2 timeout
139              
140             my $timeout = $hec->timeout;
141             $timeout = $hec->timeout(300);
142              
143             Timeout in seconds when talking to Splunk HEC. (optional, default 60s)
144              
145             =head1 METHODS
146              
147             L implements the following methods.
148              
149             =head2 new
150              
151             my $hec = Splunk::HEC->new;
152             my $hec = Splunk::HEC->new(url => 'value', token => 'value');
153             my $hec = Splunk::HEC->new({name => 'value'});
154              
155             This is the constructor used to create the Splunk::HEC object. You can
156             pass it either a hash or a hash reference with attribute values.
157              
158             =head2 send
159              
160             # single event
161             $res = $hec->send(event => 'event1', time => $epoch, source => 'datasource', sourcetype => '', index => 'data-index');
162              
163             # multiple events (array of hashrefs)
164             $res = $hec->send(
165             {event => 'event1', time => $epoch, source => 'datasource', sourcetype => '', index => 'data-index'},
166             {event => 'event2', time => $epoch, source => 'datasource', sourcetype => '', index => 'data-index'}
167             );
168              
169             Send one or more events to HEC. If multiple events are provided at once, they
170             are sent using HEC batch mode. Passed events are converted into L
171             objects prior to being encoded and sent. Once HEC responds, it returns a
172             L object.
173              
174             See the attributes of L for supported event attributes and default
175             settings.
176              
177             =head2 client
178              
179             my $hec = Splunk::HEC->new;
180             my $client = $hec->client;
181              
182             Returns the HTTP client
183              
184             =head1 ENVIRONMENT VARIABLES
185              
186             L provides configuration via the following environment variables.
187              
188             =head2 SPLUNK_HEC_URL
189              
190             Full URL to Splunk HEC endpoint (required).
191              
192             =head2 SPLUNK_HEC_TOKEN
193              
194             Splunk HEC authentication token (required)
195              
196             =head2 SPLUNK_HEC_TIMEOUT
197              
198             Timeout in seconds when talking to Splunk HEC. (optional, default 60s)
199              
200             =head1 SEE ALSO
201              
202             L, L, L, L, L
203              
204             =cut