Cómo redirigir la salida del servicio systemd a un archivo


171

Estoy tratando de redirigir la salida de un systemdservicio a un archivo, pero parece que no funciona:

[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

Por favor corrige mi enfoque.

Respuestas:


233

Creo que hay una manera más elegante de resolver el problema: envíe stdout / stderr a syslog con un identificador e indique a su administrador de syslog que divida su salida por nombre de programa.

Use las siguientes propiedades en su archivo de unidad de servicio systemd:

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

Luego, suponiendo que su distribución esté utilizando rsyslog para administrar syslogs, cree un archivo /etc/rsyslog.d/<new_file>.confcon el siguiente contenido:

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

Ahora haga que el archivo de registro sea editable 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 rsyslog ( sudo systemctl restart rsyslog) y disfrute! Su programa stdout / stderr todavía estará disponible a través de journalctl ( sudo journalctl -u <your program identifier>) pero también estará disponible en su archivo de elección.

Fuente vía archive.org


8
No funciona para mí en Ubuntu 16.04. journalctl -uaún funciona pero no se envía nada al archivo especificado.
Duncan Calvert

1
Esto funciona muy bien en el estiramiento de Debian, sin embargo, se queja de que ~está en desuso y stopdebería usarse en su lugar. También tenga en cuenta que la segunda línea puede acortarse & stopsi las dos se suceden.
jlh

47
Con systemd 236 o posterior, también puede escribir directamente en un archivo usando StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu

55
Empecé a trabajar cambiando los /etc/rsyslog.d/<newfile>.confcontenidos a: :programname, isequal, "<your program identifier>" /var/log/somelog.log Aquí hay documentación sobre los filtros de rsyslog : rsyslog.com/doc/v8-stable/configuration/filters.html Y aquí hay documentos sobre las propiedades como programname: rsyslog.com/doc/master/configuration/properties .html
mbil

1
Tuve problemas al usar esta configuración hasta que descubrí que rsyslogtiene su propio usuario syslogy tiene que tener acceso de escritura a la ubicación de los registros. Así que utilícelo en chownconsecuencia Espero que esto ayude a alguien.
Imaskar

73

Si tiene una distribución más nueva con una más nueva systemd( systemdversión 236 o más reciente ), puede establecer los valores de StandardOutputo StandardErrorpara file:YOUR_ABSPATH_FILENAME.


Larga historia:

En las versiones más recientes de systemdhay una opción relativamente nueva ( la solicitud de github es de 2016 ish y la mejora se fusionó / ​​cerró 2017 ish ) donde puede establecer los valores de StandardOutputo StandardErrorpara file:YOUR_ABSPATH_FILENAME. La file:pathopción está documentada en la página de manual más recientesystemd.exec .

Esta nueva característica es relativamente nueva y, por lo tanto, no está disponible para distribuciones anteriores como centos-7 (o cualquier centos anterior).


10
No funciona en ubuntu 1604 en 2018-03-20. La versión systemd en ubuntu 1604 es solo 229.
hombre de bronce

Gracias, dijiste muy claro. Simplemente no puedo creer que el systemd en ubuntu 1604 no pueda redirigir la salida a un archivo solo por config. Tengo que usar la forma sh para resolver este problema.
hombre de bronce

@bronzeman, la solicitud de función no se cerró hasta 2017, mientras que Ubuntu 16.04 salió en 2016. En una versión principal dada de Ubuntu (por ejemplo, 16.04, 16.10, 17.04, etc.), Ubuntu mantiene la compatibilidad ABI en sus paquetes principales del sistema. Por lo tanto, no actualizarán systemd (o el kernel de Linux, o glibc, ni nada) a menos que mantenga el mismo ABI que cuando se lanzó por primera vez la versión de Ubuntu.
villapx

1
FWIW: He buscado un poco, pero esta característica no parece tener disposiciones para la rotación de registros, como la función para volver a abrir el archivo de registro, y uno tiene que usar los gustos de copytruncatein logrotate.
antak

49

Posiblemente reciba este error:

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

Desde la systemd.exec(5)página del manual:

StandardOutput=

Controla dónde está conectado el descriptor de archivo 1 (STDOUT) de los procesos ejecutados. Toma uno de inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consoleo socket.

La systemd.exec(5)página del manual explica otras opciones relacionadas con el registro. Consulte también las páginas systemd.service(5)y systemd.unit(5)man.

O tal vez puedes probar cosas como esta (todo en una línea):

ExecStart=/bin/sh -c '/usr/local/bin/binary1 agent -config-dir /etc/sample.d/server 2>&1 > /var/log.log' 

77
Entre las opciones, se recomienda iniciar sesión en el diario systemd. Puede ver solo los registros de su proceso en el diario mediante journalctl -u your-unit-name.
Mark Stosberg

66
Para especificar un archivo, hay otra opción más limpia, como lo indica la documentación: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

55
Impresionante respuesta, ha resuelto mi problema. Sólo quiero extender, porque en la actualidad si el servicio reiniciar sobrescribir los registros antiguos, que tenga que sustituir esta parte: 2>&1 > /var/log.loga esto: 2>&1 >> /var/log.log. Gracias
PumpkinSeed

10
Francamente, llamar a Shell con una cadena de comando en ExecStart suena como la manera realmente incorrecta de hacerlo.
David Tonhofer

1
"/ bin / sh" es una gran solución, pero DEBE usar "exec", de lo contrario, el servicio no se reiniciará correctamente ya que SIGTERM no se transferirá al proceso secundario. Ver veithen.io/2014/11/16/sigterm-propagation.html
Rico

33

Sugeriría agregar stdouty stderrarchivar en el servicearchivo systemd mismo.

En referencia: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#StandardOutput=

Como lo ha configurado, no debería gustarle:

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

Debería ser:

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

Esto funciona cuando no desea reiniciar el servicio una y otra vez .

Esto creará un nuevo archivo y no se agregará al archivo existente.

Use en su lugar:

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

NOTA: asegúrese de crear el directorio ya. Supongo que no es compatible para crear un directorio.


55
Duplicado de esta respuesta , con menos detalles
Gert van den Berg

9
Creo que lo hice más directo y fácil de entender.
Rajat jain

1
Para mí, la file:ruta funciona en la primera carga del servicio, pero en los reinicios posteriores ya no escribe en el archivo. Lo intenté append:con los documentos y eso no funcionó en absoluto.
rb-

3
Tenga en cuenta que los documentos dejan en claro que file:escribe al inicio del archivo cada vez, y no se trunca ... además, append:parece ser una nueva adición (es decir, no está presente en la man systemd.execpágina en Ubuntu 18.04).
cole

19

Si por alguna razón no puede usar rsyslog, esto hará: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"


¿Qué hace la opción -e de bash?
Lámpara

3

Suponga que los registros ya están en stdout / stderr , y tienen el inicio de sesión de la unidad 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 (Servicio de registro del 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

Reiniciar rsyslog

systemctl restart rsyslog.service

1

Estamos utilizando Centos7, aplicación de arranque de primavera con systemd. Estaba ejecutando Java como a continuación. y configurar StandardOutput en el archivo no funcionaba para mí.

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

A continuación, la solución alternativa funciona sin configurar StandardOutput. ejecutando Java a través de sh como a continuación.


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

ingrese la descripción de la imagen aquí


-1 para definir parámetros jvm en orden incorrecto. -Xmx512M debe definirse antes de -jar. También se espera lo que experimentes. Systemd no invoca servicios utilizando shell
Sami Korhonen

1
@SamiKorhonen, agregué mis comentarios después de probar que esto funciona. Incluso yo estaba pensando en el pedido de -Xmx512M es similar a usted. Por favor, pruebe antes de agregar comentarios ciegos.
Santhosh Hirekerur

0

Respuesta corta:

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

Si no desea que los archivos se borren cada vez que se ejecuta el servicio, use append en su lugar:

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

2
Duplicado de esta respuesta , con menos detalles
rustyx
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.