[Este blog foi distribuído pelo site http://nitschinger.at/].

Introdução

Há uma enorme variedade de estruturas de registro para Java, e é difícil agradar a todos. Para entender como o registro em log é tratado atualmente no SDK, temos que voltar alguns anos atrás. Como você deve saber, o SDK depende do cache de spymem e, portanto, também herda seus mecanismos de registro. Na época em que o @dustin escreveu spy, não havia uma boa abstração para registro disponível (como SLF4J), então ele escreveu o seu próprio. Atualmente, as coisas mudaram, mas o espião ainda herda esse legado.

No momento em que este artigo foi escrito, o SDK suporta o registro em um registrador padrão simples (registros em STDERR a partir do nível INFO), Log4J e o SunLogger (java.util.logging). Na próxima versão 2.9.0 do spymemcached, ele também suportará a fachada de registro SLF4J, na qual você poderá conectar sua própria implementação. A próxima versão do SDK (provavelmente a 1.1.7) dependerá do spy 2.9, portanto, você também obterá os benefícios.

Antes de nos aprofundarmos nos conceitos, aqui estão os níveis de registro suportados (definidos por net.spy.memcached.compat.log.Level):

  1. TRACE (com 2.9)
  2. DEBUG
  3. INFORMAÇÕES
  4. AVISO
  5. ERRO
  6. FATAL

Lembre-se de que diferentes registradores implementam níveis diferentes, portanto, para alguns deles, é necessário fazer um mapeamento. Isso será observado durante as descrições de cada implementação.

Agora, veremos os diferentes mecanismos de registro disponíveis e como você pode configurá-los. O SLF4J será abordado no final.

Troca de registro

Se você não alterar nada, o registrador padrão será usado. Esse mecanismo apenas imprime mensagens de registro no STDERR (do nível INFO para cima). É provável que você queira integrar o SDK com a mesma biblioteca de registro que você também usa. O LoggerFactory dentro do spy decide na construção qual deles escolher, com base em uma propriedade do sistema. Portanto, você pode alterar isso programaticamente ou por meio de um parâmetro para o java comando.

Se você quiser usar o Log4JLogger de forma programática, faça-o desta forma (antes de inicializar o Cliente Couchbase objeto):

Propriedades systemProperties = System.getProperties();
systemProperties.put("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");
System.setProperties(systemProperties);

Obviamente, você precisa adicionar o JAR do Log4J ao CLASSPATH para que ele funcione (como veremos mais adiante). Como alternativa, você pode configurá-lo dessa forma na linha de comando:

java -Dnet.spy.log.LoggerImpl=net.spy.memcached.compat.log.Log4JLogger ...

Agora que sabemos como habilitar as diferentes implementações, vamos examiná-las mais detalhadamente.

O registrador padrão simples

Se você não alterar nada, o SDK usará o DefaultLogger (net.spy.memcached.compat.log.DefaultLogger). Esse registrador não tem dependências e imprime todas as mensagens de registro de nível INFO ou superior (INFO, WARN, ERROR e FATAL) no STDERR do sistema. Como o STDERR é coberto automaticamente pela maioria dos IDEs, você também os verá na janela de saída do console.

Como é muito simples, não é possível personalizar esse comportamento. Cada mensagem de registro também recebe um registro de data e hora (o formato é aaaa-MM-dd HH:mm:ss.SSS). A conexão com o Couchbase geralmente é assim:

 
2013-05-07 12:28:41.852 INFO com.couchbase.client.CouchbaseConnection: Adicionado {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} à fila de conexão
2013-05-07 12:28:41.862 INFO com.couchbase.client.CouchbaseConnection: Estado da conexão alterado para sun.nio.ch.SelectionKeyImpl@3d9360e2
2013-05-07 12:28:41.887 INFO com.couchbase.client.ViewConnection: Adicionado localhost à fila de conexão
2013-05-07 12:28:41.888 INFO com.couchbase.client.CouchbaseClient: A propriedade viewmode não está definida. Definindo viewmode para o modo de produção
2013-05-07 12:28:41.986 INFO com.couchbase.client.CouchbaseConnection: Encerrar o cliente Couchbase
2013-05-07 12:28:41.991 INFO com.couchbase.client.ViewConnection: O nó localhost não tem operações na fila
2013-05-07 12:28:41.992 INFO com.couchbase.client.ViewNode: Reator de E/S encerrado para localhost
 

Portanto, o formato é sempre o mesmo: . Lembre-se de que as mensagens DEBUG ou similares não serão registradas, portanto, você não as verá com o DefaultLogger.

 

O SunLogger (java.util.logging)

O SunLogger também não introduz dependências adicionais, pois depende do java.util.logging implementação. A java.util.logging.Level enum define os seguintes níveis: ALL, CONFIG, FINEST, FINER, FINE, INFO, WARNING, SEVERE e OFF. Como isso não mapeia bem os nossos níveis definidos, aqui está o mapeamento que acontece:

 
  1. TRACE para FINEST (com 2.9)
  2. DEBUG para FINE
  3. INFO para INFO
  4. WARN para WARNING
  5. ERROR a SEVERE
  6. FATAL a SEVERO
 
Sem nenhuma outra alteração, o SunLogger também imprime a partir do nível INFO, da seguinte forma:
 
7 de maio de 2013 12:42:16 PM com.couchbase.client.CouchbaseProperties setPropertyFile
INFO: Não foi possível carregar o arquivo de propriedades "cbclient.properties" porque: Arquivo não encontrado com o carregador de classes do sistema.
7 de maio de 2013 12:42:16 PM net.spy.memcached.MemcachedConnection createConnections
INFO: Adicionado {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} à fila de conexão
7 de maio de 2013 12:42:16 PM net.spy.memcached.MemcachedConnection handleIO
INFO: Estado da conexão alterado para sun.nio.ch.SelectionKeyImpl@4ce2cb55
7 de maio de 2013 12:42:16 PM com.couchbase.client.ViewConnection createConnections
INFO: Adicionado localhost à fila de conexão
7 de maio de 2013 12:42:16 PM com.couchbase.client.CouchbaseClient
INFO: A propriedade viewmode não está definida. Definição de viewmode para o modo de produção
7 de maio de 2013 12:42:16 PM com.couchbase.client.CouchbaseConnection run
INFO: Encerrar o cliente Couchbase
7 de maio de 2013 12:42:16 PM com.couchbase.client.ViewConnection shutdown
INFO: O nó localhost não tem operações na fila
7 de maio de 2013 12:42:16 PM com.couchbase.client.ViewNode$1 run
INFO: Reator de E/S encerrado para localhost
 

Se quiser alterar o nível de registro para DEBUG e inferior, faça isso da seguinte forma:

 
Logger.getLogger("com.couchbase.client").setLevel(Level.FINEST);
 

Agora, há mais uma coisa que você precisa fazer se quiser imprimir todas as mensagens de depuração no console. Você definiu o nível de registro corretamente, mas o ConsoleHandler ainda não está definido como depuração (portanto, provavelmente você pagará o preço do registro de depuração, mas não verá nada no seu IDE).

 
for(Handler h : Logger.getLogger("com.couchbase.client").getParent().getHandlers()) {
     if(h instanceof ConsoleHandler) {
        h.setLevel(Level.FINEST);
     }
}
 

Portanto, aqui está um exemplo completo de como usar o SunLogger e obter todas as mensagens de depuração no console.

 
    Propriedades systemProperties = System.getProperties();
    systemProperties.put("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");
    System.setProperties(systemProperties);

    Logger logger = Logger.getLogger("com.couchbase.client");
    logger.setLevel(Level.FINEST);
    for(Handler h : logger.getParent().getHandlers()) {
       se(h instanceof ConsoleHandler){
         h.setLevel(Level.FINEST);
       }
    }

 

Em seguida, basta ir em frente e criar seu Cliente Couchbase você verá uma saída detalhada como esta (cortada aqui):

 
7 de maio de 2013 12:54:34 PM com.couchbase.client.vbucket.ReconfigurableObserver update
FINEST: Recebeu uma atualização, notificando os reconfiguráveis sobre um com.couchbase.client.vbucket.config.Bucketcom.couchbase.client.vbucket.config.Bucket@3d77949
7 de maio de 2013 12:54:34 PM com.couchbase.client.vbucket.ReconfigurableObserver update
FINEST: Recebeu uma atualização, notificando os reconfiguráveis sobre um com.couchbase.client.vbucket.config.Bucketcom.couchbase.client.vbucket.config.Bucket@4e927ae
7 de maio de 2013 12:54:34 PM com.couchbase.client.vbucket.ReconfigurableObserver update
FINEST: Ele diz que é padrão e está se comunicando com /pools/default/bucketsStreaming/default?bucket_uuid=adfff22b70e09fafaa26ca37b7e05e9d
7 de maio de 2013 12:54:34 PM com.couchbase.client.vbucket.ReconfigurableObserver updat
FINEST: Ele diz que é padrão e está se comunicando com /pools/default/bucketsStreaming/default?bucket_uuid=adfff22b70e09fafaa26ca37b7e05e9d
 

Log4J

A maioria das pessoas precisará de mais flexibilidade, e o Log4J era (e ainda é) padrão em muitos aplicativos. O SDK também oferece suporte ao Log4J. Para que ele funcione, primeiro você precisa definir a instância corretamente:

 
    Propriedades systemProperties = System.getProperties();
    systemProperties.put("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");
    System.setProperties(systemProperties);
 

Agora, se você executar isso, receberá um erro informando que algumas das classes do Log4J não podem ser encontradas. Isso não é uma surpresa, pois elas não estão no classpath. Vamos corrigir isso adicionando-as adequadamente. Se você usa o maven, adicione o log4j.log4j (a versão atual é 1.2.17). Você também pode simplesmente fazer o download do JAR e adicioná-lo ao CLASSPATH conforme necessário.

 
Agora, se o executarmos novamente, receberemos outro erro:
 
log4j:WARN Não foi possível encontrar nenhum anexo para o registrador (com.couchbase.client.vbucket.ConfigurationProviderHTTP).
log4j:WARN Por favor, inicialize o sistema log4j corretamente.
log4j:WARN Consulte http://logging.apache.org/log4j/1.2/faq.html#noconfig para obter mais informações.
 

Uma maneira de corrigir isso é obter um log4j.xml em nosso CLASSPATH, mas para que ele funcione rapidamente, o Log4J fornece um arquivo de configuração BasicConfigurator. Logo após as configurações de propriedade do sistema, adicione isto:

 
org.apache.log4j.BasicConfigurator.configure();
 

Se você executá-lo com a alteração de código aplicada, verá que as mensagens de registro são bem impressas. Você também pode ver que elas aparecem diretamente no nível DEBUG (e até mesmo contêm informações de qual thread elas foram registradas):

 
69 [main] INFO com.couchbase.client.CouchbaseConnection - Adicionado {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} à fila de conexão
70 [main] DEBUG com.couchbase.client.vbucket.VBucketNodeLocator - Atualizando o nodesMap no VBucketNodeLocator.
73 [main] DEBUG com.couchbase.client.vbucket.VBucketNodeLocator - Adicionando nó com nome de host 127.0.0.1:11210.
74 [main] DEBUG com.couchbase.client.vbucket.VBucketNodeLocator - O nó adicionado é {QA sa=localhost/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=8}.
74 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG com.couchbase.client.CouchbaseConnection - Concluído o tratamento da fila.
74 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG com.couchbase.client.CouchbaseConnection - Selecionando com atraso de 0ms
79 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG com.couchbase.client.CouchbaseConnection - Selected 1, selected 1 keys
79 [IO do Memcached sobre
 

Você pode controlar os níveis de registro por meio dos mecanismos usuais do Log4J. Não entrarei em detalhes sobre eles aqui, portanto, por favor confira sua documentação oficial (por exemplo, sobre como usar o Configurador de propriedades em vez disso).

Por falar em Log4J,  Steffen Larsen implementou um Apêndice do Log4J para armazenar os registros no Couchbase (em vez de em um arquivo)!

A nova fachada: SLF4J

Não vincular o aplicativo a uma biblioteca de registro específica é sempre uma boa ideia. O SLF4J é uma fachada para várias estruturas de registro plugáveis por trás dele. Portanto, você pode escolher a implementação de registro durante o tempo de execução, seja ela retorno de registroLog4J ou outros. Como já experimentamos o Log4J, vamos fazer com que o SLF4J funcione com o Logback, um dos outros frameworks de registro muito comuns no mercado.

Observe que o suporte ao SLF4J estará disponível na versão 1.9.0 do spymemcached e, portanto, também em uma das próximas versões do Couchbase Java SDK.

Primeiro, precisamos configurá-lo adequadamente:

Propriedades systemProperties = System.getProperties();
systemProperties.put("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SLF4JLogger");
System.setProperties(systemProperties);
 

Agora, precisamos incluir dois JARs em nosso classpath. O primeiro é a API de fachada do SLF4J e o outro é a estrutura de registro de nossa escolha. O pacote da API de fachada é chamado slf4j-api (esse pacote sempre precisa estar no lugar) e, como queremos usar o logback, precisamos incluir o pacote logback-clássico JAR. Observe que isso não é específico do SDK; você pode encontrar essas informações aqui. Se você usa o maven, pode usar este snippet:

   
      org.slf4j
      slf4j-api
      1.7.5
   

   
      ch.qos.logback
      logback-clássico
      1.0.12
   
 

O SLF4J pegará automaticamente nossa implementação de logback, de modo que os registros terão a seguinte aparência:

 
13:25:43.692 [main] INFO c.c.client.CouchbaseConnection - Adicionado {QA sa=/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} à fila de conexão
13:25:43.694 [main] DEBUG c.c.c.vbucket.VBucketNodeLocator - Atualizando o nodesMap no VBucketNodeLocator.
13:25:43.697 [main] DEBUG c.c.c.vbucket.VBucketNodeLocator - Adicionando nó com nome de host 127.0.0.1:11210.
13:25:43.697 [main] DEBUG c.c.c.vbucket.VBucketNodeLocator - O nó adicionado é {QA sa=localhost/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=8}.
13:25:43.698 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG c.c.client.CouchbaseConnection - Concluído o tratamento da fila.
13:25:43.699 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG c.c.client.CouchbaseConnection - Selecionando com atraso de 0ms
13:25:43.702 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG c.c.client.CouchbaseConnection - Selecionou 1, selecionou 1 chaves
13:25:43.703 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] DEBUG c.c.client.CouchbaseConnection - Manipulando IO para: sun.nio.ch.SelectionKeyImpl@48ff2413 (r=false, w=false, c=true, op={QA sa=localhost/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=8})
13:25:43.703 [Memcached IO over {MemcachedConnection to localhost/127.0.0.1:11210}] INFO c.c.client.CouchbaseConnection - Estado da conexão alterado para sun.nio.ch.SelectionKeyImpl@48ff2413
13:25:43.713
 

Como você pode ver, eles também incluem o registro de nível DEBUG aqui. Se você não incluir a implementação de registro durante o tempo de execução, o SLF4J reclamará na inicialização:

 
SLF4J: Falha ao carregar a classe "org.slf4j.impl.StaticLoggerBinder".
SLF4J: implementação padrão do registrador sem operação (NOP)
SLF4J: Consulte http://www.slf4j.org/codes.html#StaticLoggerBinder para obter mais detalhes
 
Se você quiser saber como configurar o logback, veja aqui.
 

Resumo

Depois de conhecer a abstração no spymemcached e como ela funciona, a troca de implementações de registro é fácil e direta. Se você trabalhar com uma das pessoas do Couchbase para relatar erros, tente incluir a saída com DEBUG ativado, pois isso inclui muitas informações úteis que podem ser usadas para determinar as origens da falha.

Com a fachada SLF4J adicionada na próxima versão do spy (2.9), você poderá conectar todas as grandes estruturas de registro existentes no SDK. Informe-nos se encontrar um caso de uso não coberto por esses mecanismos ou se tiver outros comentários sobre o assunto.

Autor

Postado por Michael Nitschinger

Michael Nitschinger trabalha como engenheiro de software principal na Couchbase. Ele é o arquiteto e mantenedor do Couchbase Java SDK, um dos primeiros drivers de banco de dados totalmente reativos na JVM. Ele também é o autor e mantenedor do Couchbase Spark Connector. Michael participa ativamente da comunidade de código aberto e contribui para vários outros projetos, como RxJava e Netty.

Deixar uma resposta