2018년 8월 26일 일요일

정규표현식이 최선일까?

로그스태시 필터링 과정에서 grok 필터를, 그러니까 정규표현식을 사용하는 게 최선이냐는 질문을 받았다. 답은 그때 그때 달라요(..)

눈 씻고 봐도 구조 파악이 어려운 비정형 데이터를 정형 데이터로, 일관된 규칙을 갖는 테이블 구조로 바꿀 때는 정규표현식이 최선이다. 그런데 다행히도 컴퓨터에서 발생하는 대부분의 로그는 눈곱만큼이라도 나름의 구조를 가지고 있는 반정형 데이터이다.

grok 필터 작성 사례에 등장했던 로그를 다시 한번 살펴보자. 얼핏 어수선해 보이지만 해당 로그는 뚜렷한 "필드":"구조를 가지고 있다.


데이터 고유성

게다가 각 필드값들은 해당 필드 속성에 적합한 고유성도 확보하고 있다. 남자 필드에는 남자만, 여자 필드에는 여자만 있다는 얘기. 인간 세상에서 남자와 여자는 적당히 섞여야겠지만 데이터 세상에서 그러면 망함.


이정도로 구조화된 로그라면 굳이 정규표현식을, grok 필터를 고집할 필요는 없다. 다음은 dissect 필터를 이용한 event_type, hostname 필드 추출 표현식. 표현식과 로그 구조를 비교해보면 이해하기 그리 어렵지 않다.
dissect { mapping => { "message" => '%{}":"%{event_type}"%{}":"%{}":"%{hostname}"%{}' } }
<12>1 2018-08-14T01:24:40.62Z abc testServer 784 - - ?{"event_type":"Threat_Event","ipv4":"192.168.77.112","hostname":"test-pc","source_uuid":"3b6fsdff-a56f-48d1-96d1-2b65453684b4","occured":"14-Aug-2018 01:23:52","severity":"Warning","threat_type":"po tentially unwanted application","threat_name":"Win32/SlowPCfighter.A"

하지만 가끔은 필드값의 고유성이 불분명할 때도 있다. 엘라스틱 스택 중 Winlogbeat는 윈도우 이벤트 로그 필드 분류를 필터 설정 없이도 알아서 척척 해낸다. 이벤트 로그가 필드 분류하기 딱 좋은 'Key - Value' 구조를 갖추고 있기 때문.


다른 성격이 혼재된 데이터

그런데 'NewProcessName' 필드는 이름과 달리 프로세스명과 함께 경로 정보까지 포함하고 있다. 이때 경로 정보를 제외해서 'NewProcessName' 필드값의 고유성을 확보하고 싶다면? dissect 필터로 가능할까?

dissect 필터는 대상 문자열에서 구분기호를 선택해야 한다. 대상 문자열 'C:\windows\system32\mmc.exe'에서 경로와 파일을 구분해주는 구분기호는 '\'. 다음은 구분기호 '\'를 이용한 dissect 필터 표현식.
dissect { mapping => { "message" => "%{file_path}\%{file}" } }

다음은 필터링 결과. 'NewProcessName' 필드값이 첫번째 '\'를 기준으로 path, file 필드로 분리됐다. 원했던 결과인가?


이런 결과를 피하려면 구분기호를 더 정확하게 정의해야 한다. 다음은 수정된 dissect 필터 표현식.
dissect { mapping => { "message" => "%{file_path}2\%{file}" } }


의도대로 프로세스명만을 추출하는 데 성공했다. 하지만 다른 로그는? 2\를 구분기호로 사용하면 다른 경로에 위치한 프로세스명 추출은 모조리 실패할 수밖에 없다.

일관된 구분기호를 찾을 수 없다

그러나 정규표현식은 이런 문제를 정말 간단하게 해결해준다. 다음은 grok 필터 표현식.
grok { match => { "message" => "(?<file_path>.+\\)(?<file>[^\\]+$)" } }


1950년대에 등장한 정규표현식이 빅데이터, 인공지능이 난무하는 현재까지도 버티는 데는 다 이유가 있다. 강의 중에도 정규표현식 말고 데이터 추출하기 쉬운 방법 없냐는 질문을 종종 받는데, 그런 거 있으면 저 좀 알려주세요(..)

결국 정답은 없는 것 같다. 결론은 그냥 상황에 맞는 걸 쓰자. 개인적으로는 (성능 문제를 겪어본 적이 없어서) 손에 익은 정규표현식을 애용하지만, 성능 문제가 생기면 정규표현식과 다른 필터의 혼용을 망설이지 않을 생각이다.

나가며

써놓고 보니 지 편하다고 정규표현식 칭찬하기 바쁜 오타쿠로 보일까 심히 걱정스럽다(..)


그런데 괜한 말이 아니라, 사실 정규표현식은 별로 중요하지 않다. 진짜 중요한 건 분석하려는 데이터와 친해지는 것.

친해지면 잘 알게 된다. 대상 문자열과 친해지면 자연스럽게 구조와 특성을 잘 알게 되고, 상황에 맞는 다양한 처리법을 고안할 수 있게 된다. 개발자 중엔 성능 떨어진다며 전용 함수나 라이브러리 등을 이용한 처리를 선호하는 분들도 많더라.
  • 정규표현식 3원칙
  1. 검사 대상 문자열에 대한 충분한 이해
  2. 뚜렷한 검사 목적
  3. 정규표현식에 대한 충분한 이해 
이 책이 끝날 때까지 이 3원칙, 특히 대상 문자열에 대한 이해의 중요성을 지겹게 강조하는 나를 만나게 될 것이다. - 데이터 분석이 쉬워지는 정규표현식 (57페이지)

그런데 대상 문자열과 친해지기 위한 탐색적 데이터 분석 도구로 (VIM과) 정규표현식만한 게 또 없다. 오타쿠 맞네 배울 것도 많지 않다. 구글링 잠깐만 해봐도 알 수 있지만, 1페이지 정도면 정리 끝나는 게 정규표현식.

그런데도 어려워하는 이가 많은 이유는 아무래도 자주 쓸 일이 없어서일 것이다. 쓸 일이 없다는 얘기는 회사에서 필요 없는 업무란 뜻이고, 이윤 추구가 최대 목적인 회사에서 필요 없다는 얘기는 돈이 되지 않는, 소비자가 없는 시장이란 뜻인데(..)

그래도 배우고 싶다면 이점만 기억하자. 정규표현식은 언어학(형식/정규언어)과의 연관 때문인지 그 속성이 언어와 비슷하다. 안 쓰면 까먹는다. 반대로 얘기하면 자꾸 써버릇하면 금방 익숙해진다. 다시 같은 결론, 많이 써본 사람이 왕이다.

댓글 없음:

댓글 쓰기

크리에이티브 커먼즈 라이선스