Bricoleur88 Tech Insight

Tech News, Insights & Opinions

Study

grep command 로 에러 로그 찾기 | Linux

grep command (linux)

grep command는 리눅스/유닉스 환경에서 입력으로 전달된 파일의 내용에서 특정 문자열을 찾고자 할 때 정말 많이 사용하는 명령어 입니다.
저는 주로 문제가 발생했을 때, 에러의 원인을 찾기 위해 특정 로그 파일에서 원하는 내용을 빠르게 찾고자 할 때 많이 사용했습니다.

윈도우 OS 또는 Mac OS 의 GUI 환경에서는 특정 단어가 포함된 파일도 찾고 그 텍스트 위치도 찾기 편한 FindInFiles 라는 훌륭한 툴이 있습니다.
확실한 정보는 아니지만 제가 알기로는 한국인 개발자라고 알고 있는데요, 다음에 좀 자세히 다뤄보도록 하고 이 글에서는 이 툴에 대해 관심있을 만한 분들을 위해 깃 링크만 언급하고 넘어가도록 하겠습니다.

https://github.com/toolscode/findinfiles/releases

아무튼 이 글에서는 리눅스/유닉스 CLI 환경 혹은 터미널 환경에서 grep을 이용하는 다양하고 편리한 방법들을 소개하는 시간을 갖도록 하겠습니다.

1. grep command 예제 파일

예제 파일은 따로 없지만, 이해를 돕기위해 로그 기록이 텍스트로 남아있는 로그 파일을 탐색한다고 가정하고, 그 파일명은 test_file.log 라고 하겠습니다.
따라서 커맨드를 사용하실 때 test_file.log 대신 상황에 맞는 파일명을 그 자리에 대체하여 사용하시면 될 것입니다.

저는 직업상 트러블슈팅을 위해 에러로그를 탐색하는데 주로 사용해서 활용예가 편향적일수도 있다고 생각하는데요, 이 외에도 활용법은 다양할 수 있으니 활용하는 방법 중 하나라고 생각하시고 읽어보시면 좋을 것 같습니다.

2. grep command 예제

1) grep command : 문자열이 포함된 라인의 수를 세고 싶은 경우

텍스트 로그파일에서 Network error 라는 문자열이 몇 줄 나왔는지 (에러로 따지면 몇 번 발생했는지) 를 파악하고자 할 때 사용합니다.
그 결과가 숫자 형태로 출력됩니다.

$ grep 'Network error' -c test_file.log
2

같은 경로안에 로그 파일이 날짜나 용량 제한 생성 규칙 때문에 쪼개져서 여러파일로 존재할 수도 있습니다.

예를들어 가장 최근 파일은 test_file.log 이지만, 그 이전 로그 파일들이 다음과 같은 규칙으로 같은 경로안에 생성되어 있다고 가정해보겠습니다.

test_file.log
test_file.log-2024.09.20_0001
test_file.log-2024.09.20_0002
test_file.log-2024.09.19_0001

이 경우 여러 파일을 동시에 확인하는 것도 가능합니다. 위에 예제에서 test_file.log 뒤로 공통적인 파일명 생성 규칙을 가지고 있습니다.

따라서 애스터리스크(*)를 이용하면 다음과 같이 결과가 출력됩니다.

# 여러 파일을 동시에 확인도 가능하며 콜론(:) 뒤에 숫자가 바로 찾고자 하는 문자가 포함된 라인 수 결과입니다.
# 각 일자별로 로그 파일이 남는경우, 각 일자별 Error 로그 갯수를 세고 싶을때 유용합니다.

$ grep 'Network error' -c test_file.log*
test_file.log:1
test_file.log-2024.09.20_0001:3
test_file.log-2024.09.20_0002:2
test_file.log-2024.09.19_0001:0

한 가지 염두해 두어야 할 점은 검색한 문자열 ‘Network error’ 가 대소문자 까지 정확하게 일치하는 것만 찾는다는 점입니다.

2) 검색할 문자열이 포함된 라인 + 앞/뒤 라인을 함께 더 보고 싶을 경우

에러가 발생했을 때 에러로그 자체 메세지만 봐도 알 수 있기도 하지만, 에러로그 기준 바로 전/후에 어떤 상황 로그가 있었는지를 봐야만 원인을 명확하게 특정할 수 있는 경우가 더 많다고 생각합니다.

-A 1 옵션을 사용하면, 그 다음 한 줄을 더 출력해줍니다.
A는 After 라고 생각하면 되겠죠?
물론 1을 2로 바꾸면 한 줄 더 출력됩니다.

$ grep 'Network error' -A 1 test_file.log
ERROR 2024-09-20 09:13:03 Network error occured while UploadS3 process.
INFO 2024-09-20 09:13:03 Try again in 2 seconds later.
--
ERROR 2024-09-19 11:49:00 Network error occured while UploadS3 process.
INFO 2024-09-19 11:49:00 Try again in 2 seconds later.

예제로 알 수 있는 정보는 네트워크 에러가 S3 upload 하는 과정에서 발생했었고, 시스템이 자동으로 2초뒤에 재수행을 했는데 이틀 연속으로 발생했었네요. 이 결과로 저라면 “이 이후에 Network error 로그가 더 없는 걸 봐선 재시도 후 이상없는거 같으니 일시적인거 같은데 2일 연속으로 발생했으니 며칠 더 보고 판단 해야겠다” 라고 생각해볼거 같습니다. (또는 옵션 라인을 스텝 특성에 따라 2이상으로 늘려서 그 다음 로그를 더 보고 판단해야겠죠)

물론 에러 발생 시점보다 그 앞 (직전) 상황을 봐야하는 경우도 있을 겁니다.
그럴 때는 -A 1 옵션 대신 -B 1 옵션을 사용합니다.
(B = Before 라고 생각하면 되겠네요)

# 문자열이 포함된 라인의 위(또는 이전) 한줄을 더 출력

$ grep 'Network error' -B 1 test_file.log
requests.exceptions.ConnectionError: ('Connection aborted.', TimeoutError(110, 'Connection timed out'))
ERROR 2024-09-18 09:13:03 Network error occured while UploadS3 process.

그렇다면, 위/아래를 모두 보려면 -A 1 -B 1을 써야 될까요? 프로그래머들은 그런 귀찮음을 싫어하는지 -C 라는 옵션을 또 만들어 두었습니다.

-C 1 옵션을 쓰면 문자열이 포함된 라인의 위/아래 한 줄 씩을 모두 출력해줍니다.
(C = Center 라고 생각하면 되겠네요. 찾는 키워드를 ‘중심’으로 앞/뒤를 더 출력해주니까요.)

# 문자열이 포함된 라인과 위,아래 한 줄 씩 더 출력
# 에러 로그의 앞 뒤를 살펴봐야 할 때 유용
$ grep 'Network error' -C 1 test_file.log
requests.exceptions.ConnectionError: ('Connection aborted.', TimeoutError(110, 'Connection timed out'))
ERROR 2024-09-18 09:13:03 Network error occured while UploadS3 process.
INFO 2024-09-18 09:13:03 Try again in 2 seconds later.

3) 대소문자 구분 없이 찾는 방법

내가 정확하게 에러 키워드를 잘 모르겠고 좀 막연하게 찾고자 할 때, -i 라는 옵션 태그를 쓰면 됩니다.
단, 찾고자 하는 파일의 용량이 1GB 가 넘어가면 결과가 출력되는데 -i 옵션이 있고 없고에 따른 속도차이가 납니다.
(-i 가 있으면 속도가 느리다는 의미입니다.)


# 검색할 문자의 대소문자가 명확하지 않은 경우에 사용
# 그러나 느림!!!

$ grep -i network test_file.log
ERROR 2024-05-01 09:13:03 Network error occured while UploadS3 process.
ERROR 2024-05-01 11:49:00 Network error occured while UploadS3 process.

4) 검색한 문자열이 있는 위치의 라인 넘버를 알고 싶을 때

-n 이라는 옵션을 사용합니다.

에러로그 찾을 때는 보통 타임스탬프가 중요하지만, 관련된 에러를 찾고나서 그 원인을 고치기 위해 소스코드나 스크립트를 수정해야 할 때, 그 파일내에서 특정 키워드가 있는 라인이 어디에 있는지 찾고자 할 때 사용합니다.
(소스코드는 매우 다양할 것이므로 예제는 그냥 에러로그파일에서 찾아보는 정도로 하겠습니다. 이러한 형식으로 결과가 출력된다는 것만 아시면 됩니다.)


# 보통 소스코드나 스크립트파일 검색할 때...

$ grep -n Network test_file.log
138:ERROR 2021-05-28 09:13:03 Network error occured while UploadS3 process.
6045:ERROR 2021-05-28 11:49:00 Network error occured while UploadS3 process.

에러 메세지 로그를 생성하는 python Task.py 파일 에서 analysis is done 이라는 텍스트 메세지를 다른 메세지로 수정하려고 할 때를 가정해보면,
다음과 같은 방법으로 해당 코드가 어디에 있는지 찾는게 가능합니다.

다음은 현재 경로~ 하위 경로까지 모든 디렉터리에서 ‘analysis is done’ 이라는 텍스트가 있는 파일과 그 라인 넘버를 결과로 출력하는 예 입니다.

$ grep 'analysis is done' -r -n *
Task.py:323:  Task.do_task_log(LOGGER.info, task, 'analysis is done.')

위에서 사용한 -r 이라는 옵션은 재귀적 검색이라고 하여 자기 자신을 포함한다 라고 생각하시면 됩니다.

3. 그 밖에

사실 grep 이라는 명령어의 시너지는 다른 명령어와 파이프 (pipe, |) 조합과 함께 사용했을 때 발휘됩니다.

단순하게 첫 번째 결과를 가지고 두 번째 결과를 찾거나,

$ cat test.log | grep 'error' | grep 'Network'

도커 컨테이너의 로그에서 내가 원하지 않는 ‘Deleted’ 라는 건 제외하고 보고싶을때 처럼 말입니다.

$ docker logs test_container 2>&1 | grep -v Deleted

grep 에 대한 수 많은 예를 전부 다루고 싶지만, 자신의 직업이나 포지션에 따라 결국 자주 쓰는 것만 사용하게 되는 경향이 있고 입문하는 분들이 가장 기본적으로 이것 정도는 알고 가면 좋을 것 같아서 이 정도 까지만 다루도록 하겠습니다.

4. 다른 글

https://bricoleur88.com/포트를-알고-있을-경우-프로세스-강제-종료pid-kill-fuser-이용/


Bricoleur88 Tech Insight 에서 더 알아보기

구독을 신청하면 최신 게시물을 이메일로 받아볼 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다