File Coverage

blib/lib/Log/Any/Adapter/Sentry/Raven.pm
Criterion Covered Total %
statement 49 49 100.0
branch 14 16 87.5
condition 7 9 77.7
subroutine 11 11 100.0
pod 0 2 0.0
total 81 87 93.1


line stmt bran cond sub pod time code
1             package Log::Any::Adapter::Sentry::Raven;
2              
3             # ABSTRACT: Log::Any::Adapter for Sentry::Raven
4 2     2   129636 use version;
  2         4357  
  2         12  
5             our $VERSION = 'v0.0.2'; # VERSION
6              
7             #pod =head1 SYNPOSIS
8             #pod
9             #pod use Log::Any::Adapter;
10             #pod Log::Any::Adapter->set('Sentry::Raven',
11             #pod sentry => Sentry::Raven->new(
12             #pod sentry_dsn => $dsn,
13             #pod environment => 'production',
14             #pod ...
15             #pod )
16             #pod );
17             #pod
18             #pod =head1 DESCRIPTION
19             #pod
20             #pod This is a backend to L<Log::Any> for L<Sentry::Raven>.
21             #pod
22             #pod It takes two arguments:
23             #pod
24             #pod =over
25             #pod
26             #pod =item sentry (REQUIRED)
27             #pod
28             #pod An instantiated L<Sentry::Raven> object.
29             #pod Note that if you set any sentry-specific context directly through the sentry
30             #pod object, it will be picked up here eg.
31             #pod
32             #pod $sentry->add_context( Sentry::Raven->request_context($url, %p) )
33             #pod
34             #pod If L<Devel::StackTrace> is installed, this will add a stack trace for you
35             #pod (As of writing, L<Sentry::Raven> requires it, so it will be).
36             #pod
37             #pod =item log_level (OPTIONAL)
38             #pod
39             #pod The minimum log_level to log. Defaults to C<trace> (everything).
40             #pod
41             #pod =back
42             #pod
43             #pod Any L<Log::Any/Log context data> will be sent to Sentry as tags.
44             #pod
45             #pod =head1 SEE ALSO
46             #pod
47             #pod L<Log::Any>, L<Sentry::Raven>
48             #pod
49             #pod =cut
50              
51 2     2   205 use strict;
  2         4  
  2         41  
52 2     2   9 use warnings;
  2         5  
  2         54  
53              
54 2     2   10 use Carp qw(carp croak);
  2         3  
  2         112  
55 2     2   14 use Log::Any::Adapter::Util qw(make_method numeric_level);
  2         3  
  2         125  
56 2     2   16 use Scalar::Util qw(blessed);
  2         4  
  2         91  
57 2     2   613 use Sentry::Raven;
  2         151615  
  2         72  
58              
59 2     2   13 use base qw(Log::Any::Adapter::Base);
  2         5  
  2         1331  
60              
61             sub init {
62 8     8 0 9553 my $self = shift;
63              
64 8         35 my $sentry = $self->{sentry};
65 8 100 100     310 croak "An initialized Sentry::Raven object must be passed as the 'sentry' arg"
66             unless blessed($sentry) && $sentry->isa('Sentry::Raven');
67              
68             # copied from Log::Any::Adapter::Stderr
69 6 100 100     178 if ( exists $self->{log_level} && $self->{log_level} =~ /\D/ ) {
70 4         21 my $numeric_level = numeric_level( $self->{log_level} );
71 4 100       42 if ( !defined($numeric_level) ) {
72 1         192 carp( sprintf 'Invalid log level "%s". Defaulting to "%s"', $self->{log_level}, 'trace' );
73             }
74 4         135 $self->{log_level} = $numeric_level;
75             }
76 6 100       24 if ( !defined $self->{log_level} ) {
77 2         11 $self->{log_level} = numeric_level('trace');
78             }
79             }
80              
81             my $Include_Stack_Trace = do { eval { require Devel::StackTrace; 1 } };
82             sub structured {
83 3     3 0 98 my ($self, $level, $category, @log_args) = @_;
84              
85 3         10 my $is_level = "is_$level";
86 3 50       11 return unless $self->$is_level;
87              
88 3         7 my $log_any_context = {};
89 3 100       13 if ((ref $log_args[-1]) eq 'HASH') {
90 1         3 $log_any_context = pop @log_args;
91             }
92              
93 3         10 my $log_message = join "\n" => @log_args;
94              
95 3         6 my $sentry_severity = $level;
96 3         7 for ($sentry_severity) {
97 3 50 33     35 s/trace/debug/ or
98             s/notice/info/ or
99             s/critical|alert|emergency/fatal/
100             }
101              
102 3         9 my @message_args = (
103             $log_message,
104             level => $sentry_severity,
105             tags => $log_any_context,
106             );
107 3 100       10 if ($Include_Stack_Trace) {
108 2         15 push @message_args,
109             Sentry::Raven->stacktrace_context(Devel::StackTrace->new)
110             }
111              
112             # https://docs.sentry.io/data-management/event-grouping/
113 3         5160 $self->{sentry}->capture_message( @message_args );
114             }
115              
116             for my $method ( Log::Any->detection_methods() ) {
117             my $method_base = substr($method, 3); # chop of is_
118             my $method_level = numeric_level($method_base);
119             make_method(
120             $method,
121 14     14   4371 sub { return $method_level <= $_[0]->{log_level} },
122             );
123             }
124              
125             1;
126              
127             __END__
128              
129             =pod
130              
131             =encoding UTF-8
132              
133             =head1 NAME
134              
135             Log::Any::Adapter::Sentry::Raven - Log::Any::Adapter for Sentry::Raven
136              
137             =head1 VERSION
138              
139             version v0.0.2
140              
141             =head1 DESCRIPTION
142              
143             This is a backend to L<Log::Any> for L<Sentry::Raven>.
144              
145             It takes two arguments:
146              
147             =over
148              
149             =item sentry (REQUIRED)
150              
151             An instantiated L<Sentry::Raven> object.
152             Note that if you set any sentry-specific context directly through the sentry
153             object, it will be picked up here eg.
154              
155             $sentry->add_context( Sentry::Raven->request_context($url, %p) )
156              
157             If L<Devel::StackTrace> is installed, this will add a stack trace for you
158             (As of writing, L<Sentry::Raven> requires it, so it will be).
159              
160             =item log_level (OPTIONAL)
161              
162             The minimum log_level to log. Defaults to C<trace> (everything).
163              
164             =back
165              
166             Any L<Log::Any/Log context data> will be sent to Sentry as tags.
167              
168             =head1 SYNPOSIS
169              
170             use Log::Any::Adapter;
171             Log::Any::Adapter->set('Sentry::Raven',
172             sentry => Sentry::Raven->new(
173             sentry_dsn => $dsn,
174             environment => 'production',
175             ...
176             )
177             );
178              
179             =head1 SEE ALSO
180              
181             L<Log::Any>, L<Sentry::Raven>
182              
183             =head1 AUTHOR
184              
185             Grant Street Group <developers@grantstreet.com>
186              
187             =head1 COPYRIGHT AND LICENSE
188              
189             This software is Copyright (c) 2019 - 2020 by Grant Street Group.
190              
191             This is free software, licensed under:
192              
193             The Artistic License 2.0 (GPL Compatible)
194              
195             =cut