Cách chuyển hướng đầu ra của dịch vụ systemd sang tệp


171

Tôi đang cố gắng chuyển hướng đầu ra của một systemddịch vụ sang một tệp nhưng nó dường như không hoạt động:

[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

Hãy sửa chữa cách tiếp cận của tôi.

Câu trả lời:


233

Tôi nghĩ có một cách thanh lịch hơn để giải quyết vấn đề: gửi stdout / stderr tới syslog bằng mã định danh và hướng dẫn người quản lý nhật ký hệ thống của bạn chia đầu ra của nó theo tên chương trình.

Sử dụng các thuộc tính sau trong tệp đơn vị dịch vụ systemd của bạn:

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

Sau đó, giả sử bản phân phối của bạn đang sử dụng rsyslog để quản lý nhật ký hệ thống, hãy tạo một tệp /etc/rsyslog.d/<new_file>.confcó nội dung sau:

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

Bây giờ làm cho tệp nhật ký có thể ghi bằng 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

Khởi động lại rsyslog ( sudo systemctl restart rsyslog) và tận hưởng! Stdout / stderr chương trình của bạn vẫn sẽ có sẵn thông qua Tạp chí ( sudo journalctl -u <your program identifier>) nhưng chúng cũng sẽ có sẵn trong tệp bạn chọn.

Nguồn qua archive.org


8
Không hoạt động với tôi trên Ubuntu 16.04. journalctl -uvẫn hoạt động nhưng không có gì được gửi đến tập tin được chỉ định.
Duncan Calvert

1
Điều này hoạt động rất tốt trên Debian, tuy nhiên nó phàn nàn rằng ~không được dùng nữa và stopnên được sử dụng thay thế. Cũng lưu ý rằng dòng thứ hai có thể được rút ngắn & stopnếu hai người đến sau nhau.
jlh

47
Với systemd 236 hoặc mới hơn, bạn cũng có thể ghi trực tiếp vào tệp bằng StandardOutput = file: / some / path github.com/systemd/systemd/pull/7198
leezu 18/12/17

5
Tôi đã làm việc này bằng cách thay đổi /etc/rsyslog.d/<newfile>.confnội dung thành: :programname, isequal, "<your program identifier>" /var/log/somelog.log Tài liệu này trên các bộ lọc rsyslog: rsyslog.com/doc/v8-urdy/configuration/filters.html Và đây là tài liệu về các thuộc tính như programname: rsyslog.com/doc/master/configuration/propericat .html
mbil

1
Tôi gặp vấn đề khi sử dụng cấu hình này cho đến khi tôi thấy rsyslogcó người dùng riêng syslogvà nó phải có quyền ghi vào vị trí nhật ký. Vì vậy, sử dụng cho chownphù hợp. Hy vọng điều này sẽ giúp ai đó.
Imaskar

73

Nếu bạn có bản phân phối mới hơn với bản mới hơn systemd( systemdphiên bản 236 hoặc mới hơn ), bạn có thể đặt giá trị của StandardOutputhoặc StandardErrorthành file:YOUR_ABSPATH_FILENAME.


Câu chuyện dài:

Trong các phiên bản mới hơn systemdcó một tùy chọn tương đối mới ( yêu cầu github là từ năm 2016 ish và sự tăng cường được hợp nhất / đóng 2017 ish ) nơi bạn có thể đặt các giá trị của StandardOutputhoặc StandardErrorthành file:YOUR_ABSPATH_FILENAME. Các file:pathtùy chọn được ghi lại trong trang người đàn ông gần đây nhấtsystemd.exec .

Tính năng mới này tương đối mới và do đó không có sẵn cho các bản phân phối cũ hơn như centos-7 (hoặc bất kỳ centos nào trước đó).


10
Không hoạt động trong Ubuntu 1604 trong 2018-03-20. Phiên bản systemd trong ubfox 1604 chỉ 229.
người đàn ông bằng đồng vào

Cảm ơn, bạn nói rất rõ ràng. Tôi không thể tin rằng systemd trong ubfox 1604 không thể chuyển hướng đầu ra sang một tệp chỉ bằng config. Tôi phải sử dụng cách sh để giải quyết vấn đề này.
người đàn ông bằng đồng

@bronzeman yêu cầu tính năng đã không bị đóng cho đến năm 2017, trong khi Ubuntu 16.04 ra mắt vào năm 2016. Trong một bản phát hành chính của Ubuntu (ví dụ 16.04, 16.10, 17.04, v.v.), Ubuntu duy trì khả năng tương thích ABI trong các gói hệ thống cốt lõi của nó. Vì vậy, họ sẽ không nâng cấp systemd (hoặc nhân Linux, hoặc glibc hoặc bất cứ thứ gì) trừ khi nó duy trì cùng ABI như khi phiên bản Ubuntu được phát hành lần đầu tiên.
Villapx

1
FWIW: Tôi đã tìm kiếm một chút nhưng tính năng này không xuất hiện để có quy định cho xoay log, chẳng hạn như chức năng để mở lại các file log, với một cần phải sử dụng những cầu thủ như copytruncatetrong logrotate.
antak

48

Bạn có thể gặp lỗi này:

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

Từ systemd.exec(5)trang người đàn ông:

StandardOutput=

Kiểm soát nơi mô tả tệp 1 (STDOUT) của các quy trình được thực hiện được kết nối với. Mất một trong những inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+consolehoặc socket.

Các systemd.exec(5)trang người đàn ông giải thích tùy chọn khác liên quan đến khai thác gỗ. Xem thêm trang systemd.service(5)systemd.unit(5)người đàn ông.

Hoặc có thể bạn có thể thử những thứ như thế này (tất cả trên một dòng):

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

7
Trong số các tùy chọn, đăng nhập vào tạp chí systemd được khuyến khích. Bạn chỉ xem nhật ký cho quá trình của bạn trong tạp chí bằng cách sử dụng journalctl -u your-unit-name.
Mark Stosberg

6
Để chỉ định một tệp, có một tùy chọn sạch hơn, như được chỉ ra trong tài liệu: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
Câu trả lời tuyệt vời, nó đã giải quyết vấn đề của tôi. Tôi chỉ muốn gia hạn, vì hiện tại nếu dịch vụ khởi động lại ghi đè lên nhật ký cũ, phải thay thế phần này: 2>&1 > /var/log.logthành này : 2>&1 >> /var/log.log. Cảm ơn bạn
PumpkinSeed

10
Thành thật mà nói, việc gọi shell bằng chuỗi lệnh trong ExecStart nghe có vẻ giống như cách thực sự sai để làm điều đó.
David Tonhofer

1
"/ Bin / sh" là một cách giải quyết tuyệt vời, nhưng bạn PHẢI sử dụng "exec", nếu không dịch vụ sẽ không khởi động lại đúng cách vì SIGTERM sẽ không được chuyển sang quy trình con. Xem veithen.io/2014/11/16/sigterm-propagation.html
Giàu

33

Tôi sẽ đề nghị thêm stdoutstderrtập tin trong servicetập tin systemd .

Giới thiệu: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#St ChuẩnOutput =

Như bạn đã cấu hình, nó không giống như:

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

Nó nên là:

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

Điều này hoạt động khi bạn không muốn khởi động lại dịch vụ nhiều lần .

Điều này sẽ tạo ra một tệp mới và không nối vào tệp hiện có.

Sử dụng thay thế:

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

LƯU Ý: Hãy chắc chắn rằng bạn đã tạo thư mục. Tôi đoán nó không hỗ trợ để tạo một thư mục.


5
Bản sao của câu trả lời này , với ít chi tiết hơn
Gert van den Berg

9
Tôi nghĩ rằng, tôi đã làm cho nó trực tiếp hơn \ dễ hiểu.
Rajat

1
Đối với tôi file:tuyến đường hoạt động trong lần tải đầu tiên của dịch vụ, nhưng vào lần khởi động lại sau đó, nó không còn ghi vào tệp. Tôi đã thử append:từ các tài liệu và điều đó không làm việc cả.
rb-

3
Lưu ý rằng các tài liệu làm rõ rằng file:ghi vào đầu tệp mỗi lần và không cắt bớt ... hơn nữa, append:dường như là một bổ sung mới (tức là không có trong man systemd.exectrang trên Ubuntu 18.04).
cole

19

Nếu vì một lý do nào đó không thể sử dụng rsyslog, điều này sẽ làm: ExecStart=/bin/bash -ce "exec /usr/local/bin/binary1 agent -config-dir /etc/sample.d/server >> /var/log/agent.log 2>&1"


Tùy chọn -e của bash làm gì?
Đèn

3

Giả sử nhật ký đã được đặt vào thiết bị xuất chuẩn / thiết bị xuất chuẩn và đăng nhập đơn vị 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

Cấu hình rsyslog (Dịch vụ ghi nhật ký hệ thống)

# 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

Khởi động lại rsyslog

systemctl restart rsyslog.service

1

Chúng tôi đang sử dụng Centos7, ứng dụng khởi động mùa xuân với systemd. Tôi đã chạy java như dưới đây. và thiết lập StandardOutput thành tệp không hoạt động đối với tôi.

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

Dưới đây giải pháp khắc phục làm việc mà không cần thiết lập StandardOutput. chạy java qua sh như dưới đây.


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

nhập mô tả hình ảnh ở đây


-1 để xác định tham số jvm theo thứ tự sai. -Xmx512M phải được xác định trước -jar. Ngoài ra những gì bạn trải nghiệm được mong đợi. Systemd không gọi các dịch vụ bằng shell
Sami Korhonen

1
@SamiKorhonen, tôi đã thêm ý kiến ​​của mình sau khi thử nghiệm điều này đang hoạt động. Ngay cả tôi cũng đã nghĩ về thứ tự -Xmx512M rất vui với bạn. Vui lòng kiểm tra trước khi thêm ý kiến ​​mù.
Santhosh Hirekerur

0

Câu trả lời ngắn:

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

Nếu bạn không muốn xóa các tệp mỗi khi dịch vụ được chạy, thay vào đó hãy sử dụng thêm:

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

2
Bản sao của câu trả lời này , với ít chi tiết hơn
rustyx
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.