Added Canvas 1.1.0, originally not under SCM so no historical development records...
[canvas.git] / library / Debug.php
blobf29b45793277d6f6bcf000e2000748c15c2f74f8
1 <?php
2 // @title Debug class
3 // @author Matt Todd <matt@matttoddphoto.com>
4 // @created 2005-12-22
5 // @desc Handles various aspects of debugging, such as logging, asserting,
6 // default exception handlers or verbose exception handlers,
7 // and potentially suppoting breakpoints/interactive
8 // inspection during runtime
9 // @requires stdexception.php (StdException class)
10 // @refer_to http://www.php.net/manual/en/function.proc-open.php for
11 // breakpoint/interactive inspection during runtime
12 // @refer_to http://www.php.net/manual/en/function.assert.php for
13 // assertions and peculiarities therein
14 // @refer_to http://www.php.net/manual/en/function.apd-breakpoint.php
16 include_once('stdexception.php');
18 // classes
19 class Debug extends Canvas {
20 // property functions
21 public static function __set($name, $value) {
22 $GLOBALS["debug"][$name] = $value;
24 public static function __get($strName) {
25 return $GLOBALS["debug"][$name];
28 // functions
29 // Debug::log($message, $type = 'general', $level = 'general', $from = null);
30 public static function log($message, $type = 'general', $level = 'notice', $from = null) {
31 // handle logging the $message (possibly formatting)
33 // configuration values
34 $env = Config2::$environment;
35 $log_config = Config2::$config['logging'];
36 $dir = Config2::$config['directories']['logs'];
37 $filename = "{$env}.log";
38 if($filename == '.log') $filename = 'system.log';
39 $log_level = $log_config['log_level'];
40 $log_separately = $log_config['log_separately']; // array of types of messages to log separetely (in their own logs)
41 $always_log = $log_config['always_log']; // array of types of messages to always log
43 // handle default values (convention over configuration)
44 if(empty($dir)) $dir = 'logs/'; // default logging directory
45 if(empty($log_level)) $log_level = 'notice'; // default log level
46 if(empty($always_log)) $always_log = array();
47 if(empty($log_separately)) $log_separately = array();
48 // make sure logging is supposed to happen for this event
49 // if($env == 'production') return; // should logging be skipped in the production environment?
50 if(self::log_level($level) >= self::log_level($log_level) || in_array($type, $always_log) || in_array($type, $log_separately)) {
51 if(in_array($type, $log_separately)) $filename = "{$type}.log";
52 } else {
53 if(!in_array($type, $always_log)) return;
56 // log format
57 if(empty($log_config['log_format']))
58 $log_format = "%s (%s:%s)%s %s\n";
59 else
60 $log_format = $log_config['log_format'];
62 // changes if it was set
63 if(!empty($from)) $from = " [{$from}]";
65 $log_file = new FSFile(FSFile::build_path($dir, $filename));
66 $date = date("Y-m-d H:i:s"); // alternatively // date("c");
67 $log_file->write(sprintf($log_format, $date, $type, $level, $from, $message));
69 private static function log_level($level) {
70 // determines the log level value (a numerical index) for each logging level
71 // used to determine if logging of the specified level should be skipped or not
73 // log levels and their numerical index
74 $log_levels = array(
75 "low"=>0,
76 "info"=>1,
77 "notice"=>2,
78 "warn"=>3,
79 "error"=>4,
80 "fatal"=>5,
83 // return numerical index
84 // return 0 if it's not in the array of predefined levels
85 return (array_key_exists($level, $log_levels)) ? $log_levels[$level] : 0;
88 public static function assert($expression, $value) {
89 if($expression == $value) return true; // assertion was successful
90 else throw new AssertionException($expression); // assertion did not succeed and must be handled
92 // if $expression is a boolean value, return it
93 // if not, evaluate it and then return that value
94 // if no value returned by expression, return null value
96 // refer to http://www.php.net/manual/en/function.assert.php
99 public static function breakpoint() {
100 // refer to http://www.php.net/manual/en/function.proc-open.php to possibly implement
101 // and also http://www.php.net/manual/en/function.apd-breakpoint.php
104 // standard/verbose exception handlers
105 public static function generic_exception_handler($e) {
106 // handle generic exception
107 $exception_type = get_class($e);
108 $e_dump = print_r($e, true);
109 $template = <<<TPL
110 <html>
111 <head>
112 <title>Exception: {$exception_type}</title>
113 </head>
114 <body>
115 <h1>Internal Exception!</h1>
116 <p>{$e->getMessage()}</p>
117 <pre>{$e_dump}</pre>
118 </body>
119 </html>
120 TPL;
121 print $template;
122 die();
124 public static function verbose_exception_handler($e) {
125 // verbosely evaluate the exception and return/print the evaluation for inspection during development
127 public static function minimal_exception_handler($e) {
128 // give as little error information as possible (reserved primarily for the production environment for unhandled exceptions, a bad thing to begin with)
131 // handle timing
132 public static function timing($component) {
133 if(empty($GLOBALS['debug']['timing'][$component])) {
134 // begin timing
135 $GLOBALS['debug']['timing'][$component] = microtime(true);
136 } else {
137 // finish timing
138 $time = microtime(true) - $GLOBALS['debug']['timing'][$component];
139 Debug::log("took $time seconds...", 'bebug:timing', 'warn', $component);
144 class DebugException extends StdException {} // hopefully won't ever need to be used, but you never know
145 class AssertionException extends StdException {} // an assertion failure exception