Tengo un actor (Play Framework, Java) para realizar algunas importaciones de datos de bases de datos a intervalos regulares. Este actor llama a varias otras clases que se encargan de la importación, la persistencia, etc. Mi problema actual es que no puedo averiguar el número de línea exacto y el archivo que genera excepciones SQL. Por ejemplo, obtengo errores como este:

[info] application - javax.persistence.PersistenceException: ERROR executing DML bindLog[] error[ERROR: null value in column "email" violates not-null constraint\n   Detail: Failing row contains (266, null, null, null).]
[info] application - Starting persisting of customer id 29917837
[error] o.j.StatementLogger - insert into emails (email, domain, user_id) values (null,null,null);
throws exception: org.postgresql.util.PSQLException: ERROR: null value in column "email" violates not-null constraint
  Detail: Failing row contains (268, null, null, null).
org.postgresql.util.PSQLException: ERROR: null value in column "email" violates not-null constraint
  Detail: Failing row contains (268, null, null, null).
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:645)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:495)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:441)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

Naturalmente, puedo mirar el mensaje de error y ver que algo en algún lugar está intentando conservar mi modelo de correo electrónico sin rellenarlo. En este momento, la base del código es realmente pequeña (~ 200-300 líneas) y puedo adivinar con bastante precisión de dónde viene esto. Pero, ¿no debería el marco informar también los números de línea? ¿O quizás esto es lo que sucede cuando se utiliza a los actores, porque de alguna manera están fuera del sistema y todo eso?

4
ankush981 13 dic. 2016 a las 22:07
De hecho, tiene números de línea para la mayoría de sus clases (tener números de línea en el código java compilado es opcional). Pero, ¿es este todo tu seguimiento de pila? ¿Qué método (s) está utilizando la reflexión para invocar HikariProxyPreparedStatement?
 – 
Serg M Ten
13 dic. 2016 a las 22:25
Sí, este es el seguimiento completo de la pila. De hecho, estoy usando Play Framework, que usa actores de Akka para programar tareas. Más allá de eso, tengo poca idea de quién hace qué, pero parece que el marco está usando la reflexión.
 – 
ankush981
13 dic. 2016 a las 22:32

1 respuesta

La mejor respuesta

Está utilizando un marco que ejecuta sus consultas mediante la reflexión, lo que dificulta bastante la depuración. No sé el marco específico que está utilizando, pero es muy posible que tenga una configuración que se pueda configurar para facilitar la depuración de este tipo de cosas.

Si no es así, o es su propio código el que usa la reflexión, puede capturar la excepción, envolverla y volver a lanzarla desde el código "externo", el código que está ejecutando la operación de reflexión. Esto le dará un seguimiento de pila adicional con la ubicación exacta en su código donde está sucediendo.

Por ejemplo, puede hacer esto con su código contenedor:

try {
     this.custPersister.persist(customer);
} catch (Exception e) {
     throw new Exception(e);
}

Solo asegúrese de que esta excepción esté capturada en el lugar apropiado en su código externo y que se registre el seguimiento de la pila.

4
Jeremy Gurr 13 dic. 2016 a las 22:35
Hola Jeremy, en realidad estoy usando Play Framework. Había etiquetado mi pregunta y ahora agregué el nombre del marco a mi pregunta para mayor claridad. De hecho, antes ni siquiera obtenía tanto de los informes de excepciones. Fue solo después de envolver el código de Actor (ver pastebin.com/RXtQUye7) que comencé a obtener al menos esto mucho.
 – 
ankush981
13 dic. 2016 a las 22:31
2
Así que ya ha recorrido la mayor parte del camino. Simplemente cambie su código de envoltura como explicaré anteriormente. Editaré mi respuesta.
 – 
Jeremy Gurr
13 dic. 2016 a las 22:33
¡Mejoró mucho! (ver pastebin.com/9eEDnSZ9) El problema es que todo lo que me da ahora es qué línea del actor causó el error. Todavía no sé qué clase causó la excepción y por qué. Pero supongo que así es como funcionan Actors in Play Framework. . . Quiero decir, se supone que los actores son unidades separadas y todo eso. Pero dime, ¿por qué este simple cambio produjo tanta más información? Entonces aceptaré esto como la respuesta. :-)
 – 
ankush981
13 dic. 2016 a las 22:45
Su seguimiento de pila le dice que está sucediendo en su UserImportActor activándolo, que es llamado por su clase MailBox. Eso es bastante detalle. Para ir más allá, necesitaríamos saber mucho más sobre lo que está sucediendo en su código. En cuanto a por qué ayudó este cambio, cada vez que se lanza una excepción, la ubicación actual en el código (el seguimiento de la pila) se captura en el objeto de excepción. Si lo envuelve alrededor de otra excepción, se obtiene la información de "Causa por ..." que se ve en los registros.
 – 
Jeremy Gurr
13 dic. 2016 a las 22:50