Habilitando e desabilitando mensagens de Log
Sumário
- Configurando o nível de log a partir da linha de comando
- Configurando o nível de log a partir de uma GUI
- Definindo o nível de log a partir de código em C++
Se você executou o programa na Lista 4.1, 4.4, e 4.5 por você mesmo (ou leu o exemplo de saída em Lista 4.2 cuidadosamente), você deve ter notado que nenhuma mensagem DEBUG
foi gerada, mesmo que esses programas chamem a macro ROS_DEBUG_STREAM
. O que aconteceu com as mensagens a nível DEBUG
? A resposta é que, por padrão, os programas ROS C++ apenas geram mensagens de log no nível INFO
e superior; tentativas de gerar mensagens no DEBUG
são descartadas.
Este é um exemplo especcífico do conceito de níveis de log, que especifica, para cada nó, um nível mínimo de gravidade. O nível de log padrão é INFO
, o qual explica a ausência de mensagens no nível DEBUG
de nosso programa de exemplo. A ideia geral por trás dos níveis de log é fornecer, em tempo de execução, a capacidade de regular o nível de detalhe dos logs de cada nó.
⚠️ Definir o nível de log é algo semelhante às opções de filtragem de gravidade em
rqt_console
. A diferença é que alterar o nível de log evita que as mensagens de log sejam geradas em sua origem, enquanto os filtros emrqt_console
aceitam qualquer mensagem de log de entrada e, seletivamente, escolhem não exibir algumas delas. Exceto por alguma sobrecarga, o efeito é semelhante.
⏩ Para mensagens de log que são desabilitadas pelo nível de log, a expressão da mensagem nem mesmo é avaliada. Isso é possível porque o
ROS_INFO_STREAM
, e construções semelhantes, são mais macros do que chamadores de função. As expansões dessas macros verificam se a mensagem está habilitada e só avaliam a própria expressão da mensagem se a resposta for sim. Isso significa (a) que você não deve depender de quaisquer efeitos colaterais que possam ocorrer ao construir a string da mensagem e (b) que as mensagens de log desabilitadas não tornarão seu programa mais lento, mesmo que o parâmetro para a macro de log seja demorado avaliar.
Existem diversas maneiras de definir o nível de log de um nó.
Configurando o nível de log a partir da linha de comando
Para definir o nível de log de um nó a partir da linha de comando, use um comando como este:
rosservice call /node-name/set_logger_level ros.package-name level
Este comando chama um serviço chamado set_logger_level
, que é fornecido automaticamente por cada nó. (Estudaremos os serviços com mais afinco no Capítulo 8.)
- O node-name é o nome do nó cujo nível de log você gostaria de definir;
- O package-name é, como você imagina, o nome do pacote que possui o nó;
- O parâmetro level é uma string, escolhida entre DEBUG, INFO, WARN, ERROR e FATAL, nomeando o nível de log a ser usado para esse nó
Por exemplo, para habilitar mensagens no nível DEBUG
em nosso programa de exemplo, poderíamos usar este comando:
rosservice call /count_and_log/set_logger_level ros.agitr DEBUG
Perceba que, como esse comando se comunica diretamente com o nó em questão, não podemos usá-lo até que o nó seja iniciado. Se tudo funcionar corretamente, esta chamada para rosservice
produzirá nada além de uma linha em branco.
⚠️ O serviço
set_logger_level
reportará um erro se você digitar incorretamente o nível de log desejado, mas não se você digitar incorretamente a parteros.*package-name*
.
⏩ O argumento
ros
.package-name pararosservice
é necessário para especificar o nome do log que gostaríamos de configurar. Internamente, o ROS usa uma biblioteca chamadalog4cxx
para implementar seus recursos de log. Tudo o que discutimos neste capítulo usa, nos bastidores, o log padrão, cujo nome éros
.nome-do-pacote. Entretanto, a biblioteca cliente ROS C++ também usa vários outros logs internamente, para rastrear coisas que geralmente não são interessantes para os usuários, até o nível de coisas como bytes sendo gravados e lidos, conexões sendo estabelecidas e descartadas e retornos de chamada sendo invocados. Como o serviçoset_logger_level
fornece uma interface para todos esses registradores, devemos especificar explicitamente qual log queremos configurar. Este nível extra de complexidade é o motivo pelo qual o comandorosservice
acima não falhará se você digitar incorretamente o nome do log. Ao invés de gerar um erro,log4cxx
silenciosamente (e, pode-se acrescentar, inutilmente) cria um novo log com o nome especificado.
Configurando o nível de log a partir de uma GUI
Se você preferir uma GUI ao invés da interface de linha de comando, tente este comando:
rqt_logger_level
A janela resultante, mostrada em Figura 4.3, permite que você selecione a partir de uma lista de nós, uma lista de logs - você certamente deseja ros
.nome do pacote - e finalmente uma lista de log de níveis. Alterar o nível do log usando esta ferramenta tem o mesmo efeito que o comando rosservice
mencionado acima, porque ele usa a mesma interface de chamada de serviço para cada nó.
Figura 4.3: A interface para rqt_logger_level
.
Definindo o nível de log a partir de código em C++
Também é possível que um nó modifique os seus próprios níveis de log. A maneira mais direta de fazer isso é dada acessando a infraestrutura log4cxx
que o ROS usa para implementar os seus recursos de log, usando um código como este:
#include <log4cxx/logger.h>
. . .
log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->setLevel(
ros::console::g_level_lookup[ros::console::levels::Debug]
);
ros::console::notifyLoggerLevelsChanged();
Além da camuflagem sintática necessária, este código deve ser prontamente identificável como configurando o nível de log para DEBUG
. O token Debug
pode, é claro, ser substituído por Info
, Warn
,Error
ou Fatal
.
⏩ A chamada para
ros::console::notifyLoggerLevelsChanged()
é necessária porque o status habilitado/desabilitado de cada instrução de registro é armazenado em cache. Ele pode ser omitido se você definir o nível de log antes que alguma instrução de registro sejam executadas.