Criação de log no kernel: APIs e implementação

Do kernel até os logs de espaço do usuário

Em desenvolvimento de kernel, usamos printk para criação de log sem pensar muito a respeito. Mas você já levou em consideração o processo e a implementação subjacente da criação de log no kernel? Explore todo o processo da criação de log no kernel, desde printk até a inserção no arquivo de log do espaço do usuário.

M. Tim Jones, Consultant Engineer, Emulex Corp.

M. Tim JonesM. Tim Jones é arquiteto de firmware integrado e autor das obras Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (agora, na segunda edição), AI Application Programming (na segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Sua experiência em engenharia vai desde o desenvolvimento de kernels para espaçonaves geossíncronas até a arquitetura de sistemas integrados e o desenvolvimento de protocolos de rede. Tim é engenheiro consultor da Emulex Corp. em Longmont, Colorado.



28/Mai/2014

Entre em contato com Tim

Tim é um dos nossos autores mais populares e produtivos. Navegue por todos os artigos do Tim no developerWorks. Confira o perfil de Tim e entre em contato com ele, outros autores e leitores no My developerWorks.

O uso de log para depuração é tão antigo quanto à própria computação. Os logs são úteis não apenas para compreender a operação interna de um sistema, mas também a sincronização e os relacionamentos das atividades dentro do sistema através das mensagens ordenadas por tempo, dentro do log com registro de data e hora.

Este artigo começa a explorar a criação de log no kernel observando as application programming interfaces (APIs) usadas para configurar e coletar a informação de registro (veja a Figura 1 para obter uma visualização geral da estrutura e dos componentes). Em seguida, o artigo trata do movimento de dados de log a partir do kernel até o espaço do usuário. Finalmente, o artigo irá explorar o destino dos dados de log baseados no kernel: a estrutura de gerenciamento de log no espaço do usuário com o rsyslog.

Figura 1. Ecossistema da criação de log no kernel e componentes principais

API do Kernel

A criação de log dentro do kernel é executada usando a função printk , que é parecida com sua contraparte do espaço do usuário, printf (impressão formatada). O comando printf tem uma longa história em linguagens, mais recentemente na linguagem C , mas há muito tempo atrás, nos anos 50 e 60, na Fortran (instruções PRINT e FORMAT ), BCPL (função writf; a BCPL foi uma precursora da C), e linguagens ALGOL 68 (printf, putf).

No kernel, printk (imprimir kernel) é usada para gravar mensagens formatadas no buffer usando um formato quase idêntico à função printf. É possível localizar o formato da printk no ./linux/include/linux/kernel.h (e sua implementação no ./linux/kernel/printk.c):

int printk( const char * fmt, ... );

Esse formato indica que uma cadeia de caractere é usada para definir o texto e o formato (da mesma forma que printf) e é acompanhada por um conjunto variável de argumentos (identificados por reticências [...]).

Erros e configuração no kernel

A criação de log pelo uso de printk é ativada através da configuração do kernel que usa a opção CONFIG_PRINTK. Mesmo que CONFIG_PRINTK esteja tipicamente ativada, as chamadas de sistema feitas para um kernel que não inclui essa opção retornam um erro ENOSYS.

Uma das primeiras diferenças que pode ser notada no uso de printk é que se trata mais do protocolo e menos da função. Esse recurso usa um aspecto obscuro da linguagem C para simplificar a especificação de prioridade ou de nível de mensagem. O kernel permite que cada mensagem seja classificada com um nível de registro (um dos oito que definem a gravidade da mensagem em particular). Esses níveis comunicam se o sistema se tornou inutilizável (uma mensagem emergencial), se uma condição crítica ocorreu (uma mensagem crítica) ou se a mensagem é simplesmente informativa. O código do kernel simplesmente define o nível de registro como primeiro argumento da mensagem, conforme ilustrado no exemplo a seguir de uma mensagem crítica:

printk( KERN_CRIT "Error code %08x.\n", val );

Observe que o primeiro argumento não é um argumento, já que nenhuma vírgula (,) separa o nível (KERN_CRIT) da sequência de formatações. O KERN_CRIT não é nada mais do que uma cadeia de caractere (de fato, ele representa a cadeia de caractere"<2>"; consulte a Tabela 1 para obter uma lista completa dos níveis de registro). Como parte do pré-processador, C automaticamente combina essas duas cadeias de caractere em um recurso chamado de concatenação de sequência literal. O resultado é uma única cadeia de caractere que incorpora o nível de registro e a sequência de formatações específica do usuário como uma única cadeia de caractere. Observe que se o responsável por uma chamada não fornece um nível de registro dentro do printk, um padrão do KERN_WARNING é automaticamente usado (o que significa que apenas mensagens de log do KERN_WARNING e as de prioridade mais alta serão registradas).

Tabela 1. Níveis de registro, simbólicos e usos

SimbólicoCadeia de caractereUso
KERN_EMERG<0>Mensagens emergenciais (precedem um travamento)
KERN_ALERT<1>Erro que requer atenção imediata
KERN_CRIT<2>Erro crítico (hardware ou software)
KERN_ERR<3>Condições de erro (comum em drivers)
KERN_WARNING<4>Condições de aviso (podem causar erros)
KERN_NOTICE<5>Não se trata de um erro, mas é uma condição significativa
KERN_INFO<6>Mensagem informativa
KERN_DEBUG<7>Usado somente para mensagens de depuração
KERN_DEFAULT<d>Nível de criação de log padrão do kernel
KERN_CONT<c>Continuação de uma linha de log (evite incluir registro de data e hora)

A chamada de printk pode ser feita de qualquer contexto no kernel. A chamada começa no ./linux/kernel/printk.c na função printk, que chama vprintk (no mesmo arquivo de origem) depois de resolver os argumentos de comprimento variável usando va_start.

Funções auxiliares de criação de log

O kernel também fornece algumas funções auxiliares para criação de log que podem simplificar seu uso. Cada nível de registro tem sua própria função, que se expande como um macro para a função printk. Por exemplo, ao usar printk com o nível de registro KERN_EMERG, é possível usar pr_emerg, em seu lugar. Cada macro é listado no ./linux/include/linux/kernel.h.

A função vprintk executa várias verificações de nível de gerenciamento (procurando por recursão) e, então, captura o bloqueio para o buffer do log (__log_buf). Depois, a cadeia de caractere recebida é verificada para ver se há uma cadeia de caractere de nível de registro e, se localizada, o nível de registro é configurado de acordo com ela. Finalmente, o vprintk captura o horário atual (usando a função cpu_clock) e o converte em uma cadeia de caractere usando o sprintf (não a versão de biblioteca padrão, mas uma versão interna do kernel implementada no ./linux/lib/vsprintf.c). A cadeia de caractere passada para printk é, então, copiada no buffer do log do kernel usando uma função especial que gerencia os limites do ring (emit_log_char). No fim dessa função, uma aquisição gratuita e o release do semáforo de console são executados, o que emite a próxima mensagem de log para o console (executada dentro do release_console_sem). O tamanho do ring buffer do kernel era originalmente 4 KB, contudo, em kernels recentes é de 16 KB (e até 1 MB, dependendo da arquitetura).

Até aqui, exploramos a API usada para inserir mensagens de log no ring buffer do kernel. Agora, vamos dar uma olhada no método usado para migrar dados do kernel para o host.


Interface e criação de log no kernel

O acesso ao buffer do log é fornecido no núcleo através de uma chamada de sistema multipropósitos do syslog. Essa chamada única implementa uma variedade de ações que podem todas ser executadas em um espaço do usuário, mas, para usuários não raiz, somente uma ação pode ser executada. O protótipo para a chamada de sistema do syslog é definido no ./linux/include/linux/syslog.h; sua implementação está no ./linux/kernel/printk.c.

syslog(2) vs. syslog(3)

Observe que o syslog definido aqui (syslog(2)) é diferente da API para envio de mensagens para o criador de logs do sistema (syslog(3)). Este último permite que as mensagens sejam enviadas para o syslog (através das funções open, close e write no log usando uma prioridade específica).

A chamada de syslog funciona como entrada/de saída (E/S) e controla a interface no ring buffer de mensagem de log do kernel. A partir da chamada de syslog, um aplicativo pode ler mensagens de log (parcialmente, inteiramente ou somente mensagens novas), assim como controlar o comportamento do ring buffer (limpar conteúdo, configurar o nível das mensagens que serão registradas, ativar ou desativar o console etc.) A figura 2 fornece uma ilustração gráfica da pilha de criação de log com alguns dos principais componentes discutidos.

Figura 2. Pilha de criação de log no kernel que identificam os principais componentes

A chamada de syslog (conhecida como do_syslog, dentro do kernel no ./linux/kernel/printk.c), é uma função relativamente pequena que fornece a capacidade de ler e controlar o ring buffer do kernel. Observe que, no glibc 2.0, essa função é chamada de klogctl devido ao uso excessivo do termo syslog, que se refere a uma variedade de chamadas e aplicativos. A função de protótipo (no espaço do usuário) para syslog e klogctl é definida como:

int syslog( int type, char *bufp, int len );
int klogctl( int type, char *bufp, int len );

O argumento type comunica o comando a ser executado e é associado ao buffer opcional com seu comprimento. Alguns comandos (como o de limpeza do ring buffer) ignoram os argumentos bufp e len. Mesmo que os dois primeiros tipos de comando não executem nenhuma ação no kernel, o resto é usado para ler mensagens de log ou controlar os aspectos da criação de log. Três comandos são usados para ler mensagens de log. O comando SYSLOG_ACTION_READ é usado para bloqueio até que as mensagens de log estejam disponíveis e depois para retorná-las ao buffer fornecido. Esse comando consome as mensagens (as mensagens antigas não irão aparecer nas chamadas subsequentes para ele). O comando SYSLOG_ACTION_READ_ALL lê os últimos caracteres n do log (em que n é definido como o parâmetro 'len' passado para o klogctl). O comando SYSLOG_ACTION_READ_CLEAR executa a ação SYSLOG_ACTION_READ_ALL seguida por um comando SYSLOG_ACTION_CLEAR (limpar o ring buffer). SYSLOG_ACTION_CONSOLE ON e OFF manipulam o nível de registro para ativar ou desativar as mensagens de log no console, em que SYSLOG_CONSOLE_LEVEL permite que o responsável pela chamada defina o nível das mensagens de log que o console deve aceitar. Finalmente, SYSLOG_ACTION_SIZE_BUFFER retorna o tamanho do ring buffer do kernel, e SYSLOG_ACTION_SIZE_UNREAD retorna o número de caracteres atualmente disponíveis para leitura no ring buffer do kernel. A lista completa de comandos do SYSLOG é mostrada na Tabela 2.

Tabela 2. Comandos implementados com a chamada de sistema de syslog/klogctl

Comando/opcodePropósito
SYSLOG_ACTION_CLOSE (0)Fechar o log (não implementado)
SYSLOG_ACTION_OPEN (1)Abrir o log (não implementado)
SYSLOG_ACTION_READ (2)Ler o log
SYSLOG_ACTION_READ_ALL (3)Ler todas as mensagens do log (sem destruí-las)
SYSLOG_ACTION_READ_CLEAR (4)Ler e limpar todas as mensagens do log
SYSLOG_ACTION_CLEAR (5)Limpar o ring buffer
SYSLOG_ACTION_CONSOLE_OFF (6)Desativar printks para o console
SYSLOG_ACTION_CONSOLE_ON (7)Ativar printks para o console
SYSLOG_ACTION_CONSOLE_LEVEL (8)Configurar nível das mensagens que o console aceita
SYSLOG_ACTION_SIZE_UNREAD (9)Retornar o número de caracteres não lidos no log
SYSLOG_ACTION_SIZE_BUFFER (10)Retornar o tamanho do ring buffer do kernel

Implementado acima da camada syslog/klogctl, o sistema de arquivos kmsg proc é um caminho de E/S (implementado no ./linux/fs/proc/kmsg.c) que fornece uma interface binária para leitura de mensagens de log do buffer do kernel. Isso é comumente lido por um daemon (klogd ou rsyslogd) que consome as mensagens e as passa para rsyslog para roteamento no arquivo de log adequado (de acordo com a sua configuração).

O arquivo /proc/kmsg implementa um pequeno número de operações de arquivo que são equivalentes às operações do_syslog internas. Internamente, a chamada de open se relaciona ao SYSLOG_ACTION_OPEN e à chamada de release para SYSLOG_ACTION_CLOSE (cada uma delas é implementada como uma No Operation Performed [NOP]). A operação de pesquisa permite a espera por atividade no arquivo e chama SYSLOG_ACTION_SIZE_UNREAD para identificar o número de caracteres disponíveis para leitura. Finalmente, a operação de read faz o mapeamento para que SYSLOG_ACTION_READ consuma as mensagens de log disponíveis. Observe que o arquivo /proc/kmsg não é útil para os usuários: ele é usado por um único daemon para capturar mensagens de log e roteá-las para o arquivo de log necessário no espaço /var.


Aplicativos de espaço do usuário

O espaço do usuário fornece inúmeros pontos de acesso para leitura e gerenciamento de criação de log no kernel. Vamos começar com interfaces de níveis inferiores (como os elementos de configuração do sistema de arquivos /proc) e expandir para os aplicativos de nível superior.

O sistema de arquivos /proc exporta mais do que apenas a interface binária para acessar as mensagens de log (kmsg). Ele também apresenta vários elementos de configuração, relacionados e independentes dos que foram discutidos, através do syslog/klogctl. A listagem 1 mostra uma exploração desses parâmetros.

Listagem 1. Explorando os parâmetros de configuração printk no /proc
mtj@ubuntu:~$ cat /proc/sys/kernel/printk
4	4	1	7
mtj@ubuntu:~$ cat /proc/sys/kernel/printk_delay
0
mtj@ubuntu:~$ cat /proc/sys/kernel/printk_ratelimit
5
mtj@ubuntu:~$ cat /proc/sys/kernel/printk_ratelimit_burst
10

Na Listagem 1, a primeira entrada define os níveis de registros atualmente usados na API do printk. Esses níveis de registro representam o nível de registro do console, o nível de registro de mensagem padrão, o nível de registro mínimo do console e o nível de registro padrão do console. O valor printk_delay representa o número de milissegundos de atraso entre as mensagens printk (para incluir capacidade de leitura em alguns cenários). Observe que, neste caso, ele está configurado como zero e não pode ser configurado através do /proc. O printk_ratelimit define o intervalo mínimo de tempo permitido entre as mensagens (atualmente, está definido como um número de mensagens do kernel a cada cinco segundos). O número de mensagens é definido por printk_ratelimit_burst (atualmente, está definido como 10). Isso é particularmente útil se você tiver um kernel com muitas mensagens, mas um dispositivo de console com largura de banda limitada (por exemplo, sobre uma porta serial). Observe que, dentro do kernel, o limite de taxa é controlado pelo responsável pela chamada e não é implementado no printk. Um usuário de printk que deseja chamadas com limite de taxa deve chamar a função printk_ratelimit.

O comando dmesg pode também ser usado para imprimir e controlar o ring buffer do kernel. Esse comando usa a chamada do sistema de klogctl para ler o ring buffer do kernel e emiti-lo para a saída padrão (stdout). O comando também pode ser usado para limpar o ring buffer do kernel (usando a opção -c), configurar a criação de log no console (a opção-n) e definir o tamanho do buffer usado para ler as mensagens de log do kernel (opção -s). Observe que, se o tamanho do buffer não for especificado, dmesg identifica o tamanho adequado de buffer usando a operação SYSLOG_ACTION_SIZE_BUFFER no klogctl.

Finalmente, a mãe de todos os aplicativos de criação de log é o syslog, uma estrutura de criação de log padronizada que é implementada nos sistemas operacionais principais (incluindo Linux® e Berkeley Software Distribution [BSD]). syslog tem seu próprio protocolo usado para conduzir as mensagens de notificação de evento em uma variedade de protocolos de transporte (dividindo componentes em originadores, retransmissões e coletores). Em muitos casos, todos os três são implementados em um único host. Além dos vários recursos interessantes do syslog, ele especifica como as informações de criação de log são coletadas e filtradas, assim como onde armazená-las. syslog passou por inúmeras mudanças e se desenvolveu. Você provavelmente já ouviu falar do syslog, klog ou sysklogd. Nas distribuições mais recentes do Ubuntu, uma nova versão do syslog chamada de rsyslog é usada (baseada no syslog original), que se refere ao confiável e estendido syslogd.

O daemon do rsyslogd, através de seu arquivo de configuração no /etc/rsyslog.conf), entende a interface kmsg do arquivo de sistemas /proc e a usa para extrair as mensagens de criação de log do kernel. Observe que, internamente, todos os níveis de registro são gravados através do /proc/kmsg para que, em vez de o kernel definir quais níveis de registro transportar, a tarefa seja deixada para o rsyslog mesmo. As mensagens de log do kernel são, então, armazenadas no /var/log/kern.log (entre outros arquivos configurados). No /var/log, é encontrado um excesso de arquivos de log que incluem mensagens gerais e chamadas relacionadas ao sistema (/var/log/messages), log de inicialização do sistema (/var/log/boot.log), logs de autenticação (/var/log/auth.log) e outros.

Mesmo que os logs estejam disponíveis para revisão, é possível também usá-los para auditorias automatizadas e revisões mais detalhadas. Existe uma variedade de analisadores de arquivo de log para resolução de problemas ou conformidade com regulamentos de segurança e para procurar automaticamente por problemas usando técnicas como reconhecimento de padrão ou análise de correlação (mesmo em vários sistemas).


Indo além

Este artigo fornece uma reflexão rápida sobre a criação de log no kernel e aplicativos—desde a criação de mensagens de log no kernel passando pelo seu armazenamento dentro do ring buffer do kernel pelo seu transporte para o espaço do usuário através do syslog/klogctl ou /proc/kmsg, pelo seu roteamento através da estrutura de criação de log do rsyslog até seu local final de pouso na subárvore do /var/log. O Linux fornece uma estrutura completa e flexível para criação de log (tanto no kernel quanto externamente).

Recursos

Aprender

Obter produtos e tecnologias

  • Avalie os produtos da IBM da melhor maneira para você: faça um download de uma versão de avaliação, experimente um produto on-line, use um produto em um ambiente de nuvem ou passe algum tempo no ambiente de simulação da SOA aprendendo como implementar a Arquitetura Orientada a Serviços de maneira eficiente.

Discutir

  • Participe da comunidade do My developerWorks. Entre em contato com outros usuários do developerWorks, ao mesmo tempo em que explora blogs, fóruns, grupos e wikis direcionados aos desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux
ArticleID=556588
ArticleTitle=Criação de log no kernel: APIs e implementação
publish-date=05282014