Como redirecionar a saída do serviço systemd para um arquivo

171

Estou tentando redirecionar a saída de um systemdserviço para um arquivo, mas ele não parece funcionar:

[Unit]
Description=customprocess
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server
StandardOutput=/var/log1.log
StandardError=/var/log2.log
Restart=always

[Install]
WantedBy=multi-user.target

Corrija minha abordagem.

refeição
fonte

Respostas:

233

Eu acho que existe uma maneira mais elegante de resolver o problema: envie o stdout / stderr para o syslog com um identificador e instrua seu gerenciador de syslog a dividir sua saída pelo nome do programa.

Use as seguintes propriedades no arquivo da unidade de serviço systemd:

StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<your program identifier> # without any quote

Supondo que sua distribuição esteja usando o rsyslog para gerenciar os syslogs, crie um arquivo /etc/rsyslog.d/<new_file>.confcom o seguinte conteúdo:

if $programname == '<your program identifier>' then /path/to/log/file.log
& stop

Agora torne o arquivo de log gravável por syslog:

# ls -alth /var/log/syslog 
-rw-r----- 1 syslog adm 439K Mar  5 19:35 /var/log/syslog
# chown syslog:adm /path/to/log/file.log

Reinicie o rsyslog ( sudo systemctl restart rsyslog) e divirta-se! Seu programa stdout / stderr ainda estará disponível no journalctl ( sudo journalctl -u <your program identifier>), mas eles também estarão disponíveis no seu arquivo de escolha.

Fonte via archive.org

Valerio Versace
fonte
8
Não está funcionando para mim no Ubuntu 16.04. journalctl -uainda funciona, mas nada é enviado para o arquivo especificado.
Duncan Calvert
1
Isso funciona muito bem no trecho Debian, no entanto, reclama que ~está obsoleto e stopdeve ser usado em seu lugar. Observe também que a segunda linha pode ser reduzida para & stopse as duas vierem uma após a outra.
jlh
47
Com o systemd 236 ou mais recente, você também pode gravar diretamente em um arquivo usando StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu
5
Eu consegui isso alterando o /etc/rsyslog.d/<newfile>.confconteúdo para: :programname, isequal, "<your program identifier>" /var/log/somelog.log Aqui está a documentação sobre os filtros rsyslog: rsyslog.com/doc/v8-stable/configuration/filters.html E aqui estão os documentos sobre as propriedades como programname: rsyslog.com/doc/master/configuration/properties .html
mbil 17/07/2018
1
Eu tive problemas ao usar essa configuração até descobrir que rsyslogpossui seu próprio usuário sysloge que ele precisa ter acesso de gravação ao local dos logs. Então use em chownconformidade. Espero que isso ajude alguém.
Imaskar
73

Se você tiver uma distribuição mais nova com uma mais nova systemd( systemdversão 236 ou mais recente ), poderá definir os valores de StandardOutputou StandardErrorpara file:YOUR_ABSPATH_FILENAME.


Longa história:

Nas versões mais recentes de, systemdexiste uma opção relativamente nova ( a solicitação do github é de 2016 ish e o aprimoramento é mesclado / fechado 2017 ish ) onde você pode definir os valores de StandardOutputou StandardErrorpara file:YOUR_ABSPATH_FILENAME. A file:pathopção está documentada na página do manual mais recentesystemd.exec .

Esse novo recurso é relativamente novo e, portanto, não está disponível para distros mais antigos, como o centos-7 (ou qualquer outro cento anterior).

Trevor Boyd Smith
fonte
10
Não está funcionando no ubuntu 1604 em 20/03/2018. A versão systemd no ubuntu 1604 é de apenas 229.
homem de bronze
Obrigado, você disse muito claro. Eu simplesmente não consigo acreditar que o systemd no ubuntu 1604 não pode redirecionar a saída para um arquivo apenas por config.Eu tenho que usar a maneira sh para resolver esse problema.
bronze man
@bronzeman a solicitação do recurso não foi fechada até 2017, enquanto o Ubuntu 16.04 foi lançado em 2016. Em uma versão importante do Ubuntu (por exemplo, 16.04, 16.10, 17.04, etc.), o Ubuntu mantém a compatibilidade com ABI em seus principais pacotes de sistema. Portanto, eles não atualizarão o systemd (ou o kernel do Linux, ou glibc, ou qualquer outra coisa), a menos que mantenha a mesma ABI de quando a versão do Ubuntu foi lançada.
22618 villapx
1
FWIW: Eu procurei um pouco, mas esse recurso não parece ter provisões para rotação de log, como a função para reabrir o arquivo de log, com um ter que usar o que gosta de copytruncatenos logrotate.
antak
48

Você pode receber este erro:

Failed to parse output specifier, ignoring: /var/log1.log

Na systemd.exec(5)página do manual:

StandardOutput=

Controla onde o descritor de arquivo 1 (STDOUT) dos processos executados está conectado. Toma um dos inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consoleou socket.

A systemd.exec(5)página do manual explica outras opções relacionadas ao log. Veja também as páginas de manual systemd.service(5)e systemd.unit(5).

Ou talvez você possa tentar coisas como esta (todas em uma linha):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 
Shuangistan
fonte
7
Entre as opções, é recomendável fazer login no diário systemd. Você visualiza apenas os logs do seu processo no diário usando journalctl -u your-unit-name.
precisa saber é o seguinte
6
Para especificar um arquivo, há outra opção de limpeza, conforme indicado na documentação:The fd option connects the output stream to a single file descriptor provided by a socket unit. A custom named file descriptor can be specified as part of this option, after a ":" (e.g. "fd:foobar").
orion
5
Resposta impressionante, resolveu o meu problema. Eu só quero estender, porque atualmente se o serviço reiniciar substituir os antigos registros, tem que substituir esta parte: 2>&1 > /var/log.loga isto: 2>&1 >> /var/log.log. Obrigado
pumpkinseed
10
Francamente, chamar shell com uma sequência de comandos no ExecStart soa como o Really Wrong Way.
David Tonhofer
1
"/ bin / sh" é uma ótima solução, mas você DEVE usar "exec"; caso contrário, o serviço não será reiniciado corretamente, pois o SIGTERM não será passado para o processo filho. Veja veithen.io/2014/11/16/sigterm-propagation.html
Rich
33

Eu sugeriria adicionar stdoute stderrarquivar no servicepróprio arquivo systemd .

Referência: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Como você configurou, não deve gostar:

StandardOutput=/home/user/log1.log
StandardError=/home/user/log2.log

Deveria ser:

StandardOutput=file:/home/user/log1.log
StandardError=file:/home/user/log2.log

Isso funciona quando você não deseja reiniciar o serviço repetidamente .

Isso criará um novo arquivo e não será anexado ao arquivo existente.

Use em vez disso:

StandardOutput=append:/home/user/log1.log
StandardError=append:/home/user/log2.log

NOTA: Certifique-se de criar o diretório já. Eu acho que não suporta criar um diretório.

Rajat jain
fonte
5
Duplicar de esta resposta , com menos detalhes
van den Berg Gert
9
Eu acho que tornei mais direto \ fácil de entender.
Rajat jain
1
Para mim, a file:rota funciona na primeira carga do serviço, mas nas reinicializações subsequentes, ela não grava mais no arquivo. Eu tentei append:com os documentos e isso não funcionou.
Rb-
3
Observe que os documentos deixam claro que file:grava no início do arquivo todas as vezes e não trunca ... além disso, append:parece ser uma nova adição (ou seja, não está presente na man systemd.execpágina do Ubuntu 18.04).
cole
19

Se, por algum motivo, não puder usar o rsyslog, isso será feito: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"

Tigra
fonte
O que a opção -e do bash faz?
Lamp
3

Suponha que os logs já estejam colocados no stdout / stderr e tenham o log da unidade systemd/var/log/syslog

journalctl -u unitxxx.service

Jun 30 13:51:46 host unitxxx[1437]: time="2018-06-30T11:51:46Z" level=info msg="127.0.0.1
Jun 30 15:02:15 host unitxxx[1437]: time="2018-06-30T13:02:15Z" level=info msg="127.0.0.1
Jun 30 15:33:02 host unitxxx[1437]: time="2018-06-30T13:33:02Z" level=info msg="127.0.0.1
Jun 30 15:56:31 host unitxxx[1437]: time="2018-06-30T13:56:31Z" level=info msg="127.0.0.1

Config rsyslog (Serviço de Log do Sistema)

# Create directory for log file
mkdir /var/log/unitxxx

# Then add config file /etc/rsyslog.d/unitxxx.conf

if $programname == 'unitxxx' then /var/log/unitxxx/unitxxx.log
& stop

Reinicie o rsyslog

systemctl restart rsyslog.service
Hieu Huynh
fonte
1

Estamos usando o Centos7, aplicativo de inicialização com systemd. Eu estava executando o java como abaixo. e definir StandardOutput para arquivo não estava funcionando para mim.

ExecStart=/bin/java -jar xxx.jar  -Xmx512-Xms32M

Solução abaixo da solução alternativa funcionando sem definir o StandardOutput. executando java através de sh como abaixo.


ExecStart=/bin/sh -c 'exec /bin/java -jar xxx.jar -Xmx512M -Xms32M >> /data/logs/xxx.log 2>&1'

insira a descrição da imagem aqui

Santhosh Hirekerur
fonte
-1 para definir os parâmetros da jvm na ordem errada. -Xmx512M deve ser definido antes de -jar. Também o que você experimenta é esperado. Systemd não invoca serviços usando shell
Sami Korhonen
1
@SamiKorhonen, adicionei meus comentários depois de testar se está funcionando. Até eu estava pensando em que a ordem de -Xmx512M é um prazer para você. Teste antes de adicionar comentários cegos.
Santhosh Hirekerur
0

Resposta curta:

StandardOutput=file:/var/log1.log
StandardError=file:/var/log2.log

Se você não deseja que os arquivos sejam limpos toda vez que o serviço for executado, use o anexo:

StandardOutput=append:/var/log1.log
StandardError=append:/var/log2.log
Arnett Rufino
fonte
2
Duplicado desta resposta , com menos detalhes
rustyx 25/01