systemd.service: use pty então force flush de stdout?

1

Eu tenho um serviço que desejo executar no systemd. Ele é escrito em perl, onde por padrão a saída é armazenada em buffer se o STDOUT estiver conectado a um terminal. (Que parece semelhante ao python )

A conseqüência é que a saída chega a journalctl -f -u my.service em pedaços de muitas linhas de cada vez - quando o buffer está cheio.

Eu sei que posso modificar a fonte de serviço para liberar automaticamente STDOUT ( $|=1 em perl).

Eu sei que também posso usar unbuffer como esperado :

-ExecStart=/my/program.pl
+ExecStart=/usr/bin/unbuffer /my/program.pl

mas depois tenho outro processo envolvido e essa "solução" tem um cheiro ruim para mim. (Por exemplo, o "PID principal" é o de unbuffer , não de /my/program.pl ). E o ponto principal do systemd é evitar soluções estranhas de shell como essa.

Existe alguma maneira de executar esses serviços inalterados de uma forma que os faça pensar que estão conectados a um terminal, de modo que liberem seus STDOUT ? Eu olhei para StandardOutput= mas não achei nada útil.

    
por Peter V. Mørch 21.05.2018 / 12:14

1 resposta

2

Não é verdade, não. O buffer é configurado por processo por meio de uma chamada setbuf(3) , na qual as linguagens de script oferecem vários graus de controle (TCL: completo, Perl | Python | Ruby: incompleto, Shell: de maneira nenhuma). Você precisaria usar um wrapper que falsifica um terminal (unbuffer, expect, tmux) ou tentar patch de macaco de chamada de sistema não suportável ( stdbuf ) para tentar influenciar como a saída é feita ou para adicionar código a cada aplicativo a saída pode ser configurada para ser unbuffered, line buffered ou block buffered (ou qualquer subconjunto daqueles que a linguagem oferece, se houver). Alguns aplicativos já terão sinalizadores para isso, por exemplo -l de tcpdump , ou não é difícil adicionar esse código:

#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);

GetOptions( 'l' => \my $Flag_Unbuffer ) or exit 64;

STDOUT->autoflush(1) if $Flag_Unbuffer;

print "hi\n" for 1..4;
sleep 10;

se isso for salvo como lflag e tornado executável, a diferença de comportamento poderá ser observada executando:

$ ./lflag | cat

ou

$ ./lflag -l | cat
    
por 21.05.2018 / 16:23