File Coverage

blib/lib/PerlGuard/Agent.pm
Criterion Covered Total %
statement 14 87 16.0
branch 0 40 0.0
condition 0 12 0.0
subroutine 5 14 35.7
pod 0 8 0.0
total 19 161 11.8


line stmt bran cond sub pod time code
1             package PerlGuard::Agent;
2 1     1   22830 use 5.010001;
  1         3  
3 1     1   164525 use Moo;
  1         20637  
  1         6  
4 1     1   2675 use PerlGuard::Agent::Profile;
  1         4  
  1         38  
5 1     1   8 use Scalar::Util;
  1         2  
  1         57  
6 1     1   1172 use Data::UUID;
  1         191476  
  1         2019  
7              
8             our @ISA = qw();
9             our $VERSION = '0.11';
10              
11             has output_method => ( is => 'rw', lazy => 1, default => sub { 'PerlGuard::Agent::Output::PerlGuardServer' } );
12             has output => (is => 'lazy' );
13              
14             has profiles => ( is => 'rw', default => sub { {} });
15             has monitors => ( is => 'rw', default => sub { [] });
16              
17             has async_mode => (is => 'rw', default => sub { 0 });
18             has api_key => (is => 'rw');
19              
20             has data_uuid => (is => 'ro', default => sub { Data::UUID->new });
21              
22             has warnings => (is => 'rw', default => sub { 0 });
23              
24             our $CURRENT_PROFILE_UUID = undef;
25              
26             # Current profile only makes sense in a sync app which can only have one request running at a time
27             # Alternatively it could be used with a local statment elsewhere in an async app to make use of lexical scoping
28             sub current_profile {
29 0     0 0   my $self = shift;
30              
31 0 0         warn "current_profile is meaningless when running in async mode" if $self->async_mode();
32              
33             #Check if $CURRENT_PROFILE has a value in is
34 0 0         if(defined $CURRENT_PROFILE_UUID) {
35 0 0         if($self->profiles->{$CURRENT_PROFILE_UUID}) {
36 0 0         if($self->warnings) {
37 0 0         warn "Profile identified has finished, this should not happen" if $self->profiles->{$CURRENT_PROFILE_UUID}->has_finished();
38             }
39 0           return $self->profiles->{$CURRENT_PROFILE_UUID};
40             }
41             else {
42 0 0         if($self->warnings) {
43 0           warn "the package variable CURRENT_PROFILE_UUID is not defined, this is potentially a race condition bug";
44             }
45             }
46             }
47             else {
48 0 0         if($self->warnings) {
49 0           warn "Using fallback mechanism to identify profile";
50             }
51              
52             # This is not safe, as we could get monitors reporting on the wrong profile
53 0           my @uuids = keys %{ $self->profiles };
  0            
54 0 0         if(scalar(@uuids) == 1) {
55 0           return $self->profiles->{$uuids[0]};
56             }
57             else {
58 0 0         if($self->warnings) {
59 0           warn "Could not identify the most recent profile, we had " . scalar(@uuids) . " profiles currently active with keys @uuids and the current profile var thinks its " . $CURRENT_PROFILE_UUID ;
60             }
61 0           return;
62             }
63             }
64              
65             }
66              
67             sub _build_output {
68 0     0     my $self = shift;
69              
70 0           my $output_method = $self->output_method();
71 0           eval "require $output_method";
72 0 0         die "Cannot require module $output_method, perhaps you specified an invalid module name in output_method" if $@;
73              
74 0           my @params;
75 0 0         push(@params, api_key => $self->api_key) if($self->api_key);
76              
77 0           return $output_method->new( @params );
78             }
79              
80              
81             # This supports a transaction being added for a specific profile, which is a future feature we will need to support async apps
82             # For now though when this is called there should only ever be one profile in process (sync app)
83             sub add_database_transaction {
84 0     0 0   my $self = shift;
85 0           my $database_transaction = shift;
86 0           my $intended_profile_uuid = shift;
87              
88 0 0 0       if($intended_profile_uuid and (my $profile = $self->profiles->{$intended_profile_uuid})) {
89 0           $profile->add_database_transaction($database_transaction);
90             } else {
91             # Profile not specified! Time to guess
92              
93 0           my $current_profile = $self->current_profile;
94 0 0 0       if($current_profile && Scalar::Util::blessed($current_profile)) {
95 0           $current_profile->add_database_transaction($database_transaction);
96             }
97             else {
98 0 0         if($self->warnings) {
99 0           warn "Caught a database transaction occuring outside of a profile";
100             }
101             }
102            
103            
104             }
105             }
106              
107             sub add_webservice_transaction {
108 0     0 0   my $self = shift;
109 0           my $web_transaction = shift;
110 0           my $intended_profile_uuid = shift;
111              
112 0 0 0       if($intended_profile_uuid and (my $profile = $self->profiles->{$intended_profile_uuid})) {
113 0           $profile->add_webservice_transaction($web_transaction);
114             } else {
115             # Profile not specified
116 0           my $current_profile = $self->current_profile;
117 0 0 0       if($current_profile && Scalar::Util::blessed($current_profile)) {
118 0           $current_profile->add_webservice_transaction($web_transaction);;
119             }
120             else {
121 0 0         if($self->warnings) {
122 0           warn "Caught a web transaction occuring outside of a profile"
123             }
124             }
125             }
126              
127             }
128              
129             sub create_new_profile {
130 0     0 0   my $self = shift;
131              
132 0           my $profile = PerlGuard::Agent::Profile->new({
133             # Set some things
134             uuid => $self->data_uuid->create_str(),
135             agent => $self
136             });
137              
138 0           $self->profiles->{$profile->uuid} = $profile;
139 0           Scalar::Util::weaken($self->profiles->{$profile->uuid});
140              
141 0           return $profile;
142             }
143              
144             sub remove_profile {
145 0     0 0   my $self = shift;
146 0           my $profile_id = shift;
147 0 0         $profile_id = $profile_id->uuid() if Scalar::Util::blessed($profile_id);
148              
149 0           delete $self->profiles->{$profile_id};
150             }
151              
152             sub detect_monitors {
153 0     0 0   my $self = shift;
154              
155 0           foreach my $monitor(qw( PerlGuard::Agent::Monitors::DBI PerlGuard::Agent::Monitors::NetHTTP )) {
156             eval {
157 0 0         eval "require $monitor; 1" or die "skipping loading monitor $monitor";
158 0           my $monitor = $monitor->new(agent => $self);
159 0           $monitor->die_unless_suitable();
160 0           push(@{$self->monitors}, $monitor);
  0            
161 0           1;
162 0 0         } or do {
163 0           warn "Error when loading monitor $monitor: " . $@;
164 0           next;
165             }
166             }
167              
168             }
169              
170             sub start_monitors {
171 0     0 0   my $self = shift;
172              
173 0           foreach my $monitor(@{$self->monitors}) { $monitor->start_monitoring() }
  0            
  0            
174             }
175              
176             sub stop_monitors {
177 0     0 0   my $self = shift;
178              
179 0           foreach my $monitor(@{$self->monitors}) { $monitor->stop_monitoring() }
  0            
  0            
180             }
181              
182             1;
183             __END__