Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<com:TContent ID="Main">
2
 
3
<h1>Error Handling and Logging</h1>
4
 
5
<p>
6
If we try to access the URL <tt>http://hostname/blog/index.php?page=EditPost&id=100</tt>, we will see the following error page because the post with ID 100 does not exist in our blog system yet. We would like to customize this error page so that it looks more consistent with the other blog pages in layout. We also want to log this kind of errors to study user behaviors. In this section, we will accomplish these two tasks.
7
</p>
8
 
9
<img src="<%~ output2.gif %>" class="output" />
10
 
11
<com:InfoBox>
12
An important task in a Web application is <a href="http://www.pradosoft.com/demos/quickstart/?page=Advanced.Error">error handling</a> which is often associated <a href="http://www.pradosoft.com/demos/quickstart/?page=Advanced.Logging">logging</a>. There are two types of errors that may occur in a PRADO application: those caused by developers and those by end-users. The former should be resolved before the application is put into production, while the latter are usually within the initial design scope and should be handled nicely (e.g. log the error and display a special page instructing the end-user what to do next.) PRADO implements a very flexible yet powerful framework for error handling and logging.
13
</com:InfoBox>
14
 
15
 
16
<h2>Customizing Error Handling</h2>
17
 
18
<p>
19
PRADO implicitly loads a <tt>TErrorHandler</tt> module to handle errors. We would like to customize this module so that our blog system can display a customized page for errors caused by end-users. We thus modify the application configuration as follows:
20
</p>
21
 
22
<com:TTextHighlighter CssClass="source" Language="xml">
23
......
24
<modules>
25
    ......
26
    <module class="Application.BlogErrorHandler" />
27
    ......
28
</modules>
29
......
30
</com:TTextHighlighter>
31
 
32
<p>
33
The class <tt>BlogErrorHandler</tt> as specified in the above is a new error handler module that we will create next. It extends and replaces the default <tt>TErrorHandler</tt> module.
34
</p>
35
 
36
<p>
37
We create a file named <tt>protected/BlogErrorHandler.php</tt> as follows. The class <tt>BlogErrorHandler</tt> overrides two methods of <tt>TErrorHandler</tt>:
38
</p>
39
<ul>
40
  <li><tt>getErrorTemplate()</tt> - this method returns the template string used for displaying a particular user error.</li>
41
  <li><tt>handleExternalError()</tt> - this method is invoked when a user error occurs and displays the error.</li>
42
</ul>
43
<com:TTextHighlighter CssClass="source" Language="php">
44
Prado::using('System.Exceptions.TErrorHandler');
45
Prado::using('Application.BlogException');
46
 
47
class BlogErrorHandler extends TErrorHandler
48
{
49
	/**
50
	 * Retrieves the template used for displaying external exceptions.
51
	 * This method overrides the parent implementation.
52
	 */
53
	protected function getErrorTemplate($statusCode,$exception)
54
	{
55
		// use our own template for BlogException
56
		if($exception instanceof BlogException)
57
		{
58
			// get the path of the error template file: protected/error.html
59
			$templateFile=Prado::getPathOfNamespace('Application.error','.html');
60
			return file_get_contents($templateFile);
61
		}
62
		else // otherwise use the template defined by PRADO
63
			return parent::getErrorTemplate($statusCode,$exception);
64
	}
65
 
66
	/**
67
	 * Handles external error caused by end-users.
68
	 * This method overrides the parent implementation.
69
	 * It is invoked by PRADO when an external exception is thrown.
70
	 */
71
	protected function handleExternalError($statusCode,$exception)
72
	{
73
		// log the error (only for BlogException)
74
		if($exception instanceof BlogException)
75
			Prado::log($exception->getErrorMessage(),TLogger::ERROR,'BlogApplication');
76
		// call parent implementation to display the error
77
		parent::handleExternalError($statusCode,$exception);
78
	}
79
}
80
</com:TTextHighlighter>
81
 
82
<p>
83
In the above, we specify that when a <tt>BlogException</tt> is thrown, we use a new template <tt>protected/error.html</tt> to display the error. Therefore, we need to create the <tt>BlogException</tt> class and replace all the occurances of <tt>THttpException</tt> in our code (such as <a href="?page=Day3.CreateEditUser">EditUser</a> and <a href="?page=Day4.CreateReadPost">ReadPost</a> pages). We also need to create the error template <tt>protected/error.html</tt>. The <tt>BlogException</tt> class extends <tt>THttpException</tt> and is empty. The class file is saved as <tt>protected/BlogException.php</tt>.
84
 
85
</p>
86
 
87
<com:TTextHighlighter CssClass="source" Language="php">
88
class BlogException extends THttpException
89
{
90
}
91
</com:TTextHighlighter>
92
 
93
<p>
94
Below is the content in our error template <tt>protected/error.html</tt>. Note, the template is not a PRADO template because it only recognizes very limited number of tokens, such as <tt>%%ErrorMessage%%</tt>, <tt>%%ServerAdmin%%</tt>.
95
</p>
96
 
97
<com:TTextHighlighter CssClass="source" Language="xml">
98
<html>
99
<head>
100
<title>%%ErrorMessage%%</title>
101
</head>
102
<body>
103
<div id="page">
104
<div id="header">
105
<h1>My PRADO Blog</h1>
106
</div>
107
<div id="main">
108
<p style="color:red">%%ErrorMessage%%</p>
109
<p>
110
The above error happened when the server was processing your request.
111
</p>
112
<p>
113
If you think this is a server error, please contact the <a href="mailto:%%ServerAdmin%%">webmaster</a>.
114
</p>
115
</div>
116
</body>
117
</html>
118
</com:TTextHighlighter>
119
 
120
 
121
<h2>Logging Errors</h2>
122
 
123
<p>
124
In the <tt>handleExternalError()</tt> method of  <tt>BlogErrorHandler</tt>, we invoke <tt>Prado::log()</tt> to log the error if it is of type <tt>BlogException</tt>. The error is logged in memory. To save the logs into permanent medium such as file or database, we need to enable appropriate error logging routes. This is done in the application configuration as follows:
125
</p>
126
 
127
<com:TTextHighlighter CssClass="source" Language="xml">
128
......
129
<modules>
130
    ......
131
    <module id="log" class="System.Util.TLogRouter">
132
        <route class="TFileLogRoute" Categories="BlogApplication" />
133
    </module>
134
    ......
135
</modules>
136
......
137
</com:TTextHighlighter>
138
 
139
<p>
140
In the above, we add a log route that saves logs into a file. We also specify the category filter as <tt>BlogApplication</tt> such that only the log messages of the selected categories are saved. This helps reduce the size of the log file and also improves its readability.
141
</p>
142
 
143
<h2>Testing</h2>
144
<p>
145
To see how our blog systems reponds to an invalid user request, we test the URL <tt>http://hostname/blog/index.php?page=posts.ReadPost&id=100</tt>. We shall see the following error page which is different from what we saw earlier on.
146
</p>
147
 
148
<img src="<%~ output3.gif %>" class="output" />
149
 
150
<p>
151
If we search under the directory <tt>protected/runtime</tt>, we will find a file named <tt>prado.log</tt>. This is the log file that we just configured to save the error messages. The file may contain contents like the following,
152
</p>
153
 
154
<com:TTextHighlighter CssClass="source" Language="text">
155
Jun 28 22:15:27 [Error] [BlogApplication] Unable to find the specified post.
156
Jun 29 08:42:57 [Error] [BlogApplication] Unable to find the specified post.
157
</com:TTextHighlighter>
158
 
159
</com:TContent>