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 MongoDB↳MongoDB19 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 JavaScript↳JavaScript116 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-commerce↳E-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
- http://blog.mongodb.org/post/172254834/mongodb-is-fantastic-for-logging – MongoDB is fantastic for logging
- http://docs.mongodb.org/ecosystem/use-cases/storing-log-data – Storing log data
- http://www.sunzhongkui.me/setup-centralized-log-system-with-mongodb – Setup centralized log system with MongoDB
- http://blog.mongodb.org/post/116405435/capped-collections – Capped collections
- http://www.slideshare.net/WombatNation/logging-app-behavior-to-mongo-db – Logging app behavior to MongoDB





