특정 시간보다 큰 특정 로그 항목을 grep

특정 시간보다 큰 특정 로그 항목을 grep

특정 텍스트를 사용하여 현재 날짜보다 이후의 특정 시간에 대한 로그를 필터링하려고 합니다. 현재 날짜가 포함된 텍스트에 대한 로그를 성공적으로 필터링했습니다. 이것은 명령입니다:

grep "$(date +"%d/%b/%Y")" test.log | grep -i "failed login"

샘플 로그는 다음과 같습니다.

[04/Dec/2019 02:05:13 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser

[04/Dec/2019 02:05:15 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser

[04/Dec/2019 02:04:59 -0800] access       INFO     10.126.49.92 ahmed.rao - "POST /notebook/api/check_status HTTP/1.1" returned in 759ms

[04/Dec/2019 02:05:00 -0800] base         INFO     Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2

[04/Dec/2019 03:05:00 -0800] access       INFO     10.126.49.92 ahmed.rao - "POST /notebook/api/close_statement HTTP/1.1" returned in 1345ms

[04/Dec/2019 03:05:00 -0800] base         INFO     Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2

[04/Dec/2019 03:05:18 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser

그런데 특정 시간보다 큰 조건을 적용하는 방법을 모르겠습니다.

답변1

tsfrom 을 사용하면 moreutils이러한 타임스탬프를 보다 유용한 형식으로 쉽게 변환할 수 있습니다.

ts -r %FT%T%z < file.log |
  awk '$0 > "[2019-12-04T02:50" && tolower($0) ~ /failed login/'

귀하의 입력 (및 timezone America/Los_Angeles)을 고려하면 다음과 같습니다.

[2019-12-04T03:05:18-0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser

ts해당 타임스탬프를 구문 분석 하고 -r지정된 %FT%T%z strftime형식(시간대로)으로 변환합니다.

형식은 어휘 및 시간순으로 동일하게 정렬되므로 지정된 날짜보다 이후의 항목을 찾으 YYYY-MM-DDTHH:MM:SS려면 문자열 비교만 필요합니다 . 여전히 일을 할 수 있습니다 . 여기서는 대소문자를 구분하지 않는 표준 일치 방법이 사용됩니다 . GNU를 사용하면 다음을 수행할 수도 있습니다.awkawkgrep -itolower()awk

gawk -v IGNORECASE=1 '$0 > "[2019-12-04T02:50" && /failed login/'

없는 경우 's를 사용하여 moreutils구문 분석을 수행할 수 있습니다('s를 사용하는 Perl 스크립트이지만 's와는 반대로 의 핵심 모듈 중 하나가 아니므로 시스템에 설치되지 않을 수 있음).perlTime::PiecetsDate::ParseTime::Pieceperl

CUT=2019-12-04T02:50:00-0800 perl -MTime::Piece -F'[][]' -ale '
  BEGIN{$cut = Time::Piece->strptime($ENV{CUT}, "%FT%T%z")}
  print if /failed login/i &&
           Time::Piece->strptime($F[1], "%d/%b/%Y %T %z") >= $cut' < file.log

1 DST를 적용하는 시간대에서 겨울/여름 시계 변경 시간을 무시하면

답변2

누군가가 유용하다고 생각할 경우를 대비해 남겨두겠습니다. 하지만 그냥 사용하세요.이 답변대신에. 더 간단하고 효율적입니다.


Perl 메소드는 다음과 같습니다.

$ perl -lne 'if(/^\[([^]]+)/){$d=$1; chomp($dateThreshold=`date -d "04 Dec 2019" +%s`); $d=~s|/| |g; chomp($d=`date -d "$d" +%s`); print if $d >= $dateThreshold;} ' test.log 
[04/Dec/2019 02:05:13 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:05:15 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:04:59 -0800] access       INFO     10.126.49.92 ahmed.rao - "POST /notebook/api/check_status HTTP/1.1" returned in 759ms
[04/Dec/2019 02:05:00 -0800] base         INFO     Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:00 -0800] access       INFO     10.126.49.92 ahmed.rao - "POST /notebook/api/close_statement HTTP/1.1" returned in 1345ms
[04/Dec/2019 03:05:00 -0800] base         INFO     Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:18 -0800] access       WARNING  10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser

그리고 더 명확하게 말하자면:

perl -lne 'if(/^\[([^]]+)/){ ## skip lines that do not match
            ## Save the date of the current line as $d
            $d=$1; 
            ## Replace all slashes with pipes so the 'date' command
            ## can read this as a date.
            $d=~s|/| |g; 
            ## Now, translate $d into seconds since the epoch
            chomp($d=`date -d "$d" +%s`); 
            ## Set the threshold date in seconds since the epoch.
            chomp($dateThreshold=`date -d "04 Dec 2019" +%s`); 
            ## Print this line if its date is greater than or equal to the threshold
            print if $d >= $dateThreshold;
           } ' test.log 

BEGIN마지막으로 스크립트가 시작될 때 한 번만 실행되도록 임계값 설정 단계를 블록으로 이동하여 효율성을 향상시킬 수 있습니다 .

perl -lne 'BEGIN{chomp($dateThreshold=`date -d "04 Dec 2019" +%s`); } if(/^\[([^]]+)/){$d=$1; $d=~s|/| |g; chomp($d=`date -d "$d" +%s`); print if $d >= $dateThreshold;} ' test.log 

답변3

awkGNU 명령을 호출하는 GNU 를 사용한 또 다른 답변은 다음과 같습니다 date.

awk(우리가 부르는) 프로그램은 다음 find_after_timestamp.awk과 같습니다:

BEGIN{
    gsub("/"," ",start_datetime)
    extcmd=sprintf("date -d \"%s\" +\"%%Y %%m %%d %%H %%M %%S\"",start_datetime)
    extcmd | getline startstring
    close(extcmd)
    start_ts=mktime(startstring)
    print "Lines will be matched starting with timestamp",start_ts

    printf("Will look for: \"%s\"\n",searchpat)
}


{
    if (match($0,/^\[([[:print:]]*)\][[:print:]]*$/,line_datetime)==0) next
    gsub("/"," ",line_datetime[1])
    extcmd=sprintf("date -d \"%s\" +\"%%Y %%m %%d %%H %%M %%S\"",line_datetime[1])
    extcmd | getline line_dtstring
    close(extcmd)
    line_ts=mktime(line_dtstring)
    if (line_ts > start_ts && $0 ~ searchpat) print
}

당신은 그것을 부를 것입니다

awk -v start_datetime="04/Dec/2019 02:05:21 -0800" -v searchpat="[Ff]ailed login" -f find_after_timestamp.awk test.log

여기서 변수는 start_datetime검색 범위의 시작이 됩니다. 즉, 날짜/시간이 이 시점과 같거나 이후인 모든 항목이 고려됩니다. 값은 start_datetime로그 파일과 동일한 형식이어야 하지만 그 외에는 임의적이며 파일에 실제로 존재하는 값일 필요는 없습니다. 이 변수에는 searchpat찾고 있는 패턴이 포함됩니다.

설명하다

  • DD/MONTH/YYYY HH:MM:SS TIMEZONE이 구조 는 날짜 부분 date의 . 를 공백으로 대체 하여 ("비표준"이 아닌) 날짜/시간 사양을 GNU가 이해할 수 있는 것으로 변환하는 것을 중심으로 진행됩니다 ./gsub

  • 그런 다음 셸에서 문자열을 실행 하고 결과를 문자열 변수로 읽어 date(설정 단계, 파일 구문 분석 단계에서) 외부 명령을 호출합니다. 이제 내장 함수가 ist를 구문 분석할 수 있도록 형식이 지정됩니다.extcmdstartstringline_dtstringawkmktime

  • mktime명령은 사람이 읽을 수 있는 날짜/시간 사양을 산술 비교를 사용하여 비교할 수 있는 순수 숫자 UNIX 시간으로 변환합니다.

  • 단계 에서는 BEGIN시작 날짜 사양을 변환하기 위해 수행되고 본문에서는 현재 행과 연결된 타임스탬프를 변환하기 위해 수행됩니다. 타임스탬프가 없는 행은 무시됩니다( if (match(...)==0) next).

  • 현재 행에 참조 시작 타임스탬프보다 큰(= 이후) 타임스탬프가 있고 searchpat해당 행에서 발견되면 해당 행이 인쇄됩니다.

awk프로그램에서 외부 프로그램에 의존해야 한다는 것이 약간 눈살을 찌푸리게 한다는 것을 알고 있지만 이는 거의 모든 설치에서 사용할 수 있는 기본 도구를 사용하여 수행할 수 있습니다.

답변4

sed를 사용하세요:

sed -n "/$(date +'%d\/%b\/%Y')/,/*/p" test.log | grep -i "failed login"
  • 일치(날짜) 이후의 모든 내용을 인쇄합니다.

참고: 현재 날짜는 로그 파일에서 확인할 수 있어야 합니다.

관련 정보