Showing posts with label logging. Show all posts
Showing posts with label logging. Show all posts

Thursday, 3 August 2017

EclipseLink Logging

In the persistence.xml I have added the following to enable logging for EclipseLink.

Just for my information (so I don't lose the info).

References

EclipseLink 2.5.x. Understanding EclipseLink - Specify Logging
http://www.eclipse.org/eclipselink/documentation/2.5/solutions/tlandgs002.htm#CIHHJIGF
Eclipse - EclipseLink/Examples/JPA/Logging
https://wiki.eclipse.org/EclipseLink/Examples/JPA/Logging

Thursday, 14 January 2016

Glassfish Logging to Database

I wanted to redirect the logging messages from the Glassfish Application Server to the database.

Glassfish uses the standard Logging API available in the JDK. There are some who find the already existing logging APIs (log4j, etc) available better than the default provided in the SDK. But I find it sufficient for my purposes.

The Logging API uses Handlers to indicate what needs to be done with all those log messages. The default handlers available in the API are shown in the diagram below.

I have opted for having the logrecords sent via the network (local interface) to a small daemon that posts the log records into a database table. So that would mean using the SocketHandler.

In general, this is what you want. Several application servers all sending their log messages to a central repository that can deal with it. Of course, there are way more sophisticated solutions readily available compared to this home-brewed thing. But it helps to get the general idea of how it works.

The software I made is available at https://github.com/maartenl/sql-logging. The sequence diagram below is basically how it works.

Since the data send over the network is in the XML format, I'm using StAX for interpreting the XML stream properly.

The funny thing is that the DatabaseHandler in the diagram above, is basically a child of the Handler class (depicted in the class diagram up top). So, what we have here is a kind of Logging proxy, really.

The database table follows the fields in the LogRecord class closely:
create table mm_systemlog (
  id bigint(20) NOT NULL AUTO_INCREMENT primary key,
  millis bigint(20) not null,
  sequence bigint(20) not null,
  logger varchar(255),
  level varchar(25),
  class varchar(255),
  method varchar(255),
  thread int(10),   
  message text not null,
  INDEX(millis)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Glassfish

Glassfish has a logging.properties file (glassfish4.1/glassfish/domains/domain1/config/logging.properties). It is possible to add or change the Log Handler used by Glassfish by changing it in the logging.properties file1 3.

I was unable to provide Glassfish with a Logging Handler that directly posted the LogRecords into a database (see [2]). Hence the current solution described above.

The (fairly easy) steps were as follows:
  • the developer has put the custom handler JAR file into the domain-dir/lib/ext directory.
  • the class that extends java.util.logging.Handler must be in the server classpath.
  • add the new handler to the handlers attribute in the glassfish/domains/domain1/config/logging.properties file
    handlers=java.util.logging.ConsoleHandler,com.mrbear.logging.handlers.SimpleSocketHandler
  • reboot glassfish

XML Formatter

Below is an example of what the XML format looks like.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433234</millis>
<sequence>0</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>SEVERE</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Hello, World</message>
</record>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433261</millis>
<sequence>1</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>INFO</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Welcome Home</message>
</record>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433263</millis>
<sequence>2</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>CONFIG</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Config ....</message>
</record>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433265</millis>
<sequence>3</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>FINE</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Fine ....</message>
</record>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433266</millis>
<sequence>4</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>FINEST</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Finest ....</message>
</record>
<record>
<date>2016-01-11T06:50:33</date>
<millis>1452491433266</millis>
<sequence>5</sequence>
<logger>com.mrbear.logging.tests.SimpleSocketHandlerTest</logger>
<level>WARNING</level>
<class>com.mrbear.logging.tests.SimpleSocketHandlerTest</class>
<method>testSocketHandler</method>
<thread>1</thread>
<message>Warning ....</message>
</record>
I would like to point out that, strictly speaking, the above XML document is not valid, as there is no closing </log> tag.

This makes sense, as the xml is streamed and never quite ended.

I would also like to point out that the XML document contains for each record both the number of milliseconds sinds 1970 and the date. This at first seems superfluous to me, but after some thought it makes sense. If you add both, you get valuable information in what timezone the server logging messages is working. This information is most likely lost in the milliseconds approach.

References

[1] Oracle Blog - Configure my Custom Log Handler in GlassFish 3.1
https://blogs.oracle.com/naman/entry/configure_my_custom_log_handler
[2] StackOverflow - Capture GlassFish log file into SQL/JPA data base
http://stackoverflow.com/questions/12397861/capture-glassfish-log-file-into-sql-jpa-data-base
[3] 7 Administering the Logging Service - Adding a Custom Logging Handler
Oracle GlassFish Server Administration Guide
HK2 - Dependency Injection Kernel
https://hk2.java.net/2.3.0/
Oracle JavaTM Tutorials - Lesson: JDBC Introduction
https://docs.oracle.com/javase/tutorial/jdbc/overview/index.html
JavaBendeR - Simple Log server with java SocketHandler and centralization of log records
http://javabender.blogspot.nl/2010/09/simple-log-server-with-java.html
Java Logging API Tutorial – Examples of Logger Levels, Handlers, Formatters and Filters
http://www.journaldev.com/977/java-logging-api-tutorial-examples-logger-levels-handlers-formatters-filters
Oracle JavaTM Tutorials - Reading XML Data into a DOM
https://docs.oracle.com/javase/tutorial/jaxp/dom/readingXML.html
Oracle JavaTM Tutorials - Using StAX
https://docs.oracle.com/javase/tutorial/jaxp/stax/using.html

Sunday, 5 October 2014

Getting the Stacktrace

Found this snippet to get the stacktrace as a printable String on StackOverflow[1].
However, this only provides the stacktrace of the exception, not the possible underlying exception as well.
For that, you should look at:
Of course, if you do not wish to reinvent the wheel, there is always org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable).

Just thought I'd write this down here, I always forget how to do it.

References

[1] How can I convert a stack trace to a string?
http://stackoverflow.com/questions/1149703/how-can-i-convert-a-stack-trace-to-a-string

Tuesday, 11 March 2014

Simple Logging - Extended

This is a followup of the Simple Logging blogpost.

It is possible to change the logging.properties file to use a FileHandler. This directs everything to a file, (obviously).

Check reference 3 for a good explanation of the logging.properties file.

Unfortunately the default values of the FileHandler in the default JSE logging.properties6 file leaves a lot to be desired.

property
default
comments
mine
limit5000050 kilobytes is quite small for a log file5000000
count1this means the total number of files written is 1, so if the log increases beyond 'limit', you lose the old messages as the file is re-initialized100
appendfalsemight want to set this to true, to prevent loss of log messages upon restart. Unfortunately, this means you'll have *two* XML files within the log and they need to be separated afterwards.true

The following Handlers seem to be already available in Java4, if you're looking for something different.

I very much like the XMLFormatter. It provides even more information than general logging, and it can be easily post-processed.

JLogViewer


JLogViewer1 can view the XML logs written to file. I am sure there are other programs that perform the same function, but this is the one I happened to come across.

java -cp jlogviewer_1_0_0d.jar gianluca.utility.LogViewer

Fixing the logs

Unfortunately for me, the logs contain odd characters (because I am writing received data from sockets into the logs) that are not properly handled by jlogviewer.

I was required to remove the special characters from my logs. Found a blog post2 on how to remove them.
cat java0.log.0 | tr -d "\013" | tr -d "\001" | tr -d "\000" | tr -d "\017" > sanitized_java.log

Update 17-03-2014: updated the item on appending to existing logs.

References

[1] JLogViewer
http://jlogviewer.sourceforge.net/
[2] Removing special characters in Linux
http://deepupc.wordpress.com/2009/10/28/removing-special-charactersmca-in-vi/
[3] java Logging - Configuration
http://tutorials.jenkov.com/java-logging/configuration.html
[4] javadoc java.util.logging.Handler
http://docs.oracle.com/javase/7/docs/api/java/util/logging/Handler.html
[5] javadoc java.util.logging.LogManager
http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html
[6] default logging.properties provided by JRE 7
https://gist.github.com/maartenl/9346237

Tuesday, 21 January 2014

Simple Logging

Had a Dickens of a time, getting logging to work. I thought it would be as simple as assigning a ConsoleHandler to my logger.

Turns out that there's a Loglevel on the ConsoleHandler as well, and it is set to INFO level messages by default.

Just setting the log level on the Logger itself to Level.ALL is just not enough.

The example here is sufficient for the most basic logging of simple one-class Hello-world applications.

Of course, you can always use System.out.println statements instead for simple one-class applications, but I think it's a bad habit to get into.


Configuration


Logging configuration can be done by means of a properties file.[1][2]

The properties file can be added during the startup as VM parameters, for example -Djava.util.logging.config.file=/home/mrbear/NetBeansProjects/jtail/logging.properties.

If no properties file is provided, the default is "lib/logging.properties" in the JRE directory.[2] The default file will only show INFO messages.

The following example will show all logging all of the time.

For information on programmable logging (Class-based), see the references.

The Global Logger

To make logging even in simple cases, as easy as possible, the global logger was introduced and in Java 7 it is easily referenced.
System.out.println("x=" + x);
Can therefore be replaced by:
Logger.getGlobal().finest("x=" + x);
Unfortunately, you still have to set the LogLevel appropriately, similarly as displayed in the first code example above.

Update 2015/03/26: added the Global logger info.

References

[1] Java Logging - Configuration
http://tutorials.jenkov.com/java-logging/configuration.html
[2] LogManager - Javadoc
http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html