애플리케이션 로그에 장애 흔적이 없다면? (+VI 활용편)

Jake
26 min readJun 12, 2023

--

Overview

https://www.shutterstock.com/ko/search/troubleshooting

우리는 애플리케이션에서 발생하는 에러를 로깅함으로써 이슈를 해결합니다. 하지만 애플리케이션에서 미처 로깅하지 못한 에러들을 마주하였을 때에는 난감한 상황을 겪게 됩니다. 분명 문제가 발생하여 애플리케이션이 재시작을 하였는데 어떤 이슈로 인해 재시작 되었는지 모르기 때문입니다. 또한 이런 종류의 이슈들은 빈번하게 발생하는 이슈라기보다는 간헐적으로 발생하기 때문에 해당 이슈에 대해 어떻게 문제를 해결해야 하는지 접근하기가 어렵습니다.

특히나 하나의 Applicaton 이 아닌 여러 애플리케이션으로 서비스가 이루어졌을 때에는 에러에 대한 흔적을 찾기가 어렵습니다. 물론 kibana 와 같이 각각의 서버에서 수집한 error log 를 활용하여 모니터링 해주는 서비스가 있으나, 이러한 서비스는 error 에 대한 로그 자체가 수집되지않는경우에는 장애 상황을 파악하기 어렵습니다.

그렇다면 우리는 애플리케이션에서 수집하지 못한 장애 상황에 있어서 문제해결을 위해 어디서부터 접근해야 할까요?

우선 우리가 겪는 에러들을 정형화해볼까요?

우리가 마주할 수 있는 문제 상황

우리가 만들어낸 애플리케이션에서는 다양한 문제가 발생되기도 합니다.

가령,

  • 애플리케이션 로직에서 NPE 가 터졌을 때
  • Client 에서는 요청을 보냈다고 하는데, 우리의 서버에는 흔적이 없는 경우
  • 파일 업로드가 제한될 때
  • 조용히 재시작한 애플리케이션
  • CPU 과부하, 메모리 부족, 디스크 공간 부족 등

등의 유형들이 있습니다. 그럼 이러한 상황에서는 유형별로 어떻게 찾아가야 할지 알아보겠습니다.

애플리케이션 로직에서 NPE 가 터졌을 때

키워드를 NPE (Null Point Exception) 이라 잡았지만, 전반적인 애플리케이션 오류의 Case 를 의미합니다. NPE 인 경우 주로 변수나 객체가 null 인 상태에서 해당 변수 객체의 메서드를 호출하거나 필드에 접근할 때 발생합니다. 이처럼 애플리케이션 로직 상에서 잘못된 코드나 구성에 대한 오류로 발생할 수 있는 에러인 경우는 애플리케이션 로그에서 알 수 있습니다.

스프링부트에서 자주 채택되는 Logback, log4j, golang 에서는 logrus 등과 같이 로그 라이브러리들을 통해 우리는 애플리케이션 단에서 에러처리를 하고, 에러가 발생 시 에러 로그 파일에 해당 에러를 기록합니다.

애플리케이션에서 발생하는 에러들은 수집하기 위해 JSON Format 으로 기록하거나 error log 파일의 위치를 logstash 에 등록해 수집되기도 합니다.

이러한 에러 로그들은 말 그대로 관리되는 에러 들이므로 개발자들이 즉각적으로 빠르게 접할 수 있는 에러들입니다.

Client 에서는 요청을 보냈다고 하는데, 우리의 서버에는 흔적이 없는 경우

만일 하나의 WAS (WebApplicationServer) 와 Client 가 직접 연결되어 있는 구성이라면 Client 에서 보낸 요청은 반드시 WAS 에 남습니다. 그러나 우리의 서비스는 Tomcat, Nginx 와 같은 WebServer 구성을 가지고 있기도 하고 API Gateway 와 같은 구성도 종종 있는 경우가 있습니다.

만일 잘못된 요청에 대한 권한이나 인증 처리를 API Gateway 위치에서 걸러주고 있다면 Client 는 도메인에 요청을 보냈는데도 불구하고 우리의 WAS 에는 해당 요청에 대한 흔적이 남아 있지 않을 수 있는 것이죠.

또한, 우리의 애플리케이션 서버가 70대라면 하나 하나 요청에 대한 흔적을 뒤져볼수도 없기도 합니다.

위의 제목으로 돌아와, Client 에서 요청을 보냈다고 하는데, Application Log 를 수집하지 못한 경우에는 우선적으로 우리의 서비스로 Request 가 정말 들어왔는지 점검을 해야합니다. 그리고 그 요청의 status code 나 request, response body 에 대한 정보도 실제로 어떻게 들어왔는지를 알아야합니다.

그러면 Request 가 우선적으로 들어오는 WebServer 와 API Gateway 에 대해 알아볼까요.

Webserver

https://vietnamlife.info/nginx-%EB%B0%9C%EC%9D%8C%EC%9D%B4-%EC%97%94%EC%A7%84-x%EB%9D%BC%EA%B3%A0-%EC%A0%95%ED%99%95%ED%9E%88-%EB%B0%9C%EC%9D%8C%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-nginx-%EC%A0%90%EC%9C%A0%EC%9C%A8/

웹서버는 일종의 프록시 서버의 역할로 우리의 WAS(Web Application Server) 앞에서 요청을 받아주는 역할을 하는 서버입니다.

웹서버는 정적인 컨텐츠를 제공하며 동적인 데이터가 필요한 정보의 경우 백엔드 서비스로부터 API 호출을 담당합니다. 일종의 API 게이트웨이 역할을 하는 것이죠.

그렇기 때문에 우리는 일단 Client 로부터 요청이 잘 왔는지 정보들을 webserver 의 로그에서 볼 수 있습니다.

특히 Nginx 는 웹서버, 리버스 프록시, 로드 밸런서, 메일 프록시, 캐시 서버 등 다양한 기능을 지원하는 프로그램이므로 해당 로그에서 요청에 대한 정보를 파악할 수 있습니다.

nginix 의 log 는 access.log 와 error.log 에서 확인할 수 있습니다.

nginix 의 nginx.conf 파일에서 log 파일을 설정할 수 있으며 경로도 확인할 수 있습니다.

http {
...

server {
access_log /var/log/nginx/default/access.log;
error_log /var/log/nginx/default/error.log;
}
}

nginix 는 기본 로그 포맷을 다음과 같이 사용합니다.

$log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
  • $remote_addr: 클라이언트의 IP 주소
  • $remote_user: 클라이언트의 인증된 사용자 (인증되지 않은 경우 비워짐)
  • $time_local: 로그 기록 시간 (형식: [일/월/년:시간:분:초 +시간대])
  • $request: 클라이언트의 요청 메서드, URL 및 HTTP 버전
  • $status: 서버의 응답 상태 코드
  • $body_bytes_sent: 클라이언트로 보내진 응답 바이트 수
  • $http_referer: 이전 페이지의 URL (참조)
  • $http_user_agent: 클라이언트의 사용자 에이전트 (브라우저 등)
192.168.33.1 - - [15/Oct/2019:19:41:46 +0000] "GET / HTTP/1.1" 200 396 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"
  • $remote_addr : 192.168.33.1
  • $remote_user: -
  • $time_local: [15/Oct/2019:19:41:46 +0000]
  • $request: "GET / HTTP/1.1"
  • $status: 200
  • $body_bytes_sent: 396
  • $http_referer: -
  • $http_user_agent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"

API Gateway

https://blog.zarathu.com/posts/2022-02-08-traefik-reverseproxy/

API Gateway 는 다양한 백엔드 서비스의 API 호출을 관리하고 보안, 인증, 로깅, 모니터링의 기능을 제공합니다. 웹서버와 API Gateway 의 차이점이라고 한다면, 웹서버는 정적인 컨텐츠, HTTP/HTTPS 보안 연결 등을 제공하는데 초점이 맞춰진 반면 API Gateway 는 API 의 요청을 해당 서비스로 라우팅하는 기능, 보안, 인증, 로깅, 모니터링 등 요청에 대한 관리에 초점이 맞춰진 것을 알 수 있습니다.

실제 서비스에서는 이러한 위에서 언급한 역할 분담을 통해 각각 역할에 특화된 서비스를 구성하는 형태를 진행합니다.

API Gateway 의 로깅에서도 웹서버에서 확인했던 부분과 같이 Client 로부터 받은 요청이 해당 서비스에 잘 당도했는지를 보게 됩니다.

2023. 6. 7. 오전 9:09:52169.255.26.77 - - [07/Jun/2023:00:09:52 +0000] "GET / HTTP/1.1" 404 19 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" 3065 "backend not found" "/" 0ms
  • 시간: 2023년 6월 7일 오전 9시 9분 52초
  • IP 주소: 169.255.26.77
  • 사용자: 사용자 정보가 없음 (“-”)
  • 날짜 및 시간: [07/Jun/2023:00:09:52 +0000]
  • 요청 메서드: “GET”
  • 요청 URL: “/”
  • HTTP 버전: “HTTP/1.1”
  • 응답 상태 코드: 404
  • 응답 바이트 수: 19
  • 참조 (이전 페이지 URL): “-”
  • 사용자 에이전트: “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36”
  • 응답 시간: 0ms
  • 추가 정보: “backend not found”
  • 요청 도메인: “/”
  • 응답 시간: 0ms

WebServer 와 API Gateway 에서 우리가 알 수 있는 에러 상황

위처럼 WebServer, API Gateway 의 로그에서 Client 로부터 받은 요청이 잘 들어왔는지 확인할 수 있습니다.

  • Client 로부터 받은 Request 가 일단 정말 들어왔는지 어디 계층까지 로그가 찍혀있는지
  • Request 가 4XX 에러로, 잘못된 권한이나 요청의 형태로 들어왔는지
  • 404 에러로 아예 잘못된 URL 로 요청이 들어왔는지
  • 503 에러로, 해당 요청이 발생했을 시간에 서버가 일시적으로 요청을 처리하지 못하는 경우인지
  • 504 에러인 게이트웨이 시간 초과(Gateway Timeout) 로, Client 로 부터 받은 요청이 뒷 단의 여러 서버들을 거치면서 Timeout 이 발생했는지

의 경우들을 WebServer 나 API Gateway 에서 볼 수 있습니다.

파일 업로드가 제한될 때

파일 업로드가 제한되는 경우는 애플리케이션에서도 각종 에러로 제한될 수 있지만, WebServer 에서의 설정으로 인해 제한되는 경우도 있습니다.

Nginx 는 기본적으로 클라이언트로부터 전송되는 요청의 바디 크기를 제한합니다. 이러한 제한은 client_max_body_size 보다 크면 업로드를 거부하고 클라이언트에게 에러 응답을 반환합니다.

또한 .php , .exe 같은 실행 가능한 파일의 경우도 업로드를 제한합니다. 만일 실행파일이 애플리케이션의 업로드된다면 내부적으로 어떤 로직이 돌 수도 있기 때문에 보안의 이유로 차단되는 것이죠. 이는 upload_file_type 이라는 설정으로 업로드 파일 확장자를 지정합니다.

Nginx 는 업로드된 파일을 임시 디렉토리에 저장합니다. 만일 디스크 공간이 부족하다면 파일 업로드가 실패할 수 있습니다.

대용량 파일의 업로드의 경우, 업로드 처리시간이 오래 걸릴 경우 Timeout 에러가 날 수 있습니다. 때문에 Nginx 에서는 client_body_timeout 설정으로 업로드 처리 시간을 적절히 조정해야 합니다. 업로드 처리 시간이 초과되면 Nginx 는 연결을 닫고 업로드를 중단합니다.

파일 업로드를 예시로 들었던 이유는 파일 업로드 기능이라도 애플리케이션보다 앞에 위치한 웹서버에서 에러를 반환할 수 있기 때문입니다. 물론 첫번째로 애플리케이션 로그를 확인하겠지만 해당 로그가 남아있지 않으면 Nginx 나 ApiGateway 등 앞단에서 흔적을 찾아볼 수 있습니다.

조용히 재시작한 애플리케이션

애플리케이션이 재시작되는데, 이에 대한 알람이나 애플리케이션 로그에서 그 흔적을 찾을 수 없는 상황.. 조용이 재시작한 애플리케이션을 마주한 적은 없으신가요?

프로그램이 조용히 꺼졌다 켜지는 것은 상상할 수 없겠죠.. 그리고 이것은 매우 위험한 일이라는 것입니다. 우리의 서비스가 어떤 에러도 내뿜지 않고 꺼진다는 것은 서비스에서 매우 치명적이기 때문이죠. 물론 조용하다는 것은 애플리케이션 로그에서 해당 흔적이 없다는 것을 의미할 뿐이지 어디엔가에는 흔적이 남아있을 것입니다.

바로 수집하지 않은 로그에 말이죠. 물론 애플리케이션에서 발생할 수 있는 모든 에러를 로깅하고 수집한다면 이러한 상황은 일어나지 않겠지만 만에하나 이런 상황이 발생한다면 우리는 흔적을 찾을 수 있어야겠죠.

그러면 우리는 어떤 곳부터 이런 흔적을 찾아봐야 할까요?

Docker Log

https://linuxhandbook.com/docker-logging/

애플리케이션에도 흔적이 없고 웹서버, API Gateway 에서도 요청이 제대로 들어온 것을 확인하였다면, 에러가 발생했으나 애플리케이션 로그에 남기지 않는 경우를 의심해봐야 합니다.

우리는 각 애플리케이션마다 logrus , log4j 등 로그 라이브러리를 활용하여 프린트를 하는데 에러가 발생한 부분에 대해서 로깅을 하지 않고 멈춰버리는 현상이 있을 수 있는 것이죠.

때문에 해당 error log 가 수집되지 않아 로깅 모니터링 서비스에서도 이를 볼 수 없는 경우가 발생하기도 합니다.

그럼 개발자가 찍는 애플리케이션 로그 말고, Docker 의 로그를 보도록 할까요?

로그 확인하기

# 전체 로그 확인
docker logs {container}
# 마지막 로그 10줄 확인
docker logs --tail 10 {container}
# 실시간 로그 스트림 확인
docker logs -f {container}
# 로그마다 타임스탬프 표시
docker logs -f -t {container}
# 지정된 시간 이후에 기록된 로그만 출력
docker logs --since 2023-06-01 {container}
# 지정된 시간 이전에 기록된 로그만 출력
docker logs --until 2023-06-07 {container}
# 추가적인 컨테이너 정보
docker logs --details {container}

먼저 로그 확인하는 방법입니다. 만일 문제가 생겼을 때 즉각적으로 바로 확인할 수 있는 명령어이기도 합니다.

또한 여기서 Tip 으로 VI 명령어 중 해당 출력 내용을 파일 쓰기하는 유용한 명령어가 있습니다.

바로 >> 입니다.

만일 위의 docker logs 명령어와 결합하여 사용하게 된다면 다음과 같습니다.

docker logs --since 2023-06-06 --until 2023-06-08 76d2c63abf52 >> /tmp/logging.txt

위의 명령어를 사용한다면 우리는 도커의 특정 기간동안 기록된 로그를 파일로 추출하여 확인해볼 수 있습니다.

Docker 의 Log Driver ?

도커 컨테이너에서 로그를 기록할 때에는 Docker 의 logging driver 를 통해 기록됩니다.

도커에서 표준 출력(stdout)과 표준 에러(stderr) 를 로깅 드라이버에서 관리하는데, 이 중 json-file 의 로그 드라이브가 가장 많이 쓰입니다.

여기서 우리가 알 수 있는 중요한 정보는 바로 호스트 운영체제의 로그 저장 경로 입니다.

해당 에러가 너무 오래전이거나 도커를 리스타트하는 바람에 위의 명령어를 통해서 확인을 못하는 경우가 있습니다.

그러나 이 로깅 드라이버 json-file 일 때에는 바로 아래 경로에서 docker 의 log 가 rotate 되면서 기록됨을 알 수 있습니다.

cat /var/lib/docker/containers/${container_id}/${container_id}-json.log

이 때 중요한 부분은 해당 위치는 root 권한이어야 보이기 때문에 sudo su - 로 root 권한을 획득한 후에 확인이 필요합니다.

위의 이미지처럼 docker log 로 찍힌 부분들을 해당 위치에서 볼 수 있어 옛날에 발생했던 log 들도 확인할 수 있었습니다!

로그 용량 제한하기

  • 컨테이너 단위로 로그 용량 제한을 할 수 있지만 도커 엔진에서 기본 설정을 진행할 수도 있습니다.
  • 운영환경에서 필수 설정
# 한 로그 파일 당 최대 크기를 3Mb로 제한하고, 최대 로그파일 3개로 로테이팅
docker run \\
-d \\
--log-driver=json-file \\
--log-opt max-size=3m \\
--log-opt max-file=5 \\
nginix

CPU 과부하, 메모리 부족, 디스크 공간 부족 등

애플리케이션의 에러가 아닌, 애플리케이션이 설치된 시스템 문제로도 에러가 발생할 수 있습니다. 만일, 특정 시간대에 부하로 인해 CPU, 메모리, 디스크 공간 등의 자원에 대한 에러로 의심된다면 우리는 syslog 를 확인해봐야 합니다.

Syslog

  • syslog 는 시스템의 로깅 메시지를 수집, 저장 및 관리하는 표준화된 시스템 로깅 프로토콜과 시스템 로그파일을 의미합니다.
  • syslog 는 다양한 운영체제에서 사용되지만 특히, 리눅스 시스템에서 흔히 사용됩니다.
  • 로그파일은 /var/log 디렉터리에 저장되며, 여러가지 로그파일로 구성되어 있습니다.
  • syslog 는 /var/log/syslog , /var/log/syslog1 로그파일에서 시스템의 로그들을 볼 수 있습니다.
  • syslog 는 커널 이벤트, 애플리케이션, 보안, 시스템 이벤트 등 다양한 로그들을 포함합니다.
Dec 12 11:15:10 HOSTNAME dockerd[441]: failed to start daemon: error while opening volume store metadata database: timeout
Dec 12 11:15:10 HOSTNAME systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Dec 12 11:15:10 HOSTNAME systemd[1]: docker.service: Failed with result 'exit-code'.
Dec 12 11:15:10 HOSTNAME systemd[1]: Failed to start Docker Application Container Engine.
Dec 12 11:15:10 HOSTNAME dbus-daemon[320]: [system] Successfully activated service 'org.freedesktop.timedate1'
Dec 12 11:15:10 HOSTNAME systemd[1]: Started Time & Date Service.
Dec 12 11:15:10 HOSTNAME systemd[1]: Finished Wait until snapd is fully seeded.
Dec 12 11:15:10 HOSTNAME systemd[1]: Condition check resulted in Auto import assertions from block devices being skipped.
Dec 12 11:15:10 HOSTNAME udisksd[335]: Error statting /swap/file: No such file or directory
Dec 12 11:15:10 HOSTNAME lxd.activate[382]: => Starting LXD activation
Dec 12 11:15:10 HOSTNAME lxd.activate[382]: ==> Loading snap configuration
Dec 12 11:15:10 HOSTNAME lxd.activate[382]: ==> Checking for socket activation support
Dec 12 11:15:10 HOSTNAME lxd.activate[382]: ==> Setting LXD socket ownership
Dec 12 11:15:10 HOSTNAME lxd.activate[382]: ==> LXD never started on this system, no need to start it now
Dec 12 11:15:10 HOSTNAME systemd[1]: snap.lxd.activate.service: Succeeded.

위의 로그들을 보면, 각 프로세스들의 로깅메시지들을 볼 수 있으며, 만일 장애가 발생했던 시간에 시스템적으로 어떤 흔적이 있는지 찾아볼 수 있습니다.

dmesg

  • dmesg 는 리눅스와 유닉스 기반 시스템에서 사용되는 명령어입니다.
  • 커널 메시지 버퍼에 저장된 시스템 부팅 및 커널 메시지를 출력하는데 사용됩니다.
  • dmesg 명령어를 실행하면 커널이 생성한 로그메시지를 활용할 수 있습니다.
  • dmesg 는 커널 버퍼에 저장된 로그 메시지를 출력하는 것으로, 로그가 시스템 메모리에만 저장되며, 시스템 재부팅시에는 초기화됩니다.
# 최신 메시지만 출력
dmesg -T
# 페이징 된 커널 버퍼에 저장된 메시지 출력
dmesg -T | less
  • dmesg 예시
[Mon Jun 12 05:37:29 2023] PCI: Using ACPI for IRQ routing
[Mon Jun 12 05:37:29 2023] PCI: System does not support PCI
[Mon Jun 12 05:37:29 2023] clocksource: Switched to clocksource tsc-early
[Mon Jun 12 05:37:29 2023] hv_vmbus: Unknown GUID: c376c1c3-d276-48d2-90a9-c04748072c60
[Mon Jun 12 05:37:29 2023] VFS: Disk quotas dquot_6.6.0
[Mon Jun 12 05:37:29 2023] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[Mon Jun 12 05:37:29 2023] FS-Cache: Loaded
[Mon Jun 12 05:37:29 2023] pnp: PnP ACPI init
[Mon Jun 12 05:37:29 2023] pnp 00:00: Plug and Play ACPI device, IDs PNP0b00 (active)
[Mon Jun 12 05:37:29 2023] pnp: PnP ACPI: found 1 devices
[Mon Jun 12 05:37:29 2023] NET: Registered protocol family 2
[Mon Jun 12 05:37:29 2023] tcp_listen_portaddr_hash hash table entries: 16384 (order: 6, 262144 bytes, linear)
[Mon Jun 12 05:37:29 2023] TCP established hash table entries: 262144 (order: 9, 2097152 bytes, linear)
[Mon Jun 12 05:37:29 2023] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes, linear)
[Mon Jun 12 05:37:29 2023] TCP: Hash tables configured (established 262144 bind 65536)
[Mon Jun 12 05:37:29 2023] UDP hash table entries: 16384 (order: 7, 524288 bytes, linear)
[Mon Jun 12 05:37:29 2023] UDP-Lite hash table entries: 16384 (order: 7, 524288 bytes, linear)
[Mon Jun 12 05:37:29 2023] NET: Registered protocol family 1
[Mon Jun 12 05:37:29 2023] RPC: Registered named UNIX socket transport module.
[Mon Jun 12 05:37:29 2023] RPC: Registered udp transport module.

VI 활용을 통한 로그 파일 추출하기

자 그러면, 이제 원하는 로그파일을 얻었기 때문에, 방대한 로그 중 우리가 원하는 부분을 추출할 수 있는 팁들을 알아볼까요?

dig

digping 같은 명령어는 해당 도메인이 정상인지 알아보는 유효한 명령어입니다.

dig [도메인] [옵션]
  • dig 명령어를 사용하면 위처럼 도메인에 대한 정보를 반환받습니다.
  • status : NOERROR 는 DNS 조회가 성공했음을 나타냅니다.
  • www.naver.com 에 대한 dig 응답으로 총 3개의 답변이 있는데,
  • www.naver.,comwww.naver.com.nheos.com 으로 별칭이 등록되어 있음을 나타냅니다.
  • CNAME (Canonicial) 은 일종의 Alias 로, 도메인의 별칭을 의미합니다.
  • www.naver.com.nheos.com 은 223.130.200.104 , 223.130.195.95 인 IP 주소를 가리키고 있습니다.
  • Query time 은 DNS 조회에 걸린 시간을 나타냅니다.

Marker

Marker 기능입니다. 우리는 아까 위에서 찾고자 하는 로그 파일을 모두 얻었습니다. 그러나 이 로그 파일을 일일이 찾기가 힘듭니다. 특정 시간대를, 아님 특정 키워드를 기준으로 로그파일을 추출할 수 있다면 얼마나 편할까요?

vi 에디터 기능 중 marker 기능을 사용하면 그 부분이 가능합니다.

먼저 시작점에 대해 커서를 클릭하고 m a 를 각각 한번씩 누릅니다.

그리고 종료지점에 대해 커서를 클릭하고 m b 를 각각 한번씩 누릅니다.

마커가 설정되었으면 확인을 위해 `a` , b 를 눌러봐서 해당 마커위치로 커서가 이동하는지 확인해봅니다.

마커가 정상적으로 설정되었다면 :'a,'b w /tmp/test.txt 명령어를 통해 마커의 구간단위로 파일을 추출해볼 수 있습니다.

Shell Script

다음으로는 shell script 를 통해서 특정 키워드가 포함된 로그의 갯수를 세거나, 아님 필요한 로그들을 추출할 수 있는 로직을 만들어볼까 합니다.

저같은 경우, 애플리케이션 로그 부분의 장애로, logstash 를 통한 통계 수집에 영향이 있던 사례였는데요! 애플리케이션에 로그 자체가 적재되지 않았었지만, 도커 로그에 남아있는 로그를 통해 특정 시간 동안 이벤트가 얼마나 발생했는지 알 수 있었습니다.

Log-Count.sh

#!/bin/bash                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
for ((i=0; i<20; i++))
do
if (( i < 10 )); then
index="0$i"
else
index="$i"
fi

JOIN=`cat aaa.txt | grep "2023-05-31T02:$index" | grep "join_id :" | wc -l`
LEAVE=`cat aaa.txt | grep "2023-05-31T02:$index" | grep "Leave" | wc -l`
CHAT=`cat aaa.txt | grep "2023-05-31T02:$index" | grep "Message :" | wc -l`
LIKE=`cat aaa.txt | grep "2023-05-31T02:$index" | grep "like :" | wc -l`

echo "11:$index JOIN=$JOIN LEAVE=$LEAVE CHAT=$CHAT LIKE=$LIKE"
done

위에서 docker log 명령어나 마커를 통해 특정 범위의 로그파일을 추출할 수 있었습니다.

이 특정 범위 안에서 제가 보고자하는 내용의 로그들을 따로 추출할 수 있는 스크립트 명령어가 필요했습니다.

특정 파일에 대해 키워드를 인자값으로 받고 해당 문자열을 포함하고 있는 로그들만 따로 파일에 기록하여 로그를 Debugging 한 예시입니다.

Log-Grep.sh

#!/bin/bash

str=$1
targetFile=$2
resultFile=$3

while IFS= read -r line; do
grep_result=$(grep "$str")
echo "$grep_result" >> "$result_file"
done < "$targetFile"
  • 명령행 인수로 문자열(str), 대상 파일(targetFile), 결과 파일(resultFile)을 입력받습니다.
  • while 루프를 시작합니다. 이 루프는 대상 파일(targetFile)을 한 줄씩 읽어옵니다.
  • 각 줄에 대해 grep 명령어를 사용하여 문자열(str)을 검색합니다. grep_result 변수에 grep 결과가 저장됩니다.
  • grep 결과를 결과 파일(resultFile)에 추가합니다. echo “$grep_result” >> “$resultFile” 명령을 사용합니다.

--

--