Existe uma maneira de fazer o journalctl mostrar logs da "última vez em que foo.service foi executado"?


15

Estou particularmente interessado nisso por examinar a saída dos serviços oneshot executados em um timer. A --unitsinalização está próxima, mas concatena todas as execuções do serviço juntas. A maneira mais óbvia em que posso pensar seria filtrar o PID, mas isso me preocupa com a reutilização / serviços do PID que bifurcam, e obter o último PID é bastante inconveniente. Existe algum outro identificador que corresponda a uma única execução de um serviço, que eu poderia usar para filtrar os logs?

Edição: Eu aceitaria felizmente um "não" autoritário se essa for a resposta real.

Respostas:


6

Desde a systemdversão 232, temos o conceito de identificação de chamada. Cada vez que uma unidade é executada, ela possui um ID de chamada de 128 bits exclusivo. Diferente de MainPIDqual pode ser reciclado ou ActiveEnterTimestampque pode ter problemas de resolução, é uma maneira segura de obter todo o log de uma chamada de unidade do systemd específica.

Para obter o ID de chamada mais recente de uma unidade

$ systemctl show --value -p InvocationID openipmi
bd3eb84c3aa74169a3dcad2af183885b

Para obter o diário da última chamada de, digamos openipmi, se falhou ou não, você pode usar o liner único

$ journalctl _SYSTEMD_INVOCATION_ID=`systemctl show -p InvocationID --value openipmi.service`
-- Logs begin at Thu 2018-07-26 12:09:57 IDT, end at Mon 2019-07-08 01:32:50 IDT. --
Jun 21 13:03:13 build03.lbits openipmi[1552]:  * Starting ipmi drivers
Jun 21 13:03:13 build03.lbits openipmi[1552]:    ...fail!
Jun 21 13:03:13 build03.lbits openipmi[1552]:    ...done.

(Observe que o --valueitem está disponível desde que systemd 230, mais antigo que InvocationID)


Se alguém está tentando investigar isso: journalctl --user -u UNITFILE -f -o json-prettypode ser útil; você está procurando MESSAGEcampos em particular. Descobri que você também pode precisar USER_INVOCATION_ID, e também algumas mensagens não têm nenhum ID de chamada anexado a elas, portanto, não podem ser filtradas por esse mecanismo. Não sei por que, talvez meu registro esteja mal configurado ..
karlicoss 24/01

14

Não tenho certeza de qual carimbo de data / hora faz mais sentido, mas isso funciona para mim. Espero que exista uma maneira melhor de trabalhar com os registros de data e hora do systemctl showque o awk - não consegui descobrir como controlar o formato dos registros de data e hora.

unit=foo.service

ts=$(systemctl show -p ActiveEnterTimestamp $unit)

echo $ts
ActiveEnterTimestamp=Fri 2016-11-11 12:30:01 MST

journalctl -u $unit --since "$(echo $ts | awk '{print $2 $3}')"

Apenas no caso de alguém precisar disso como uma linha: journalctl --since " systemctl show -p ActiveEnterTimestamp thermo.service | awk '{print $2 \" \" $3}'" -fu thermo.service | menos
DimanNe 4/11

Você também pode usar systemctl show -p ActiveEnterTimestamp --value $unit, para que não seja necessário extra awk
karlicoss

4

Você pode usar o sinalizador de inicialização para buscar apenas os logs dessa inicialização. por exemplo

journalctl _SYSTEMD_UNIT=avahi-daemon.service -b 5

2
Isso é semelhante ao que eu quero, mas não funciona em situações como: 1) se a máquina foi reinicializada desde a última vez em que o serviço foi executado, ou 2) se o serviço foi executado várias vezes desde a última inicialização.
Jack O'Connor

Não sei por que não funciona no 1º caso. Se tiver sido reiniciado, também será reiniciado. Você só precisa ir a essa inicialização específica e buscar suas informações. Quanto ao segundo ... você está certo. Os logs de ruído dependem do número de vezes que o serviço foi reiniciado. Mas uma vez que você localizou seu serviço, pode filtrá-lo usando o argumento _PID = XXX. As chances de reutilizar o mesmo pid para o mesmo serviço no mesmo ciclo de inicialização são ..... nenhuma idéia ... mas quase impossível.
Nikolaidis Fotis

Estou interessado em lidar com serviços que não necessariamente executam na inicialização, porque eles estão em timers ou porque são comandos únicos.
Jack O'Connor

3

Isso pode ajudá-lo a:

  • journalctl -u foo.service | cauda -n 2

    ou substitua 2 pelo número esperado de linhas

  • journalctl -u foo.service --since = ' 2016-04-11 13:00:00 '

Você também pode combiná-los para obter primeiro o último registro de data e hora do tempo de execução e depois usá-lo com a opção --since.


Parece uma solução alternativa semelhante à abordagem PID, mas é muito manual. Se meu serviço for executado por muitos segundos e cuspir muitas linhas de log, tenho que procurar a primeira linha com o carimbo de data e hora de início que me interessa. Isso não funcionará muito bem em um script.
Jack O'Connor

3

Você pode usar filtros de campo com o Journalctl. Por exemplo

journalctl _PID=1234

Obtenha uma lista de todos os campos disponíveis usando:

journalctl --fields --unit kubelet

Um campo disponível é _PID.

Você pode obter o PID de um processo em execução usando pidofousystemctl show --property MainPID <SERVICE_NAME>

Então, aqui está como eu obtenho os logs do processo atual do Kubernetes kubelet:

# journalctl --unit kubelet _PID=$(systemctl show --property MainPID kubelet 2>/dev/null | cut -d= -f2) | head

Agora me diga por que eu é tão difícil instalar o Kubernetes :-(


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.