Habilitando e desabilitando mensagens de Log

Sumário

  1. Configurando o nível de log a partir da linha de comando
  2. Configurando o nível de log a partir de uma GUI
  3. 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 em rqt_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 parte ros.*package-name*.

⏩ O argumento ros.package-name para rosservice é necessário para especificar o nome do log que gostaríamos de configurar. Internamente, o ROS usa uma biblioteca chamada log4cxx 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ço set_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 comando rosservice 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.