셸 스크립트를 사용한 로깅 - STDERR을 캡처하여 타임스탬프와 함께 로깅

셸 스크립트를 사용한 로깅 - STDERR을 캡처하여 타임스탬프와 함께 로깅

해결됨:

몇 달 전, 나는 로그인 쉘 스크립트에 관심을 갖게 되었습니다.

첫 번째 아이디어는 다음과 같이 함수를 수동으로 기록하는 것입니다.

add2log() {
    printf "$(date)\tINFO\t%s\t%s\n" "$1" "$2" >>"$logPATH"
}

하지만 자동화하고 싶습니다. 예를 들어 STDERR이 자동으로 기록됩니다.

오랜만에 만족스러운 답을 찾았고, 드디어 공유하는 시간을 갖게 되었습니다.


이제 각 셸 스크립트에 대해 "main.sh"를 사용하여 로깅 기능과 구성(로그 및 구성 파일 설정)을 보관합니다. 다음과 같습니다.

#!/bin/bash

###################################################################
# MY HEADERS
###################################################################


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~Global vars

mainScriptNAME=$(basename "$0")
mainScriptNAME="${mainScriptNAME%.*}"
mainScriptDIR=$(dirname "$0")
version="v0.0"
scriptsDIR="$mainScriptDIR/SCRIPTS"
addonsDIR="$mainScriptDIR/ADDONS"


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOGGER FUNCS

manualLogger() {

    # $1=PRIORITY $2=FUNCNAME $3=message
    printf "$(date)\t%s\t%s()\t%s\n" "$1" "$2" "$3" >>"$logFilePATH"
}

stdoutLogger() {

    # $1=message
    printf "$(date)\tSTDOUT\t%s\n" "$1" >>"$logFilePATH"
}

stderrLogger() {

    # $1=message
    printf "$(date)\tSTDERR\t%s\n" "$1" >>"$logFilePATH"
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~LOG & CONF

createLog() {
    # code to set and touch logFilePATH & confFilePATH
    manualLogger "INFO" "${FUNCNAME[0]}" "Log file created."
}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~MAIN

#
createLog

#run scripts
{

    #
    source "$scriptsDIR/file1.sh"
    doSomthing1
    doSomthing2

    #
    source "$scriptsDIR/file2.sh"
    anotherFunction1
    anotherFunction2

    ...


} 2> >(while read -r line; do stderrLogger "$line"; done) \
1> >(while read -r line; do stdoutLogger "$line"; done) 


다시 말해서:

  • 내가 실행하려는 모든 스크립트/함수는 ./SCRIPTS 폴더의 별도 파일에 있습니다(그래서 내 main.sh는 거의 항상 동일합니다).
  • STDOUT 및 STDERR을 캡처하기 위해 이 모든 스크립트를 { ... } 그룹에 넣습니다.
  • 해당 STDOUT 및 STDERR은 해당 로거 기능으로 리디렉션됩니다.

로그 파일은 다음과 같습니다(수동 로거, STDOUT 로거 및 STDERR 로거의 예).

Lun 23 mai 2022 12:20:42 CEST   INFO    createLog() Log file created.
Lun 23 mai 2022 12:20:42 CEST   STDOUT  Some standard output
Lun 23 mai 2022 12:20:42 CEST   STDERR  ls: sadsdasd: No such file or directory

팀은 모든 출력을 로그로 수집합니다. 대신 리디렉션 2> >(while read ...과 . 1> >(while read ...예를 들어 doSomthing1STDOUT 및 STDERR은 기록되지만 doSomthing2STDERR만 리디렉션됩니다.

답변1

표면적으로는 방금 디버깅 문을 추가한 것처럼 보입니다. 여기서 "무거운"이란 무엇을 의미합니까? Bash 스크립팅(또는 해당 문제에 대한 다른 프로그래밍 언어)에서 무언가를 다시 에코해야 하는 경우 인터프리터에게 echo전달한 내용을 알려주는 명령문이 있어야 합니다 .

스크립트(또는 코드 조각)의 특정 지점에서 작업을 수행하려는 경우 명령을 작성하는 것을 대체할 수 있는 방법은 없습니다.

IO 리디렉션을 사용하여 다양한 트릭을 얻을 수 있지만 원하는 효과를 얻으려면 시작 부분과 끝 부분에 하나씩 두 개의 명령문이 있어야 합니다.

완전히 문서화된 스크립트를 원한다면 을 참조하십시오 set -x. 스크립트의 특정 기능만 기록하려면 set -xsuhshell에서 해당 기능을 사용하세요.

(set -x; func1)

답변2

전용 디렉터리에 플래그 파일을 사용합니다.

foo.bash:
  
#!/bin/bash
[[ -f $HOME/.local/debug/foo.debug ]] && \
  source $HOME/.local/debug/foo.debug
...

foo.debug와 같은 것을 포함하여 내가 좋아하는 모든 것을 파일에 넣을 수 있으며 debug_foofunction=1나중에 디버그 코드를 호출(또는 호출하지 않음)하는 데 사용할 수 있습니다 foo( 주의하세요. 정의되지 않을 수 있음). 간단히 말하면 모든 디버깅 코드가 꺼집니다. 으로 변경하면 다른 디버깅 설정(예: )을 유지하면서 디버깅을 끌 수 있습니다 .foofunctiondebug_foofunction
rm $HOME/.local/debug/foo.debugdebug_foofunction=0foofunctiondebug_foootherfunction=1

man bash" trap" 내장 에 대해 읽어보세요 .

실제 해결책은 복잡한 스크립트를 작성하지 않는 것입니다. 문제 세트에 맞는 프로그래밍 언어를 사용하십시오.

항상 스크립트를 https://shellcheck.net구문 검사기 에 붙여넣거나 shellcheck로컬로 설치하십시오. 사용을 shellcheck개발 프로세스의 일부로 만드세요 .

관련 정보