File Coverage

blib/lib/Log/Sentry.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Log::Sentry;
2              
3             =head1 NAME
4              
5             Log::Sentry - sending log messages to Sentry.
6              
7             =cut
8              
9             our $VERSION = '0.01';
10              
11              
12             =head1 SYNOPSIS
13              
14              
15             my $raven = Log::Sentry->new(
16             sentry_public_key => "public",
17             sentry_secret_key => "secret",
18             remote_url => "sentry url"
19             );
20              
21              
22             $raven->message({ message => "Panic!" });
23              
24             =head1 EXPORT
25              
26              
27             =cut
28              
29 1     1   22565 use strict;
  1         2  
  1         49  
30 1     1   6 use warnings;
  1         2  
  1         35  
31              
32 1     1   170366 use HTTP::Request::Common;
  1         1215108  
  1         91  
33 1     1   1132 use LWP::UserAgent;
  1         462158  
  1         33  
34 1     1   385 use JSON;
  0            
  0            
35             use MIME::Base64 'encode_base64';
36             use Time::HiRes (qw(gettimeofday));
37             use DateTime;
38             use Sys::Hostname;
39              
40             =head4 new
41              
42             Constructor. Use like:
43              
44             my $raven = Log::Sentry->new(
45             sentry_public_key => "public",
46             sentry_secret_key => "secret",
47             remote_url => "sentry url",
48             sentry_version => 3 # can be omitted
49             );
50              
51             =cut
52             sub new {
53             my ( $class, %options ) = @_;
54              
55             foreach (qw(sentry_public_key sentry_secret_key remote_url)) {
56             if (!exists $options{$_}) {
57             die "Mandatory paramter '$_' not defined";
58             }
59             }
60            
61             my $self = {
62             ua => LWP::UserAgent->new(),
63             %options,
64             };
65              
66             $self->{'sentry_version'} ||= 3;
67              
68             bless $self, $class;
69             }
70              
71             =head4 message
72              
73             Send message to Sentry server.
74              
75             $raven->message( {
76             'message' => "Message",
77             'logger' => "Name of the logger", # defult "root"
78             'level' => "Error level", # default 'error'
79             'platform' => "Platform name", # default 'perl',
80             'culprit' => "Module or/and function raised error", # default ""
81             'tags' => "Arrayref of tags", # default []
82             'server_name' => "Server name where error occured", # current host name is default
83             'modules' => "list of relevant modules",
84             'extra' => "extra params described below"
85             } );
86              
87             The structure of 'modules' list is:
88              
89             [
90             {
91             "my.module.name": "1.0"
92             }
93             ]
94              
95             The structure of 'extra' field is:
96              
97             {
98             "my_key" => 1,
99             "some_other_value" => "foo bar"
100             }
101              
102              
103             =cut
104             sub message {
105             my ( $self, $params ) = @_;
106            
107             my $message = $self->buildMessage( $params );
108             my $stamp = gettimeofday();
109             $stamp = sprintf ( "%.12g", $stamp );
110              
111             my $header_format = sprintf (
112             "Sentry sentry_version=%s, sentry_timestamp=%s, sentry_key=%s, sentry_client=%s, sentry_secret=%s",
113             $self->{sentry_version},
114             time(),
115             $self->{'sentry_public_key'},
116             "perl_client/0.02",
117             $self->{'sentry_secret_key'},
118             );
119             my %header = ( 'X-Sentry-Auth' => $header_format );
120              
121             my $request = POST($self->{remote_url}, %header, Content => $message);
122             my $response = $self->{'ua'}->request( $request );
123              
124             return $response;
125             }
126              
127              
128             sub buildMessage {
129             my ( $self, $params ) = @_;
130            
131             my $data = {
132             'event_id' => sprintf("%x%x%x", time(), time() + int(rand()), time() + int(rand())),
133             'message' => $params->{'message'},
134             'timestamp' => time(),
135             'level' => $params->{'level'} || 'error',
136             'logger' => $params->{'logger'} || 'root',
137             'platform' => $params->{'platform'} || 'perl',
138             'culprit' => $params->{'culprit'} || "",
139             'tags' => $params->{'tags'} || [],
140             'server_name' => $params->{server_name}||hostname,
141             'modules' => $params->{'modules'},
142             'extra' => $params->{'extra'} || {}
143             };
144              
145             my $json = JSON->new->utf8(1)->pretty(1)->allow_nonref(1);
146             return $json->encode( $data );
147             }
148              
149             1;
150              
151             =head1 LICENSE AND COPYRIGHT
152              
153             Copyright 2013 Danil Orlov.
154              
155             This program is free software; you can redistribute it and/or modify it
156             under the terms of the the Artistic License (2.0). You may obtain a
157             copy of the full license at:
158              
159             L