File Coverage

blib/lib/Sentry/Client.pm
Criterion Covered Total %
statement 163 190 85.7
branch 11 20 55.0
condition 27 42 64.2
subroutine 30 37 81.0
pod 0 11 0.0
total 231 300 77.0


line stmt bran cond sub pod time code
1             use Mojo::Base -base, -signatures;
2 4     4   260595  
  4         20  
  4         23  
3             use Mojo::Home;
4 4     4   2329 use Mojo::Util 'dumper';
  4         1961  
  4         168  
5 4     4   24 use Sentry::DSN;
  4         8  
  4         124  
6 4     4   1387 use Sentry::Hub::Scope;
  4         19  
  4         27  
7 4     4   942 use Sentry::Integration;
  4         9  
  4         29  
8 4     4   1834 use Sentry::Logger 'logger';
  4         9  
  4         25  
9 4     4   133 use Sentry::SourceFileRegistry;
  4         8  
  4         157  
10 4     4   1492 use Sentry::Stacktrace;
  4         9  
  4         26  
11 4     4   1596 use Sentry::Transport::Http;
  4         11  
  4         24  
12 4     4   1605 use Sentry::Util qw(uuid4 truncate);
  4         14  
  4         99  
13 4     4   161 use Time::HiRes;
  4         9  
  4         181  
14 4     4   75 use Try::Tiny;
  4         7  
  4         38  
15 4     4   360  
  4         8  
  4         7119  
16             has _dsn => sub ($self) { Sentry::DSN->parse($self->_options->{dsn}) };
17             has _options => sub { {} };
18             has _transport =>
19             sub ($self) { Sentry::Transport::Http->new(dsn => $self->_dsn) };
20             has scope => sub { Sentry::Hub::Scope->new };
21             has integrations => sub ($self) { $self->_options->{integrations} // [] };
22              
23             Sentry::Integration->setup($self->integrations);
24 17     17 0 25 }
  17         38  
  17         23  
25 17         54  
26             # (alternatively normal constructor) This takes typically an object with options + dsn.
27              
28             $self, $message,
29 0     0 0 0 $level = Sentry::Severity->Info,
  0         0  
  0         0  
30             $hint = undef
31             ) {
32 13         39 my %event = (
  13         16  
33 13         21 event_id => $hint && $hint->{event_id},
34             level => $level,
35 13     13 0 1395 message => $message,
  13         16  
  13         17  
36             );
37              
38 13   66     97 return \%event;
39             }
40              
41             $self, $message,
42 13         31 $level = undef,
43             $hint = undef,
44             $scope = undef
45             ) {
46 11         17 my $event = $self->event_from_message($message, $level, $hint);
  11         26  
47 11         72  
48 11         18 return $self->_capture_event($event, $hint, $scope);
49             }
50 11     11 0 3298  
  11         14  
  11         15  
51 11         28 my $event_id = ($hint // {})->{event_id};
52              
53 11         35 return $self->_capture_event($event, $hint, $scope);
54             }
55              
56 8     8 0 11 return $self->_source_file_registry->get_context_lines($file, $line);
  8         12  
  8         10  
  8         19  
  8         12  
  8         9  
57 8   50     35 }
58              
59 8         34 return scalar $frame->filename !~ m{\A /}xms;
60             }
61              
62 0     0   0  
  0         0  
  0         0  
  0         0  
  0         0  
63 0         0 if (!ref($exception)) {
64             $exception = Mojo::Exception->new($exception)->trace;
65             }
66 0     0 0 0  
  0         0  
  0         0  
67 0         0 my $stacktrace = Sentry::Stacktrace->new({
68             exception => $exception,
69             frame_filter => sub ($frame) {
70 0 0   0   0 index($frame->package, 'Sentry') == -1
71             && $frame->package !~ m{(Class::MOP|CGI::Carp|Try::Tiny)}xms;
72 1     1 0 4 },
  1         2  
  1         3  
  1         2  
  1         3  
  1         3  
73 1 50       5 });
74 0         0  
75             return {
76             event_id => $hint && $hint->{event_id},
77 0         0 level => Sentry::Severity->Error,
78             exception => {
79 0     0   0 values => [{
  0         0  
80 0 0       0 type => ref($exception),
81             value => $exception->can('to_string')
82             ? $exception->to_string
83 1         23 : $exception,
84             module => ref($exception),
85             stacktrace => $stacktrace,
86             }]
87 1 50 33     57 }
88             };
89             }
90              
91             my $event = $self->event_from_exception($exception, $hint);
92              
93             return $self->_capture_event($event, $hint, $scope);
94             }
95              
96             my $event_id;
97              
98             try {
99             $event_id = $self->_process_event($event, $hint, $scope)->{event_id};
100             } catch {
101 1     1 0 2 logger->error($_);
  1         2  
  1         3  
  1         2  
  1         2  
  1         2  
102 1         21 };
103              
104 1         47 return $event_id;
105             }
106              
107 20     20   33 # Captures the event by merging it with other data with defaults from the
  20         23  
  20         30  
  20         27  
  20         25  
  20         28  
108 20         22 # client. In addition, if a scope is passed to this system, the data from the
109             # scope passes it to the internal transport.
110             # sub capture_event ($self, $event, $scope) { }
111 20     20   887  
112             # Flushes out the queue for up to timeout seconds. If the client can guarantee
113 1     1   17 # delivery of events only up to the current point in time this is preferred.
114 20         125 # This might block for timeout seconds. The client should be disabled or
115             # disposed after close is called
116 20         381  
117             # Same as close difference is that the client is NOT disposed after calling flush
118              
119             # Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
120             # Normalized keys:
121             # - `breadcrumbs.data`
122             # - `user`
123             # - `contexts`
124             # - `extra`
125             my %normalized = ($event->%*,);
126             return \%normalized;
127             }
128 0     0 0 0  
  0         0  
  0         0  
129             my $options = $self->_options;
130             my $max_value_length = $options->{max_value_length} // 250;
131 0     0 0 0  
  0         0  
  0         0  
132             $event->{environment} //= $options->{environment} // 'production';
133             $event->{dist} //= $options->{dist};
134             $event->{release} //= $options->{release} if $options->{release};
135              
136             $event->{message} = truncate($event->{message}, $max_value_length)
137             if $event->{message};
138              
139 20     20   32 return;
  20         28  
  20         24  
  20         24  
140 20         183 }
141 20         84  
142             return $self->_options;
143             }
144 20     20   29  
  20         27  
  20         36  
  20         24  
145 20         47 $event->{sdk} //= {};
146 20   50     119  
147             my @integrations = $self->integrations->@*;
148 20   50     121 $event->{sdk}->{integrations} = [map { ref($_) } @integrations]
      33        
149 20   33     82 if @integrations;
150 20 50 0     43 }
151              
152             # Adds common information to events.
153 20 100       77 #
154             # The information includes release and environment from `options`,
155 20         34 # breadcrumbs and context (extra, tags and user) from the scope.
156             #
157             # Information that is already present in the event is never overwritten. For
158 11     11 0 205 # nested objects, such as the context, keys are merged.
  11         15  
  11         16  
159 11         37 #
160             # @param event The original event.
161             # @param hint May contain additional information about the original exception.
162 20     20   24 # @param scope A scope containing event metadata.
  20         27  
  20         27  
  20         40  
163 20   100     59 # @returns A new event with more information.
164             my %prepared = (
165 20         48 $event->%*,
166 20 50       116 sdk => $self->_options->{_metadata}{sdk},
  0         0  
167             platform => 'perl',
168             event_id => $event->{event_id} // ($hint // {})->{event_id} // uuid4(),
169             timestamp => $event->{timestamp} // time,
170             );
171              
172             $self->_apply_client_options(\%prepared);
173             $self->_apply_integrations_metadata(\%prepared);
174              
175             # If we have scope given to us, use it as the base for further modifications.
176             # This allows us to prevent unnecessary copying of data if `capture_context`
177             # is not provided.
178             my $final_scope = $scope;
179             if (($hint // {})->{capture_context}) {
180             $final_scope = $scope->clone()->update($hint->{capture_context});
181             }
182 20     20   25  
  20         28  
  20         30  
  20         24  
  20         29  
  20         28  
183             # We prepare the result here with a resolved Event.
184             my $result = \%prepared;
185             # This should be the last thing called, since we want that
186             # {@link Hub.addEventProcessor} gets the finished prepared event.
187             if ($final_scope) {
188              
189 20   100     89 # In case we have a hub we reassign it.
      100        
      66        
      66        
190             $result = $final_scope->apply_to_event(\%prepared, $hint);
191 20         316 }
192 20         67  
193             return $self->_normalize_event($result);
194             }
195              
196             my $prepared = $self->_prepare_event($event, $scope, $hint);
197 20         38  
198 20 50 100     68 my $is_transaction = ($event->{type} // '') eq 'transaction';
199 0         0  
200             my $before_send = $self->_options->{before_send}
201             // sub ($event, $hint) {$event};
202              
203 20         30 my $processed_event = $before_send->($prepared, $hint // {});
204              
205             die 'An event processor returned undef, will not send event.'
206 20 100       51 unless $processed_event;
207              
208             $self->_send_event($processed_event);
209 17         63  
210             return $processed_event;
211             }
212 20         65  
213             $self->_transport->send($event);
214             return;
215 20     20   28 }
  20         28  
  20         29  
  20         25  
  20         27  
  20         25  
216 20         57  
217             1;
218 20   100     83