1package Search::Elasticsearch::Error; 2$Search::Elasticsearch::Error::VERSION = '6.00'; 3our $DEBUG = 0; 4 5@Search::Elasticsearch::Error::Internal::ISA = __PACKAGE__; 6@Search::Elasticsearch::Error::Param::ISA = __PACKAGE__; 7@Search::Elasticsearch::Error::NoNodes::ISA = __PACKAGE__; 8@Search::Elasticsearch::Error::Unauthorized::ISA = __PACKAGE__; 9@Search::Elasticsearch::Error::Forbidden::ISA = __PACKAGE__; 10@Search::Elasticsearch::Error::Illegal::ISA = __PACKAGE__; 11@Search::Elasticsearch::Error::Request::ISA = __PACKAGE__; 12@Search::Elasticsearch::Error::Timeout::ISA = __PACKAGE__; 13@Search::Elasticsearch::Error::Cxn::ISA = __PACKAGE__; 14@Search::Elasticsearch::Error::Serializer::ISA = __PACKAGE__; 15 16@Search::Elasticsearch::Error::Conflict::ISA 17 = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); 18 19@Search::Elasticsearch::Error::Missing::ISA 20 = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); 21 22@Search::Elasticsearch::Error::RequestTimeout::ISA 23 = ( 'Search::Elasticsearch::Error::Request', __PACKAGE__ ); 24 25@Search::Elasticsearch::Error::ContentLength::ISA 26 = ( __PACKAGE__, 'Search::Elasticsearch::Error::Request' ); 27 28@Search::Elasticsearch::Error::SSL::ISA 29 = ( __PACKAGE__, 'Search::Elasticsearch::Error::Cxn' ); 30 31@Search::Elasticsearch::Error::BadGateway::ISA 32 = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); 33 34@Search::Elasticsearch::Error::Unavailable::ISA 35 = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); 36 37@Search::Elasticsearch::Error::GatewayTimeout::ISA 38 = ( 'Search::Elasticsearch::Error::Cxn', __PACKAGE__ ); 39 40use overload ( 41 '""' => '_stringify', 42 'cmp' => '_compare', 43); 44 45use Data::Dumper(); 46 47#=================================== 48sub new { 49#=================================== 50 my ( $class, $type, $msg, $vars, $caller ) = @_; 51 return $type if ref $type; 52 $caller ||= 0; 53 54 my $error_class = 'Search::Elasticsearch::Error::' . $type; 55 $msg = 'Unknown error' unless defined $msg; 56 57 local $DEBUG = 2 if $type eq 'Internal'; 58 59 my $stack = $class->_stack; 60 61 my $self = bless { 62 type => $type, 63 text => $msg, 64 vars => $vars, 65 stack => $stack, 66 }, $error_class; 67 68 return $self; 69} 70 71#=================================== 72sub is { 73#=================================== 74 my $self = shift; 75 for (@_) { 76 return 1 if $self->isa("Search::Elasticsearch::Error::$_"); 77 } 78 return 0; 79} 80 81#=================================== 82sub _stringify { 83#=================================== 84 my $self = shift; 85 local $Data::Dumper::Terse = 1; 86 local $Data::Dumper::Indent = !!$DEBUG; 87 88 unless ( $self->{msg} ) { 89 my $stack = $self->{stack}; 90 my $caller = $stack->[0]; 91 $self->{msg} = sprintf( "[%s] ** %s, called from sub %s at %s line %d.", 92 $self->{type}, $self->{text}, @{$caller}[ 3, 1, 2 ] ); 93 94 if ( $self->{vars} ) { 95 $self->{msg} .= sprintf( " With vars: %s\n", 96 Data::Dumper::Dumper $self->{vars} ); 97 } 98 99 if ( @$stack > 1 ) { 100 $self->{msg} 101 .= sprintf( "Stacktrace:\n%s\n", $self->stacktrace($stack) ); 102 } 103 } 104 return $self->{msg}; 105 106} 107 108#=================================== 109sub _compare { 110#=================================== 111 my ( $self, $other, $swap ) = @_; 112 $self .= ''; 113 ( $self, $other ) = ( $other, $self ) if $swap; 114 return $self cmp $other; 115} 116 117#=================================== 118sub _stack { 119#=================================== 120 my $self = shift; 121 my $caller = shift() || 2; 122 123 my @stack; 124 while ( my @caller = caller( ++$caller ) ) { 125 next if $caller[0] eq 'Try::Tiny'; 126 127 if ( $caller[3] =~ /^(.+)::__ANON__\[(.+):(\d+)\]$/ ) { 128 @caller = ( $1, $2, $3, '(ANON)' ); 129 } 130 elsif ( $caller[1] =~ /^\(eval \d+\)/ ) { 131 $caller[3] = "modified(" . $caller[3] . ")"; 132 } 133 134 next 135 if $caller[0] =~ /^Search::Elasticsearch/ 136 and ( $DEBUG < 2 or $caller[3] eq 'Try::Tiny::try' ); 137 push @stack, [ @caller[ 0, 1, 2, 3 ] ]; 138 last unless $DEBUG > 1; 139 } 140 return \@stack; 141} 142 143#=================================== 144sub stacktrace { 145#=================================== 146 my $self = shift; 147 my $stack = shift || $self->_stack(); 148 149 my $o = sprintf "%s\n%-4s %-50s %-5s %s\n%s\n", 150 '-' x 80, '#', 'Package', 'Line', 'Sub-routine', '-' x 80; 151 152 my $i = 1; 153 for (@$stack) { 154 $o .= sprintf "%-4d %-50s %4d %s\n", $i++, @{$_}[ 0, 2, 3 ]; 155 } 156 157 return $o .= ( '-' x 80 ) . "\n"; 158} 159 160#=================================== 161sub TO_JSON { 162#=================================== 163 my $self = shift; 164 return $self->_stringify; 165} 1661; 167 168# ABSTRACT: Errors thrown by Search::Elasticsearch 169 170__END__ 171 172=pod 173 174=encoding UTF-8 175 176=head1 NAME 177 178Search::Elasticsearch::Error - Errors thrown by Search::Elasticsearch 179 180=head1 VERSION 181 182version 6.00 183 184=head1 DESCRIPTION 185 186Errors thrown by Search::Elasticsearch are error objects, which can include 187a stack trace and information to help debug problems. An error object 188consists of the following: 189 190 { 191 type => $type, # eg Missing 192 text => 'Error message', 193 vars => {...}, # vars which may help to explain the error 194 stack => [...], # a stack trace 195 } 196 197The C<$Search::Elasticsearch::Error::DEBUG> variable can be set to C<1> or C<2> 198to increase the verbosity of errors. 199 200Error objects stringify to a human readable error message when used in text 201context (for example: C<print 'Oh no! '.$error>). They also support the C<TO_JSON> 202method to support conversion to JSON when L<JSON/convert_blessed> is enabled. 203 204=head1 ERROR CLASSES 205 206The following error classes are defined: 207 208=over 209 210=item * C<Search::Elasticsearch::Error::Param> 211 212A bad parameter has been passed to a method. 213 214=item * C<Search::Elasticsearch::Error::Request> 215 216There was some generic error performing your request in Elasticsearch. 217This error is triggered by HTTP status codes C<400> and C<500>. This class 218has the following sub-classes: 219 220=over 221 222=item * C<Search::Elasticsearch::Error::Unauthorized> 223 224Invalid (or no) username/password provided as C<userinfo> for a password 225protected service. These errors are triggered by the C<401> HTTP status code. 226 227=item * C<Search::Elasticsearch::Error::Missing> 228 229A resource that you requested was not found. These errors are triggered 230by the C<404> HTTP status code. 231 232=item * C<Elastisearch::Error::Conflict> 233 234Your request could not be performed because of some conflict. For instance, 235if you try to delete a document with a particular version number, and the 236document has already changed, it will throw a C<Conflict> error. If it can, 237it will include the C<current_version> in the error vars. This error 238is triggered by the C<409> HTTP status code. 239 240=item * C<Search::Elasticsearch::Error::ContentLength> 241 242The request body was longer than the 243L<max_content_length|Search::Elasticsearch::Role::Cxn/max_content_length>. 244 245=item * C<Search::Elasticsearch::Error::RequestTimeout> 246 247The request took longer than the specified C<timeout>. Currently only 248applies to the 249L<cluster_health|Search::Elasticsearch::Client::6_0::Direct::Cluster/cluster_health()> 250request. 251 252=back 253 254=item * C<Search::Elasticsearch::Error::Timeout> 255 256The request timed out. 257 258=item * C<Search::Elasticsearch::Error::Cxn> 259 260There was an error connecting to a node in the cluster. This error 261indicates node failure and will be retried on another node. 262This error has the following sub-classes: 263 264=over 265 266=item * C<Search::Elasticsearch::Error::Unavailable> 267 268The current node is unable to handle your request at the moment. Your 269request will be retried on another node. This error is triggered by 270the C<503> HTTP status code. 271 272=item * C<Search::Elasticsearch::Error::BadGateway> 273 274A proxy between the client and Elasticsearch is unable to connect to Elasticsearch. 275This error is triggered by the C<502> HTTP status code. 276 277=item * C<Search::Elasticsearch::Error::GatewayTimeout> 278 279A proxy between the client and Elasticsearch is unable to connect to Elasticsearch 280within its own timeout. This error is triggered by the C<504> HTTP status code. 281 282=item * C<Search::Elasticsearch::Error::SSL> 283 284There was a problem validating the SSL certificate. Not all 285backends support this error type. 286 287=back 288 289=item * C<Search::Elasticsearch::Error::Forbidden> 290 291Either the cluster was unable to process the request because it is currently 292blocking, eg there are not enough master nodes to form a cluster, or 293because the authenticated user is trying to perform an unauthorized 294action. This error is triggered by the C<403> HTTP status code. 295 296=item * C<Search::Elasticsearch::Error::Illegal> 297 298You have attempted to perform an illegal operation. 299For instance, you attempted to use a Scroll helper in a different process 300after forking. 301 302=item * C<Search::Elasticsearch::Error::Serializer> 303 304There was an error serializing a variable or deserializing a string. 305 306=item * C<Elasticsarch::Error::Internal> 307 308An internal error occurred - please report this as a bug in 309this module. 310 311=back 312 313=head1 AUTHOR 314 315Clinton Gormley <drtech@cpan.org> 316 317=head1 COPYRIGHT AND LICENSE 318 319This software is Copyright (c) 2017 by Elasticsearch BV. 320 321This is free software, licensed under: 322 323 The Apache License, Version 2.0, January 2004 324 325=cut 326