-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Problem with the Hibernate Appender.
PostPosted: Mon Jul 24, 2006 5:29 pm 
Beginner
Beginner

Joined: Thu Jun 29, 2006 12:36 pm
Posts: 20
Hibernate version: 3.1.3

Hello,

I have a problem with the Hibernate Appender. The Problem occurs when the appender causes an error, e.g. I want to log a message and the message is too long for the field in the database. Then Hibernate throws an error:
Code:
2006-07-24 16:52:35,591 ERROR [Thread-3] JDBCExceptionReporter: Data truncation: Data too long for column 'message' at row 1


and makes the session unusable. So all the changes that other threads that use the same session object want to make, can't be done. Even worse, the
Code:
org.hibernate.AssertionFailure:

that occurs when I continue to use the session object causes the whole application to crash.

Has anyone had the same problem and knows how to change the Hibernate Appender Code? Or how to handle exceptions caused by the logger?

Do you need more informations?

I tried already all I can think of. Thank you in advance.
Pi


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 28, 2006 4:54 pm 
Beginner
Beginner

Joined: Thu Jun 29, 2006 12:36 pm
Posts: 20
Ok, I could find a solution for some of the problems. I created another HibernateUtil class that is only used by the Hibernate Appender. The Hibernate Appender has now its own session object that it can use. This solved the following problems:

- As the whole application used only one session object the Hibernate Appender commited sometimes my transactions though I didn't want that.

- When during logging something went wrong, e. g. like in the case discribed above, the session object couldn't be used anymore by the application and had to shut down.

One problem still remains, once an error occurs in the Hibernate Appender, e.g. a message was too long, the Appender doesn't work anymore, also when the other messages would fit into the database.

I tried to solve that by implementing a methof that resets the SessionFactory and call this message when the Appender catches an error. Unfortunatly this doesn't work as expected and the Hibernate Appender still throws exceptions everytime an event has to be logged.

Code:
public static void resetSessionFactory(){
      threadSession.set(null);
      threadTransaction.set(null);
      sessionFactory = null;
      sessionFactory = new Configuration().configure().buildSessionFactory();
      System.out.println("***SessionFactory reset***");
}


Even though this approach solved some of the main issues, I have the feeling that it is not a good solution. I don't know how expensive it is if two SessionFactory Objects are created. And the problem remains, that once an error occurs, logging to the database completely crashes.

Isn't it possible to just create another session object that the logger can use on its own, instead of creating a whole SessionFactory?

Do you have any ideas, or comments? I would be very much interested in your opinions.

Pi


Top
 Profile  
 
 Post subject: Several tweaks are still needed
PostPosted: Mon Jul 31, 2006 2:21 pm 
Newbie

Joined: Tue Aug 02, 2005 4:53 pm
Posts: 14
Yeah, currently you will find that there are several limitation of the current implementation.

Currently there is a single session that is created and when it barfs is never recreated. You will need to do some better session validity testing than what exists now (none really) or even just always grab a new session (bad for performance). And you shouldn't need to grab a new session factory, just a new session from that session factory.

You also need to be vary careful about transactional boundaries. You probably don't want logging to participate in the transaction your application logic is. How this is accomplished may vary greatly depending on your app framework, etc. You will certainly want to add more robust eror handling in the appender too, so it doesn't cause your whole application to bail.

It would be a good idea to take logging messages and check their length against the configuration and either truncate the messages that are too long or split the logging messages accross multiple log entries. In either case you may also want to increase the log message db field size and could even make it a CLOB if the performance of that doesn't bother you.

I've emailed you some additional feedback. Hope this helps.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 31, 2006 4:46 pm 
Beginner
Beginner

Joined: Thu Jun 29, 2006 12:36 pm
Posts: 20
This is the first thing I wanted to check;

Quote:
You will need to do some better session validity testing than what exists now (none really) or even just always grab a new session (bad for performance). And you shouldn't need to grab a new session factory, just a new session from that session factory.


I did a first test and added in the HibernateUtil class in the getSession() method a method call session.isdirty(), if the session isn't valid anymore, this throws an exception (unfortunately it isn't really reliable). In the catch block I wrote the following line: session = sessionfactory.openSession().

Some strange things happen. I tested the new code with a string that is too long for the database field, what happens is, that once a "data too long error" occurs, it doesn't matter how short your following log messages are, they have always the length of the message that was too long and therefore every following message throws again an error. :-(
Where does this error come from? New session objects are created for every message.

Another point is, that even when I test if the session is valid before starting a transaction, there is no guaranty, that it remains valid during it. Imagine the following scenario:

- get session
- start transaction
- do buisness database communication
- log some event (!!! logging fails, and throws hibernate exception !!!)
- do some more database communication
- commit transaction (throws exception)

Quote:
It would be a good idea to take logging messages and check their length against the configuration and either truncate the messages that are too long or split the logging messages accross multiple log entries. In either case you may also want to increase the log message db field size and could even make it a CLOB if the performance of that doesn't bother you.


It is not really that special error that bothers me, I came accross it accidently, it's more the fact that logging affects my whole application flow. I think I could easily avoid this kind of error. But even if I decide, that I don't care about handling these exceptions there is still the transaction problem:

Quote:
You also need to be vary careful about transactional boundaries.


I really have no good idea how to solve this with only one shared session object. The only idea I have, would be to remove the line tx.commit() in the hibernate appender and all transaction handling is made in the actual application code.

So far my results. Thank you for your reply!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 31, 2006 5:46 pm 
Beginner
Beginner

Joined: Thu Jun 29, 2006 12:36 pm
Posts: 20
Another idea, instead of two sessionFactory classes, I could write a method that creates a session object just for logging, e.g.

Code:
private static final ThreadLocal threadLogSession = new ThreadLocal();

[...]

public static Session getLogSession() {
      Session s = (Session) threadLogSession.get();
      //    Open a new Session, if this thread has none yet
      try {
         if (s == null) {
            s = sessionFactory.openSession();
            threadLogSession.set(s);
         }else{
            try {
               s.isDirty();
            } catch (Exception e) {
               s = sessionFactory.openSession();
               threadLogSession.set(s);
            }
         }
      } catch (HibernateException ex) {
         logger.error("Can't get session: "+ex.getMessage());
         throw new InfrastructureException("Can't get session: "+ex);
      }
      return s;
   }   



This would solve the transaction problem, but would have the drawback of two open database connections.

OK, I think I will try the following "solution":

. use one session object for logging and application flow
- avoid logging messages that are too long
- remove the tx.commit() line in the appender
- and hope that everything works


Top
 Profile  
 
 Post subject: Transaction boundaries and mode
PostPosted: Mon Jul 31, 2006 6:55 pm 
Newbie

Joined: Tue Aug 02, 2005 4:53 pm
Posts: 14
Yeah, the transaction boundaries are going to be key. It seems you would want REQUIRES_NEW for the logging transaction. You don't want this transaction to participate in the outer application transaction.

I'm not sure howto set the transaction mode for hibernate for that method. I'm used to using spring to wire up transactions for my classes that use hibernate, which makes it easy. I haven't manually set transaction modes for hibernate before.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.