Quantcast
Channel: Jean-Baptiste Onofré's Blog
Viewing all articles
Browse latest Browse all 38

Create custom log4j appender for Karaf and Pax Logging

$
0
0

Karaf leverages Pax Logging for the logging layer. Pax Logging provides an abstraction service for most popular logging frameworks, like SLF4J, Log4j, commons-logging, etc.

Karaf provides a default logging configuration in etc/org.ops4j.pax.logging.cfg file.

By default, all INFO log messages (rootLogger) are send into a file appender (in data/log/karaf.log). The file appender “maintains” one file of 1MB, and store up to 10 backup files.

Adding a new appender configuration, example with Syslog appender

We can add new appender configuration in the Karaf logging module.

For instance, we can add a syslog appender in etc/org.ops4j.pax.logging.cfg:


log4j.rootLogger = INFO, out, syslog, osgi:*
...
# Syslog appender
log4j.appender.syslog=org.apache.log4j.net.SyslogAppender
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
log4j.appender.syslog.layout.ConversionPattern=[%p] %c:%L - %m%n
log4j.appender.syslog.syslogHost=localhost
log4J.appender.syslog.facility=KARAF
log4j.appender.syslog.facilityPrinting=false
...

We create the syslog appender configuration, and we use this appender for the rootLogger.

Pax Logging provides all default Log4j appenders.

Creating a custom appender

It’s also possible to create your own appender.

For instance, you want to create MyJDBCAppender, extending the standard Log4J JDBCAppender. MyJDBCAppender has a better management of the quote in the SQL query for a DB2 backend for instance:


package org.apache.karaf.blog.logging.appender;

import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.jdbc.JDBCAppender;

/**
* Override apache log4j JDBCAppender for DB2 use (escaping of ' char in data)
* Need proper substitution of the ' char by {@link SQL_APOS} in the writing of the log4j sql property
*/
public class MyJDBCAppender extends JDBCAppender {

private static final String SQL_APOS = "{sql_apos}";
private static final String XML_APOS = "'";

/** {@inheritDoc} */
@Override
protected String getLogStatement(LoggingEvent event) {
String sqlLayout = getLayout().format(event);
// escape ' as standard sequence (') in the sql statement after layout
sqlLayout = sqlLayout.replace("'", XML_APOS);
// revert specific sequence as ' to have final executable sql statement
sqlLayout = sqlLayout.replace(SQL_APOS, "'");
return sqlLayout;
}

}

We put the MyJDBCAppender java file in a src/main/java/org/apache/karaf/blog/logging folder.

We package this appender as an OSGi bundle. This bundle is a fragment to the Pax Logging service bundle:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>org.apache.karaf.blog.logging.appender</groupId>
  <artifactId>org.apache.karaf.blog.logging.appender.jdbc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>bundle</packaging>

  <dependencies>
    <dependency>
      <groupId>org.ops4j.pax.logging</groupId>
      <artifactId>pax-logging-service</artifactId>
      <version>1.6.9</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.3.7</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>org.apache.karaf.blog.logging.appender.jdbc</Bundle-SymbolicName>
            <Export-Package>org.apache.karaf.blog.logging.appender</Export-Package>
            <Import-Package/>
            <Private-Package>org.apache.log4j.jdbc</Private-Package>
            <Fragment-Host>org.ops4j.pax.logging.pax-logging-service</Fragment-Host>
            <_failok>true</_failok>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

We can use our appender in etc/org.ops4j.pax.logging.cfg file, for instance:


log4j.rootLogger = INFO, out, myappender, osgi:*
...
log4j.appender.myappender=org.apache.karaf.blog.logging.appender.MyJDBCAppender
log4j.appender.myappender.url=jdbc:db2:....
log4j.appender.myappender.driver=com.ibm.db2.jcc.DB2Driver
log4j.appender.myappender.user=username
log4j.appender.myappender.password=password
log4j.appender.myappender.sql=insert into logs values({{sql_apos}%x{sql_apos}, {sql_apos}%d{sql_apos}, {sql_apos}%C{sql_apos}, {sql_apos}%p{sql_apos}, {sql_apos}%m{sql_apos})
log4j.appender.myappender.layout=org.apache.log4j.PatternLayout

In order to be loading very early in the Karaf bootstrap, our appender bundle should be present in the system folder and defined in etc/startup.properties.

The system folder has a “Maven repo like” structure. So you have to copy with:


system/groupId/artifactId/version/artifactId-version.jar

In our example, it means:


mkdir -p $KARAF_HOME/system/org/apache/karaf/blog/logging/appender
cp target/org.apache.karaf.blog.logging.appender.jdbc-1.0-SNAPSHOT.jar $KARAF_HOME/system/org/apache/karaf/blog/logging/appender/org.apache.karaf.blog.logging.appender.jdbc/1.0-SNAPSHOT/org.apache.karaf.blog.logging.appender.jdbc-1.0-SNAPSHOT.jar

and in etc/startup.properties, we define the appender bundle just after the pax-logging-service bundle:


...
org/ops4j/pax/logging/pax-logging-api/1.6.9/pax-logging-api-1.6.9.jar=8
org/ops4j/pax/logging/pax-logging-service/1.6.9/pax-logging-service-1.6.9.jar=8
org/apache/karaf/blog/logging/appender/org.apache.karaf.blog.logging.appender.jdbc/1.0-SNAPSHOT/org.apache.karaf.blog.logging.appender.jdbc-1.0-SNAPSHOT.jar=8
...

You can now start Karaf, it will use our new custom appender.


Viewing all articles
Browse latest Browse all 38

Trending Articles