File Coverage

blib/lib/Sentry/Client.pm
Criterion Covered Total %
statement 162 189 85.7
branch 11 20 55.0
condition 25 40 62.5
subroutine 30 37 81.0
pod 0 11 0.0
total 228 297 76.7


line stmt bran cond sub pod time code
1             use Mojo::Base -base, -signatures;
2 4     4   250275  
  4         15  
  4         24  
3             use Mojo::Home;
4 4     4   2329 use Mojo::Util 'dumper';
  4         1839  
  4         162  
5 4     4   21 use Sentry::DSN;
  4         7  
  4         121  
6 4     4   1373 use Sentry::Hub::Scope;
  4         9  
  4         27  
7 4     4   875 use Sentry::Integration;
  4         10  
  4         25  
8 4     4   1648 use Sentry::Logger 'logger';
  4         10  
  4         21  
9 4     4   126 use Sentry::SourceFileRegistry;
  4         7  
  4         146  
10 4     4   1386 use Sentry::Stacktrace;
  4         8  
  4         25  
11 4     4   1517 use Sentry::Transport::Http;
  4         9  
  4         23  
12 4     4   1552 use Sentry::Util qw(uuid4 truncate);
  4         16  
  4         32  
13 4     4   192 use Time::HiRes;
  4         10  
  4         174  
14 4     4   21 use Try::Tiny;
  4         61  
  4         27  
15 4     4   365  
  4         6  
  4         6728  
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 24 }
  17         24  
  17         19  
25 17         58  
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         20 my %event = (
  13         18  
33 13         20 event_id => $hint && $hint->{event_id},
34             level => $level,
35 13     13 0 1360 message => $message,
  13         20  
  13         16  
36             );
37              
38 13   66     79 return \%event;
39             }
40              
41             $self, $message,
42 13         43 $level = undef,
43             $hint = undef,
44             $scope = undef
45             ) {
46 11         21 my $event = $self->event_from_message($message, $level, $hint);
  11         14  
47 11         15  
48 11         70 return $self->_capture_event($event, $hint, $scope);
49             }
50 11     11 0 3526  
  11         20  
  11         13  
51 11         32 my $event_id = ($hint // {})->{event_id};
52              
53 11         35 return $self->_capture_event($event, $hint, $scope);
54             }
55              
56 8     8 0 14 return $self->_source_file_registry->get_context_lines($file, $line);
  8         9  
  8         12  
  8         12  
  8         11  
  8         9  
57 8   50     22 }
58              
59 8         21 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 3 },
  1         2  
  1         1  
  1         2  
  1         2  
  1         1  
73 1 50       4 });
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         13 : $exception,
84             module => ref($exception),
85             stacktrace => $stacktrace,
86             }]
87 1 50 33     29 }
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         2  
  1         2  
  1         13  
  1         2  
102 1         4 };
103              
104 1         34 return $event_id;
105             }
106              
107 20     20   28 # Captures the event by merging it with other data with defaults from the
  20         26  
  20         31  
  20         27  
  20         26  
  20         26  
108 20         30 # 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   906  
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         123 # This might block for timeout seconds. The client should be disabled or
115             # disposed after close is called
116 20         425  
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   29 return;
  20         23  
  20         24  
  20         20  
140 20         135 }
141 20         74  
142             return $self->_options;
143             }
144 20     20   31  
  20         28  
  20         22  
  20         24  
145 20         43 $event->{sdk} //= {};
146 20   50     115  
147             my @integrations = $self->integrations->@*;
148 20   50     118 $event->{sdk}->{integrations} = [map { ref($_) } @integrations]
      33        
149 20   33     82 if @integrations;
150 20 50 0     51 }
151              
152             # Adds common information to events.
153 20 100       67 #
154             # The information includes release and environment from `options`,
155 20         30 # 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 200 # nested objects, such as the context, keys are merged.
  11         17  
  11         14  
159 11         27 #
160             # @param event The original event.
161             # @param hint May contain additional information about the original exception.
162 20     20   25 # @param scope A scope containing event metadata.
  20         25  
  20         23  
  20         22  
163 20   100     45 # @returns A new event with more information.
164             my %prepared = (
165 20         47 $event->%*,
166 20 50       114 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 (exists(($hint // {})->{capture_context})) {
180             $final_scope = $scope->clone()->update($hint->{captureconsole});
181             }
182 20     20   24  
  20         31  
  20         28  
  20         23  
  20         25  
  20         22  
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     86 # In case we have a hub we reassign it.
      100        
      66        
      66        
190             $result = $final_scope->apply_to_event(\%prepared, $hint);
191 20         252 }
192 20         51  
193             return $self->_normalize_event($result);
194             }
195              
196             my $prepared = $self->_prepare_event($event, $scope, $hint);
197 20         27  
198 20 50 100     59 my $is_transaction = ($event->{type} // '') eq 'transaction';
199 0         0  
200             my $before_send = $self->_options->{before_send} // sub ($event) {$event};
201             my $processed_event = $before_send->($prepared);
202              
203 20         30 die 'An event processor returned undef, will not send event.'
204             unless $processed_event;
205              
206 20 100       50 $self->_send_event($processed_event);
207              
208             return $processed_event;
209 17         53 }
210              
211             $self->_transport->send($event);
212 20         50 return;
213             }
214              
215 20     20   29 1;
  20         23  
  20         24  
  20         27  
  20         23  
  20         25  
216 20         47