Página de excepción de Grails

Escrito por el , actualizado el .
java programacion planeta-codigo
Enlace permanente Comentarios

Grails

No es la primera vez que comento algo similar (I, II) disponer de la mayor cantidad de información cuando se produce una excepción o un error en la aplicación es vital para determinar rápidamente la causa del error y para solucionarlo correctamente. Para disponer de esta información podemos generar un archivo de log que nos permita revisar lo que pasó en la aplicación en un determinado momento. En el momento de desarrollo también nos puede interesar tener una página de excepción informativa.

La página de error de Grails por defecto da poca información, a poco más da la traza de la excepción y un extracto de los archivos relacionados donde se ha producido, podría ser mejor. Podría informar de los parámetros que se enviaron en la petición, las cabeceras http o las cookies además de los parámetros de sesión, a veces esta información nos puede servir para identificar la causa más rápidamente ya que la excepción puede estar produciéndose con el valor de un determinado parámetro o un determinado navegador, esta información no la tenemos en una simple traza de la excepción.

En este artículo crearé una página de excepción para Grails con los parámetros de la petición y sesión, cabeceras HTTP y las cookies enviadas además de la traza de la excepción. Los parámetros, las cookies y cabeceras HTTP se pueden obtener de la request y los atributos de la sesión del objeto session. El código del ejemplo de página de excepción es el siguiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<%@ page import="java.text.SimpleDateFormat" %>
<%
	SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss Z")
%>
<!DOCTYPE html>
<html>
<head>
    <meta name="layout" content="main" />
    <title>Excepción</title>
	<g:if env="development"><link rel="stylesheet" href="${resource(dir: 'css', file: 'errors.css')}" type="text/css"></g:if>
</head>
<body>
	<div>
		<div>
			<h1>Detalles del error</h1>	
			<g:renderException exception="${exception}"/>
			
			<pre><g:each in="${exception.stackTraceLines}">${it.encodeAsHTML()}</g:each></pre>
	
			<div>
				<div>
					<h2>Parámetros</h2>
					<g:if test="params">
						<g:set var="paramsKeys" value="${params.keySet()}"/>
						<% paramsKeys.removeAll(['action', 'controller']) %>
						<ul style="list-style-type: none;">
							<g:each in="${paramsKeys}" var="param">
								<g:if test="${params.list(param).size() == 1}">
									<li class="list-group-item"><b>${param}</b>: ${params.get(param)}</li>
								</g:if>
								<g:else>
									<li class="list-group-item"><b>${param}</b>: ${params.list(param)}</li>
								</g:else>
							</g:each>
						</ul>
					</g:if>
				</div>	
				<div>
					<h2>Cabeceras</h2>
					<g:if test="request.headerNames ">
						<g:set var="headers" value="${request.headerNames}"/>
						<% 
							headers = Collections.list(headers)
							headers.removeAll(['cookie'])
						%>
						<ul style="list-style-type: none;">
							<g:each in="${headers}" var="header">
								<li class="list-group-item"><b>${header}</b>: ${request.getHeader(header)}</li>
							</g:each>
						</ul>
					</g:if>
				</div>
				<div>
					<h2>Cookies</h2>
					<g:if test="request.cookies">
						<g:set var="cookies" value="${request.cookies}"/>
						<ul style="list-style-type: none;">
							<g:each in="${cookies}" var="cookie">
								<li class="list-group-item"><b>${cookie.name}</b>: ${cookie.value}</li>
							</g:each>
						</ul>
					</g:if>
				</div>
			</div>
			<div>
				<div>
					<h2>Sesión</h2>
					<ul style="list-style-type: none;">
						<li class="list-group-item"><b>Fecha creación</b>: ${sdf.format(new Date(session.getCreationTime()))}</li>
					</ul> 
					<g:if test="reqeust.getSession(false)">
						<g:set var="sessionKeys" value="${session.getAttributeNames()}"/>
						<ul style="list-style-type: none;">
							<g:each in="${sessionKeys}" var="s">
								<li class="list-group-item"><b>${s}</b>: ${session.getAttribute(s)}</li>
							</g:each>
						</ul>
					</g:if>
					<g:else>
						No hay sesión
					</g:else>
				</div>
			</div>
		</div>
	</div>
</body>
</html>
exception.gsp

Para hacer uso de la página de excepción deberemos configurar el archivo UrlMappings para que Grails use esta página de excepción.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class UrlMappings {

	static mappings = {
        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }

        "/"(view:"/index")
        "500"(view:'/error')
        "500"(controller:"test", action:"exception", exception:Exception)
	}
}
UrlMappings.groovy

El resultado se puede ver en la siguiente captura de pantalla.

Página de error por defecto de Grails Página de error personalizada de Grails

Los estilos mostrados en las capturas de pantalla podrían ser mejores pero la esencia está en la información que se muestra. En otro artículo publicaré como obtener estadísticas de Hibernate para detectar problemas de N+1 u obtener las consultas sql que se están realizando en cada página de una aplicación Grails, esta información nos puede ayudar bastante y no es excesivamente complicado hacerla. Con ambas conseguiremos que las aplicaciones que desarrollemos con Grails sean un poco más informativas.


Comparte el artículo: