추가 읽기

추가 읽기

시스템 서비스로 실행되는 쉘 스크립트가 있고 메시지를 기록하고 싶습니다.세밀한 우선순위를 가지세요서비스의 systemd 로그를 입력하십시오.

저널링을 사용할 때 logger(1)일부 메시지만 기록하고 나머지는 삭제합니다. 어떤 메시지가 서비스 로그에 기록되는지는 완전히 무작위인 것처럼 보입니다. 때로는 하나 또는 두 개의 메시지만 기록되고 때로는 메시지가 전혀 기록되지 않습니다.

journalctl --system처음에는 부팅 순서/종속성 문제인 줄 알았습니다. 그러나 모든 메시지가 시스템 로그(예: )에는 나타나지만 서비스 로그(예: journalctl -u SERVICE.service) 에는 나타나지 않기 때문에 그런 것은 아닌 것 같습니다 . 나도 시도해 보았지만 systemd-cat불행히도 비슷하게 작동합니다.

스크립트 기반 서비스가 우선순위 메시지를 자체 시스템 로그에 기록하는 올바른 방법은 무엇입니까?

답변1

systemd가 직면한 문제는 logger자체 도구 systemd-notify가 직면한 문제와 동일합니다 . 이 프로토콜은 데이터그램을 기반으로 하는 비동기 프로토콜이며 도구는 하나의 작업만 완료합니다. 호출자는 도구를 실행하기 위해 프로세스를 분기합니다. 데이터그램을 내보내고 해당 프로세스는 종료됩니다.

systemd로깅 및 준비 알림 프로토콜에 대한 서버 프로세스는 보낸 사람이 어떤 서비스에 속해 있는지 알고 싶어하며, 전자는 로그 항목에 올바른 서비스 이름 필드를 추가하기 위해, 후자는 어떤 서비스에 대해 이야기되고 있는지 알기를 원합니다. Linux에서 데이터그램 보낸 사람의 프로세스 ID를 얻은 다음 프로세스 테이블로 이동하여 프로세스가 속한 제어 그룹과 프로세스가 속한 서비스를 찾습니다.

전송 프로세스가 작업을 완료하고 즉시 종료되는 경우에는 작동하지 않습니다(경쟁 조건에 따라 다름). 프로세스가 더 이상 프로세스 테이블에 존재하지 않습니다. systemd-notify알림이 실패했습니다. logger메시지가 관련 서비스에 속하는 것으로 표시되지 않습니다. 스트리밍 프로토콜로 전환해도(예: logger's --tcp옵션 사용) 문제가 해결되지 않습니다.~하지 않는 한로깅 프로토콜 자체는반품클라이언트가 스트림을 닫고 종료하기 전에 서버의 응답을 기다리도록 변경되었지만 그렇지 않습니다. RFC 5426 서버 승인이 클라이언트로 다시 전송되지 않습니다.

따라서 로그 정보가 로그에 있는 동안에는 서비스 이름으로 태그가 지정되지 않으며 서비스 이름으로 쿼리할 때 가져오지 않습니다. (그런데 이것들은 생각하는 것처럼 별도의 로그가 아닙니다. journalctl하나의 큰 로그에 적용된 필터일 뿐입니다. -u필터입니다.)

이것은 오래 전부터 잘 알려진 실수입니다.

사람들은 systemd이것을 Linux의 결함이라고 설명합니다. 프로세스 집합을 캡슐화하고 추적하는 데 사용할 수 있는 적절한 작업 개체가 없습니다. 해당 데이터그램 소켓 메커니즘 AF_LOCAL도 그러한 정보를 전송하지 않습니다. 그렇다면 systemd모든 서비스 프로세스를 하나의 작업에 넣을 수 있으며 해당 로깅 및 준비 알림 서버는 클라이언트 프로세스가 종료된 경우에도 데이터그램이 수신되면 클라이언트 작업 정보를 추출할 수 있습니다.

system-journald일부 버전 logger에서는 작동하는 특수 프로토콜이 있습니다 . 아니요, _SYSTEMD_UNIT이는 서버에 의해 설정된 "신뢰할 수 있는 필드"입니다. 이를 설정하려는 클라이언트의 모든 시도는 무시됩니다. 이 역시 데이터그램을 기반으로 하는 비동기 프로토콜이므로 확인이 필요하지 않습니다. 똑같은 문제가 있습니다.

올바른 서비스로 로그 항목에 안정적으로 태그를 지정하려면표준 오류에 쓰기. 이는 수명이 길고 서버측 서비스 단위 이름에 대한 보다 안정적인 연결을 허용합니다. 예, 레거시 시설과 우선 순위를 지정할 수는 없습니다.

추가 읽기

답변2

@JdeBP의 매우 유용한 답변을 통해 내 메시지가 올바른 서비스 로그에 표시되도록 하는 방법을 찾을 수 있었습니다. 문제는 및 journald및 Harvest 사이의 경쟁 조건에서 발생하므로 logger다음에서 수명이 긴 중간 데이터그램을 가질 수 있습니다. 각 스크립트/서비스에 대해. 이렇게 하면 journald전송 프로세스가 항상 발견됩니다.

socat다음 함수는 아직 시작되지 않은 경우 릴레이를 시작한 다음 logger기본값 대신 릴레이 소켓으로 전송되도록 메시지를 설정합니다. 상위 스크립트가 종료되면 릴레이가 자동으로 종료되고 해당 소켓을 삭제합니다.

# Usage:  builtin_logger  TAG SEVERITY MESSAGE
builtin_logger() {
    if [[ "${SHELL_SERVICE_LOG_SOCK-}" == "" ]]; then
        declare -g SHELL_SERVICE_LOG_SOCK
        SHELL_SERVICE_LOG_SOCK="/tmp/service-log.$$"
        sh -c "socat UNIX-RECV:'$SHELL_SERVICE_LOG_SOCK' UNIX-SENDTO:'/dev/log' &
               SOCAT_PID=\$!
               trap \"if [ -e '$SHELL_SERVICE_LOG_SOCK' ]; then rm '$SHELL_SERVICE_LOG_SOCK'; kill \$SOCAT_PID; fi\" EXIT INT TERM
               tail --pid=$$ -f /dev/null" & 
        sleep 0.1 # waiting for socat to run (TODO inotify)
    fi
    logger -u "$SHELL_SERVICE_LOG_SOCK" -t "$1" -p user."$2" "$3"
}

관련 정보