로그 파일을 여러 번 처리하는 경우 마지막으로 처리된 줄부터 시작합니다.

로그 파일을 여러 번 처리하는 경우 마지막으로 처리된 줄부터 시작합니다.

저는 웹 애플리케이션용 로깅 및 보고 시스템을 설계하고 있습니다.
웹 애플리케이션에서는 일부 이벤트("사용자 로그인", "사용자가 수행한 작업 X" 등)가 발생할 수 있습니다.
애플리케이션이 이러한 이벤트를 플랫 로그 파일에 기록하기를 원합니다.
그런 다음 주기적으로 실행되고 해당 파일에서 데이터를 가져와 데이터베이스 테이블에 실행 중인 집계 보고서를 유지 관리하는 또 다른 프로그램을 작성하고 싶습니다(예: "일일 총 이벤트 X 유형의 이벤트 수").

과제 중 하나는 보고자가 동일한 행을 두 번 처리하지 않도록 하는 것입니다.

이러한 시스템을 설계하거나 "처리된 행 추적"과 같은 문제를 처리하는 Unix 방식이 있습니까?

로그를 처리하기 전에 로그를 회전하고 각 줄에 고유한 줄 번호를 할당하는 것을 고려했지만 모두 엉망인 것 같습니다.

감사해요.

답변1

애플리케이션이 로그 파일을 영구적으로 열어 두지 않는 한, 로그를 구문 분석하기 전에 로그를 회전시키는 것이 좋은 생각처럼 들립니다. 그렇다면 회전하는 것은 작동하지 않습니다. 그러나 로깅 프레임워크를 작성하고 있으므로 이를 처리할 수 있습니다.

간단한 스크립팅을 원한다면 다음과 같은 것을 사용할 수 있습니다(거의 모든 스크립팅 언어로 수행 가능).

#! /bin/bash

process_line() {
    # do the work here
    echo "== $1 =="
}

logfile=$1
statefile=${logfile}.state

if [ -f ${statefile} ] ; then
    processed=$(cat $statefile)
else
    processed=0
fi

curline=0
IFS='
'

while read line ; do
    if [ $curline -ge $processed ] ; then
        echo processing $line
        process_line "$line"
    fi
    curline=$(($curline+1))
done < ${logfile}

echo $curline > $statefile

기본적으로 입력이 처리되는 시점을 별도의 파일( $statefile)에 저장하고, 그 시점부터 한 줄씩 입력을 처리한다(이미 처리된 입력은 건너뛰기).

분명히 이것은 더 많은 오류 처리가 필요하며 입력이 큰 경우 최적이 아닙니다. ( dd bs=1 skip=$already_read count=$(($size-$already_read))한 줄씩 작업을 수행하는 대신 바이트 오프셋 및 조회를 저장하거나 파이핑 출력을 다른 프로세스에 사용하면 더 잘 수행할 수 있지만 perl이 최적화가 필요한 경우에는 이를 사용하겠습니다.)

실제로 스크립트가 중단되면 해당 줄을 두 번 처리하게 됩니다. 끝에서 한 번만 실행하는 대신 각 줄 끝에서 상태 파일을 업데이트하여 "재생" 횟수를 제한할 수 있습니다.

로그를 처리하고 순환하는 경우 이러한 상태 파일에 주의해야 합니다. 또한 회전해야 하며 스크립트는 회전 후 한 번 실행되어 출력의 마지막 몇 줄을 처리합니다.

이 방법으로 처리하기가 쉽지 않은 부분이 바로 부분선입니다. 스크립트가 실행되는 동안 애플리케이션이 작성하는 경우 스크립트가 마지막 줄의 일부를 볼 수도 있습니다. 차이점을 알 수 없으므로 처리된 것으로 기록합니다. (이 문제를 해결하려면 거의 모든 접근 방식이 필요합니다.)

이는 로그 파일 형식에서 EOL 마커를 사용하고 라인을 처리하기 전에 확인함으로써 피할 수 있습니다. 그러나 그것은 예쁘지 않다.

bash스크립트 자체에서 처리하는 대신 다음과 같이 사용할 수 있습니다(일반으로 대체) .process_lineecho

$ ./logger /var/log/app12.log | ./analyzer --logtype=app12

./analyzer데이터를 입력으로 가져옵니다.

관련 정보