| Eidolon documentation | Contained in the Eidolon distribution. |
Eidolon::Debug - Eidolon debugging facility.
In CGI/FCGI gateway of your application (index.cgi/index.fcgi) write:
use Eidolon::Debug;
The Eidolon::Debug package provides an easy way to avoid a confusing Internal Server Error web server message. It sends HTTP header before displaying an error, so you don't need to dig web-server's log to find the cause of the error anymore. Obviously, it will do nothing if error is in your web-server configuration, so if Internal Server Error message still remains, check your web-server configuration. Also, this package displays a stack trace when application dies. It is very useful in application development, so Eidolon::Debug is included in applications by default.
This package doesn't depend on any other Eidolon package, so you can use it outside Eidolon applications too.
While used, Eidolon::Debug hooks global die and warn subroutines, so be
careful using other packages, that modify or depend on $SIG{"__DIE__"} and
$SIG{"__WARN__"} handlers.
Start a javascript debugging console. Prints a minimal HTTP header and javascript code, so further error and warning messages could be displayed in nice-looking form.
Get subroutine call stack. Returns reference to array of hashrefs, each hashref stands for one level of the call stack. This hashref contains the following data:
Package name, where error has been occured.
File name, where error has been occured.
Line number, which caused program to die.
Subroutine name, where error has been occured.
Prints the call stack in nice preformatted table. $stack - reference to
array of call stack hashrefs (result, returned by get_stack() subroutine).
Custom warning handler. $message - warning message to be displayed.
Custom error handler. $message - error message to be displayed.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Anton Belousov, <abel@cpan.org>
Copyright (c) 2009, Atma 7, http://www.atma7.com
| Eidolon documentation | Contained in the Eidolon distribution. |
package Eidolon::Debug; # ============================================================================== # # Eidolon # Copyright (c) 2009, Atma 7 # --- # Eidolon/Debug.pm - debugging facility # # ============================================================================== use warnings; use strict; our $VERSION = "0.02"; # 2009-05-12 05:50:18 my $console_started = 0; # ------------------------------------------------------------------------------ # BEGIN() # package initialization # ------------------------------------------------------------------------------ BEGIN { $SIG{"__WARN__"} = \&warn; $SIG{"__DIE__"} = \¨ } # ------------------------------------------------------------------------------ # start_console() # start debug console # ------------------------------------------------------------------------------ sub start_console { my $script; # print HTTP header print "Content-Type: text/html; charset=UTF-8\n\n"; { local $/; $script = <DATA>; } print $script; $console_started = 1; } # ------------------------------------------------------------------------------ # \@ get_stack() # get call stack # ------------------------------------------------------------------------------ sub get_stack { my (@stack, $package, $file, $line, $sub, $level); # we don't need this function in stack $level = 1; # walk stack while (($package, $file, $line, $sub) = caller($level)) { push @stack, { "package" => $package, "file" => $file, "line" => $line, "sub" => $sub }; $level++; } return \@stack; } # ------------------------------------------------------------------------------ # print_stack(@$stack) # print call stack # ------------------------------------------------------------------------------ sub print_stack { my ($stack, $level, $sublen, $sub); $stack = shift; $sublen = 0; # count fields width $sublen = length($_->{"sub"}) > $sublen ? length($_->{"sub"}) : $sublen foreach (@$stack); # print stack foreach (reverse @$stack) { printf ( "{ line: '%05d', sub: '%-${sublen}s', file: '%s' },", $_->{"line"}, $sub ? $sub : "main", $_->{"file"} ); $sub = $_->{"sub"}; } } # ------------------------------------------------------------------------------ # warn($message) # warning handler # ------------------------------------------------------------------------------ sub warn { my ($message, $stack, $phase); $message = shift; $phase = defined $^S ? "Runtime" : "Compile"; start_console unless $console_started; $message =~ s/[\r\n]//g; $message =~ s/'/\\'/g; printf "<script>eidolonDebug.addWarning('$phase warning', '$message');</script>"; } # ------------------------------------------------------------------------------ # die($message) # die handler # ------------------------------------------------------------------------------ sub die { my ($message, $stack, $phase); $message = shift; $phase = defined $^S ? "Runtime" : "Compile"; # call original die if called from eval block CORE::die($message) if (defined $^S && $^S == 1); start_console unless $console_started; $message =~ s/[\r\n]//g; $message =~ s/'/\\'/g; print "<script>eidolonDebug.addError('$phase error', '$message', ["; # don't print stack on compile errors if (defined $^S) { print_stack(get_stack); } print "]);</script>"; exit; } 1;
__DATA__ <body> <div id="eidolon-console" style="background-color: #F0F0F0; border: 1px solid #909090; position: absolute; top: 10px; left: 10px; width: 800px; font-family: Verdana, Tahoma; font-size: 12px; text-align: left;"></div> <script> EidolonConsole = function () { this.errors = []; this.warnings = []; this.details = 0; } EidolonConsole.prototype.addError = function (title, message, stack) { this.errors.push( { "title": title, "message": message, "stack": stack } ); this.redraw(); } EidolonConsole.prototype.addWarning = function (title, message) { this.warnings.push( { "title": title, "message": message } ); this.redraw(); } EidolonConsole.prototype.redraw = function () { var obj, i, html, item, k, frame; obj = document.getElementById("eidolon-console"); html = '<div id="eidolon-title" style="background-color: #7B84B0; color: white; padding: 10px; cursor: pointer;" onclick="eidolonDebug.toggleDetails();"><b>Eidolon::Debug</b> - ' + this.errors.length + ' errors, ' + this.warnings.length + ' warnings</div>'; html += '<div id="eidolon-details" style="display: none; padding: 10px; color: #606060;"></div>'; obj.innerHTML = html; obj = document.getElementById("eidolon-details"); html = ""; for (i = 0; i < this.errors.length; i++) { item = this.errors[i]; html += '<div style="border-left: 4px solid red; padding: 0 10px 0 10px; margin-bottom: 10px;"><b>' + item.title + ":</b> " + item.message + '<div style="font-size: 12px;"><pre>'; for (k = 0; k < item.stack.length; k++) { frame = item.stack[k]; if (frame) html += frame.line + " " + frame.sub + " " + frame.file + "\n"; } html += "</pre></div></div>"; } for (i = 0; i < this.warnings.length; i++) { item = this.warnings[i]; html += '<div style="border-left: 4px solid #7B84B0; padding: 0 10px 0 10px; margin-bottom: 10px;"><b>' + item.title + ":</b> " + item.message + "</div>"; } obj.innerHTML = html; } EidolonConsole.prototype.toggleDetails = function () { var obj = document.getElementById("eidolon-details"); if (this.details) { this.details = 0; obj.style.display = "none"; } else { this.details = 1; obj.style.display = "block"; } } var eidolonDebug = new EidolonConsole(); </script>