DataARTIGO

Usando MongoDB para armazenar log de aplicações

Neste artigo veremos uma solução para centralizar o gerenciamento de logs dos servidores utilizando MongoDB, Log4mongo e Log4j.

O MongoDBMongoDB19 conteúdosMongoDB e LGPD: Quais os recursos disponíveis?Data · jul 2019Laravel & MongoDB: saiba mais sobre embedded documentsData · abr 2021LEFT JOIN no MongoDB, não é magia… É Aggregation Framework!!!Data · set 2019Ver tudo em Data é uma boa alternativa para armazenar log de servidores. Neste artigo veremos uma solução para centralizar o gerenciamento de logs dos servidores utilizando MongoDB, Log4mongo e Log4j. Com o conector para Hadoop podemos fazer análises complexas dos logs. Essa combinação de NoSQL com Hadoop é muito interessante neste momento em que o big data vem se popularizando. Na segunda parte do artigo há um tutorial de MongoDB, com os passos para instalação e exemplos de consultas.

Os eventos de log são armazenados em JSON, que é um formato adequado para esse tipo de informação. O MongoDB é schemaless, ou seja, você pode adicionar novos campos quando quiser, o que aumenta a flexibilidade da solução. O MongoDB é rápido tanto para inclusão quanto para consultas, suporta milhares de inserts por segundo e, além das queries normais, também podem podemos rodar análises usando JavaScriptJavaScript116 conteúdosJavaScript em 2020: O que esperarDev (Back & Front) · jan 2020Campos públicos e privados em classes JavaScript – O que vem por aí no ESNextDev (Back & Front) · abr 201929 anos de JavaScript!Dev (Back & Front) · jan 2025Ver tudo em Dev (Back & Front) para executar jobs MapReduce no Hadoop. As vantagens de usar o MongoDB para centralizar os eventos de log dos servidores incluem:

  • Encontrar informações de qualquer aplicação;
  • Estatísticas de acesso e utilização;
  • Erros no histórico da aplicação;
  • Auditoria.

Em um cenário tradicional, os eventos de log são armazenados em texto, gravados no sistema de arquivo em servidores diferentes, de forma que a recuperação de informações pode ser bem complicada e demorada. Não dá para simplesmente consultar todos os eventos de um usuário ou de um módulo em determinado período. Novamente, os arquivos estão distribuídos em vários lugares e têm muitos gigabytes de tamanho. O procedimento normal seria baixar os dados do servidor e procurar com uma ferramenta de texto. É um processo demorado que pode precisar do envolvimento de outras equipes.

Existem casos em que o log é armazenado em banco de dados relacional. A recuperação de eventos de log é mais simples, já que temos o SQL para consultar os dados. Mas há alguns pontos negativos:

  •     Manutenção de mais uma base de dados, que pode ser maior que a base do próprio sistema;
  •     A inclusão de registros é lenta em bases relacionais;
  •     A consulta é lenta. Lembre-se que um sistema médio tem milhões de eventos.

Log4mongo

Vamos utilizar a biblioteca Log4mongo (http://log4mongo.org) para armazenar os eventos de log no MongoDB. Esta biblioteca inclui diversos appenders para o Log4J e com apenas algumas configurações já podemos gravar os eventos no MongoDB.

O Log4mongo tem suporte para diferentes linguagens:

  • Java
  • .Net
  • PHP
  • Python

Como configurar o Log4mongo

Para configurar o Log4mongo no seu projeto, siga os passos abaixo:

  • Faça o download e instale o MongoDB. Está disponível aqui (http://www.mongodb.org/downloads).
  • Inicie o banco de dados com o comando DIR_MONGODB/bin/mongod –dbpath DIR_DADOS.
  • Crie o arquivo de configuração do log4j.properties na sua aplicação com o bloco de código abaixo.

log4j.rootLogger=INFO, MongoDB, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L – %m%n

log4j.appender.MongoDB=org.log4mongo.MongoDbAppender
log4j.appender.MongoDB.databaseName=db-e-commerceE-commerce21 conteúdosECBR Club: novo espaço para devs se conectarem ao ecossistema de e-commerceDev (Back & Front) · mai 2025TOTVS anuncia joint venture com VTEXMarketing Tech · mai 2019Jovens da Brasilândia recebem formação gratuita em tecnologiaGestão Dev & TI · jul 2025Ver tudo em Marketing Tech
log4j.appender.MongoDB.collectionName=log

log4j.logger.javax.faces=INFO, MongoDB
log4j.logger.org.primefaces=INFO, MongoDB
log4j.logger.com.sun.faces=INFO, MongoDB
log4j.logger.org.hibernate=INFO, MongoDB

Código-fonte

Está disponível no GitHub uma aplicação de exemplo com o código-fonte desse artigo.

Para gerar eventos de log, navegue pela aplicação web ou execute a classe TesteInsereCategoria. Neste projeto serão utilizadas as seguintes tecnologias:

  • Log4mongo
  • JSF 2
  • Primefaces 4
  • JPA 2
  • Tomcat 7

O objetivo é capturar os eventos de log da aplicação. Dessa forma, poderemos dizer quais as páginas mais acessadas, quem alterou um determinado registro e qual o erro mais comum da aplicação.

  • Inclusão, alteração e exclusão de dados;
  • Consultas realizadas;
  • Acesso a páginas;
  • Comandos executados;
  • Exceções disparadas.

Como instalar o MongoDB

Após o download do MongoDB, descompacte o arquivo no seu diretório raiz. Vamos considerar que a instalação está no diretório C:\mongodb. Vamos chamar esse diretório de DIR_MONGODB. Você deve criar um diretório para os dados do banco, então crie o diretório C:\dados\mongodb-data. Este será o diretório DIR_DADOS_MONGODB.

Os executáveis do MongoDB estão em DIR_MONGODB/bin. Acesse esse diretório através do terminal. Os comandos de administração do MongoDB são através de linha de comando mas existem algumas ferramentas úteis aqui.

Como iniciar o MongoDB

Para iniciar o MongoDB, use o comando mongod. Você deve acessar o diretório DIR_MONGODB/bin no console:

mongod --dbpath DIR_DADOS_MONGODB

Para acessar o console de administração do MongoDB:

Mongo

Verifique a resposta do terminal. Deve ser algo similar à listagem abaixo. A partir de agora podemos executar comandos no MongoDB.

MongoDB shell version: 2.4.9

connecting to: test
>

Como criar um database no MongoDB

Não existe a opção de criar uma database no MongoDB. Você pode simplesmente executar o comando “use nome-database” e inserir algum registro. Automaticamente o MongoDB verifica se a base de dados já existe. Se não existir, será criada. O mesmo princípio se aplica às collections, que são como as tabelas de um banco relacional.

Ao iniciar o Tomcat com a nossa aplicação de exemplo, o Filter será inicializado e vai inserir o primeiro registro no banco. Como a base não existia, tanto o banco quanto o esquema serão criados.

A base de dados configurada no Log4mongo se chama db-e-commerce; vamos analisar o que já tem por lá. Para visualizar as bases de dados existentes no seu MongoDB, use o comando:

> show dbs

Caso a collection ainda não tenha sido criada, a resposta do terminal será:

local  0.078125GB
test  (empty)

Se você já iniciou o Tomcat, a base de dados foi criada e a resposta do terminal será:

db-e-commerce  0.203125GB
local  0.078125GB

Para visualizar as coleções que já existem:

> use db-e-commerce
> show collections

Você deve visualizar a collection log, que foi configurada para essa aplicação no log4j.properties.

log
system.indexes

Ou então, para o mesmo resultado:

> show tables

Podemos usar também o comando:

> db.getCollectionNames()
[ "log", "system.indexes" ]

Ou ainda:

> db.system.namespaces.find()

{ "name" : "db-e-commerce.system.indexes" }
{ "name" : "db-e-commerce.log.$_id_" }
{ "name" : "db-e-commerce.log" }

Como criar capped collection no MongoDB

Uma capped collection é uma tabela com tamanho fixo, para evitar estouro no disco. Este comando é opcional, já que estamos apenas fazendo testes.

> db.createCollection('log', {capped:true, size:100000000})

Como fazer consultas no MongoDB

Com os eventos de log centralizados no MongoDB, é bem fácil recuperar informações através das consultas do banco. A linguagem de consulta é bastante completa e a resposta é rápida. Para retornar todos os registros, utilize db.log.find():

> db.log.find()

A resposta será um JSON similar à listagem abaixo:

{ “_id” : ObjectId(“53088a3044ae7fe240c3aac9”), “timestamp” : ISODate(“2014-02-22T11:29:52.221Z”), “level” : “INFO”, “thread” : “localhost-startStop-1”, “message” : “init”, “loggerName” : { “fullyQualifiedClassName” : “net.marcoreis.ecommerce.util.FiltroLogger”, “package” : [  “net”,  “marcoreis”,  “ecommerce”,  “util”,  “FiltroLogger” ], “className” : “FiltroLogger” }, “fileName” : “FiltroLogger.java”, “method” : “init”, “lineNumber” : “20”, “class” : { “fullyQualifiedClassName” : “net.marcoreis.ecommerce.util.FiltroLogger”, “package” : [  “net”,  “marcoreis”,  “ecommerce”,  “util”,  “FiltroLogger” ], “className” : “FiltroLogger” }, “host” : { “process” : “27662@marcoreis-ultrabook”, “name” : “marcoreis-ultrabook”, “ip” : “127.0.0.1” } }

Para consultar os diferentes níveis de erros já gravados, como o “SELECT DISTINCT” do SQL:

> db.log.distinct("level")
[ "INFO", "ERROR", "WARN" ]

Contar quantos registros já foram gravados:

> db.log.count()
416141

Contar quantos registros do tipo INFO:

> db.log.count({"level":"INFO"})
416113

Filtrando o find para mostrar somente o nível ERROR:

> db.log.find({"level":"ERROR"})

O resultado será:

{ “_id” : ObjectId(“53088d4e44ae7fe240c3ab09”), “timestamp” : ISODate(“2014-02-22T11:43:10.751Z”), “level” : “ERROR”, “thread” : “http-bio-8080-exec-7”, “message” : “Usuário inválido”, “loggerName” : { “fullyQualifiedClassName” : “net.marcoreis.ecommerce.controller.BaseBean”, “package” : [  “net”,  “marcoreis”,  “ecommerce”,  “controller”,  “BaseBean” ], “className” : “BaseBean” }, “fileName” : “BaseBean.java”, “method” : “errorMsg”, “lineNumber” : “45”, “class” : { “fullyQualifiedClassName” : “net.marcoreis.ecommerce.controller.BaseBean”, “package” : [  “net”,  “marcoreis”,  “ecommerce”,  “controller”,  “BaseBean” ], “className” : “BaseBean” }, “host” : { “process” : “27662@marcoreis-ultrabook”, “name” : “marcoreis-ultrabook”, “ip” : “127.0.0.1” } }

Registros entre duas datas, como o “BETWEEN” do SQL:

> db.log.find({"timestamp":{$gte:ISODate("2014-02-22"), $lte:ISODate("2014-02-24")}}).count()

Recuperar o primeiro documento da base, como o “ORDER BY”. Se houver muitos registros você deve utilizar o limit ou criar um índice.

> db.log.find().sort({"timestamp":1}).limit(1)

Recuperar o documento mais recente da base:

> db.log.find().sort({"timestamp":1}).limit(-1)

Encontrar todas as páginas JSF que foram acessadas:

> db.log.distinct( "message", {"class.className" : "FiltroLogger" } )

Conclusão

É claro que nenhuma solução de log é perfeita. Todas terão pontos positivos e negativos. A ideia deste artigo foi mostrar uma alternativa usando um banco NoSQL.

Nesta solução com MongoDB, o ponto alto é que temos dados muito detalhados. E podemos adicionar cada vez mais detalhes para conhecer melhor o comportamento da aplicação e do usuário. Através dos comandos de consulta podemos recuperar e analisar os dados de forma centralizada, com uma visão global das aplicações.

Referências

trabalha como Arquiteto de Software no TJDFT, com experiência em JavaEE, servidores de aplicação e sistemas de missão crítica em projetos envolvendo o Poder Judiciário.Pesquisa a área de Information Retrieval imaginando como melhorar e democratizar o acesso à informação dentro das corporações.

Ver perfil