Salvando o Log no Banco de Dados no JBoss AS 7.1

Postado em Atualizado em

Obs: Pré Requisito Módulo JDBC MySQL
JBoss: jboss-as-7.1.0.CR1b

Algumas vezes necessitamos armazenar o log das nossas aplicações diretamente no banco de dados.  Podemos fazer isso através de Logs customizáveis. A comunidade JBoss.org, criou um excelente artigo sobre Custom Log Handlers, e o nosso post de hoje será baseado nesse artigo.

A comunidade deixou uma classe de exemplo, que extende java.util.logging.Handler, segue abaixo o código:

package com.JdbcLogger;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

import org.jboss.logmanager.MDC;

public class JdbcLogger extends Handler
  {
    private static final Object PARAM_TIMESTAMP = "$TIMESTAMP";
    private static final Object PARAM_LEVEL = "$LEVEL";
    private static final Object PARAM_MESSAGE = "$MESSAGE";
    private static final String PARAM_MDC = "$MDC[";
    private static final Object PARAM_PASSTROUGH = "?";

    private String driverClassName;
    private String jdbcUrl;
    private String username;
    private String password;
    private String insertStatement;

    private Connection connection;

    private List<String> parameters = new ArrayList<String>();

    @Override
    public void publish(LogRecord record)
    {
      if (!ensureReady())
     {
      return;
     }
    try
     {
       insertRecord(record);
     }
     catch (SQLException e)
     {
     e.printStackTrace();
    }
  }

   private synchronized boolean ensureReady()
   {
     if (connection != null)
     {
       return true;
     }
     try
     {
       parseStatementParameters();
       setupConnection();
     }
       catch (ClassNotFoundException e)
     {
       e.printStackTrace();
       return false;
     }
       catch (SQLException e)
     {
       e.printStackTrace();
      return false;
     }
      return true;
   }

   private void parseStatementParameters()
   {
      int paramsStart = insertStatement.indexOf("(");
      int paramsStop = insertStatement.lastIndexOf(")");
      String paramsString = insertStatement.substring(paramsStart + 1, paramsStop);
      for (String param : paramsString.split(","))
      {
         parameters.add(param.trim());
         paramsString = paramsString.replace(param, "?");
      }
       insertStatement = String.format("%s(%s)", insertStatement.substring(0, paramsStart), paramsString);
      }

   private void setupConnection() throws ClassNotFoundException, SQLException
   {
      Class.forName(driverClassName);
      connection = DriverManager.getConnection(jdbcUrl, username, password);
   }

   private void insertRecord(LogRecord logRecord) throws SQLException
   {
     PreparedStatement statement = null;
     try
     {
        statement = connection.prepareStatement(insertStatement);
        setStatementParameters(statement, logRecord);
        statement.executeUpdate();
     }
     finally
     {
      if (statement != null)
      {
        statement.close();
      }
    }
   }

  private void setStatementParameters(PreparedStatement statement, LogRecord logRecord) throws SQLException
  {
   for (int i = 0; i < parameters.size(); i++)
   {
    statement.setObject(i + 1, getParameterValue(i, logRecord));
   }
  }

  private Object getParameterValue(int i, LogRecord record)
  {
   String parameter = parameters.get(i);
   if (PARAM_PASSTROUGH.equals(parameter))
  {
   return null;
  }
   if (PARAM_TIMESTAMP.equals(parameter))
  {
   return new Date(record.getMillis());
  }
   else if (PARAM_LEVEL.equals(parameter))
  {
   return record.getLevel().toString();
  }
   else if (PARAM_MESSAGE.equals(parameter))
  {
   return getFormatter().format(record);
  }
   else if (parameter.startsWith(PARAM_MDC))
  {
   int startIndex = parameter.indexOf("[") + 1;
   int stopIndex = parameter.indexOf("]") - 1;
   String key = parameter.substring(startIndex, stopIndex + 1);
   return MDC.get(key);
  }
  else
  {
   return parameter;
  }
 }

  @Override
  public void flush()
  {
  }

  @Override
  public void close()
   {
     if (connection != null)
   {
    try
    {
     connection.close();
    }
     catch (SQLException e)
    {
     e.printStackTrace();
    }
   }
  }

  public void setDriverClassName(String driverClassName)
  {
   this.driverClassName = driverClassName;
  }

  public void setJdbcUrl(String jdbcUrl)
  {
   this.jdbcUrl = jdbcUrl;
  }

  public void setUsername(String username)
  {
   this.username = username;
  }

  public void setPassword(String password)
  {
   this.password = password;
  }

  public void setInsertStatement(String insertStatement)
  {
   this.insertStatement = insertStatement;
  }
 }

Agora devemos gerar um arquivo .jar para empacotar a classe acima, como por exemplo logger.jar
O próximo passo é criar um módulo, para disponibilizarmos o nosso log no JBoss AS 7.

Com o comando abaixo, criamos a estrutura de diretórios necessária para o funcionamento.

   mkdir -p JBOSS_HOME/modules/com/JdbcLogger/main

Copie o logger.jar gerado anteriormente para JBOSS_HOME/modules/com/JDBCLogger/main

Agora crie o arquivo module.xml

   vim JBOSS_HOME/modules/com/JdbcLogger/main/module.xml

E e adicione o conteúdo abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.JdbcLogger">
<resources>
       <resource-root path="logger.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
    <module name="org.jboss.logging"/>
    <module name="org.jboss.logmanager"/>
    <module name="com.mysql"/>
   </dependencies>
</module>

Lembrando que o módulo com.mysql, já precisa estar disponível no JBoss AS 7. Caso não saiba como criar, veja o artigo https://jbossdivers.wordpress.com/2012/01/20/introducao-ao-jboss-as-7-parte-2/ .

No arquivo JBOSS_HOME/standalone/configuration/standalone.xml,  e  subsystem jboss:domain:logging:1.1, adicione o conteúdo abaixo:

<custom-handler name="DB" module="com.JdbcLogger">
  <level name="INFO"/>
  <formatter>
     <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t)%s%E%n"/>
  </formatter>
  <properties>
      <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
      <property name="jdbcUrl" value="jdbc:mysql://192.168.0.189:3306/security"/>
      <property name="username" value="root"/>
      <property name="password" value="123456"/>
      <property name="insertStatement" value="insert into log_table values (?, $TIMESTAMP, $LEVEL, $MDC[ip], $MDC[user], $MESSAGE, hardcoded)"/>
  </properties>
</custom-handler>

No root logger adicione o handler criado.

<root-logger>
   <level name="INFO"/>
   <handlers>
      <handler name="CONSOLE"/>
      <handler name="FILE"/>
      <handler name="DB"/>
   </handlers>
</root-logger>

A tabela abaixo, deve ser criada no banco de dados que armazenará os logs ( no nosso caso o security ).

   CREATE TABLE log_table(id INT(11) NOT NULL AUTO_INCREMENT, timestamp VARCHAR(255) DEFAULT NULL,level VARCHAR(255) DEFAULT NULL,mdc_ip VARCHAR(255) DEFAULT NULL,mdc_user VARCHAR(255) DEFAULT NULL,message VARCHAR(1500) DEFAULT NULL,hardcoded VARCHAR(255) DEFAULT NULL,PRIMARY KEY (id))ENGINE = INNODB AUTO_INCREMENT = 1;

Inicie o JBoss AS 7

./JBOSS_HOME/bin/standalone.sh

Agora realize o select na tabela log_table.

   select * from log_table

Alguns dados deverão ser retornados, como na imagem abaixo.

Podemos ainda utilizar um dominio de segurança encriptado para os dados de acesso ao banco de dados, para isso vejam o Post Introdução ao JBoss AS parte 2 .

Espero que seja útil🙂
Abraços!

Fonte: https://community.jboss.org/wiki/CustomLogHandlersOn701

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s