이번에 Project를 진행하면서 특정 기간동안의 특정 도메인 TRAFFIC 정보를 GATHERING 한 후
TRAFFIC CUT-OVER 이후에 CUT-OVER 이전의 TRAFFIC에서 찾을 수 없는 CASE를 추출하는 SHELL을 작성해야 하는 상황이 발생하였다.

결국 특정 기간의 TRAFFIC 정보를 분석해서 MASTER 파일을 작성한 후 CUT-OVER 이후의 로그 파일과 이를 비교해야 하는 SHELL 이었다.

우선 진행해야 하는 건 로그 파일을 뒤져서 URL이 특정 도메인으로 시작하는 데이터를 가져오는 일이 었다.

일단 로그파일에서 특정 도메인 정보를 가져오는 건 비교적 쉬웠다.

egrep --file=<PATTERN_FILE>-i <LOG 파일들> | cut -d^ -f2,5,6

'^'를 구분자로 가지는 <LOG 파일들>에서 <PATTERN_FILE>에 지정된 문자열을 가지는 데이터를 가져와서 2,5,6 필드들을 가져오는 구문이었다. 이때 egrep의 -i 옵션을 사용하여 case insensitive 하게 처리 하도록 했다.

다른 필드 값들에 있는 케이스를 무시했었는데, 데이터를 보다보니 PATTERN에 있는 도메인 정보가 다른 필드에서도 사용되는 case도 있고, 도메인이 TEST 같은 간단한 경우는 URL 내의 다른 정보에서도 나오는 것이 아닌가.

결국 아래와 같이 egrep을 한 데이터를 다시 egrep 하도록 하였다.

egrep --file=<PATTERN_FILE>-i <LOG 파일들> | cut -d^ -f2,5,6 | egrep --file=<PATTERN_FILE> -i

이렇게 하니 로그 데이터를 모을 수 있었는데, 2번째 필드의 경우는 다시 ','로 세부 필드가 또 구분되게 되어 있다.

결국 tr로 모든 ','를 '^'로 변환하여 2번째 필드 안의 세부 필드들도 다음 프로세스에서 사용할 수 있게 하였다.

결국 아래와 같이 LOG 데이터를 1차 가공 파일로 저장하도록 SHELL을 작성하였다.

egrep --file=<PATTERN_FILE>-i <LOG 파일들> | cut -d^ -f2,5,6 | egrep --file=<PATTERN_FILE> -i | tr -s ',' '^' >> ${LOG_DATE}_site_log.txt

이 site_log파일에 있는 내용을 가지고 실제 TRAFFIC URL을 가져오는 코드를 작성해야 하는데, sort 와 uniq를 사용하니 간단히 해결 됐다.

awk '{FS="^"} {print $2"@"$5}' ${LOG_DATE}_site_log.txt | sort | uniq -c > ${LOG_DATE}_traffic.txt

먼제 awk로 2번째와 5번째 필드 문자열을 @를 연결자로 합치고, ( 즉 <2번째 필드>@<5번째 필드> ) 이 값을 가지고 sort와 uniq를 진행하니 ,

발생횟수 <2번째 필드>@<5번쨰 필드> 형태의 데이터를 가지는 TRAFFIC 정보 파일이 작성 되었다.


흠.. 그런데 생각해보니 EMPTY case 정보도 필요 할 듯 하여 3번째 필드가 0인 case의 EMPTY LOG를 EMTPY TRAFFIC 정보 파일에 저장하는 아래 SHELL도 작성하게 되었다.
awk -F'^' 'BEGIN {OFS="^"} {if ($3 == "0" ) print $2"@"$5}' ${LOG_DATE}_site_log.txt | sort | uniq -c > ${LOG_DATE}_empty_traffic.txt


처음에는 위 파일들을 MASTER 파일로 사용하려 했는데, 좀더 진행해 보니 날짜 별로 조금씩 트랙픽이 틀려져서 위 파일을 마스터 파일을 쓸 수가 없었다. 결국 날짜별 site_log 파일을 가지고 MASTER 파일을 만들어 내어야 하는데 나중에 처리할 떄 대/소문자 이슈를 없애기 위해서 전체 날짜별 TRAFFIC 파일들 CONCATE 시킨 후 모든 데이터를 소문자로 바꾸어 위와 동일한 Process를 통해 master 파일을 작성할 수 있었다.

for f in *_site_log.txt
do
        awk '{FS="^"} {print $2"@"$5}' ${f} | sort | uniq >> ${TMP}
        echo "$f file"
done

cat ${TMP} | tr '[:upper:]' '[:lower:]' | sort | uniq > ${마스터파일}

tr '[:upper:]' '[:lower:]' 이부분이 대문자를 소문자로 변환해 주는 파일이다.


이제 마지막으로 다른 로그 파일을 가져와서 마스터 파일에 있지 않은 TRAFFIC 정보를 추출해야 한다.
즉 마스터 파일과 join을 한 후 join 되지 않는 데이터를 가져와야 하는데 이 걸 라인단위로 읽어서 마스터 파일과 비교하는 SHELL을 짜려니 만만하지가 않다.

구글링을 해 보니 딱 나에게 필요한 기능의 SHELL COMMAND가 있다.

comm -23 <로그파일> <마스터파일> > <최종파일>

comm는 두개의 sort된 파일을 가지고 JOIN을 해서 결과를 추출해 주는데

이때 -1, -2, -3 과 같이 옵션을 주면

-1 은 왼쪽 ( <로그파일>) 결과만 있는 부분을 제거 - Right outer join과 유사 )
-2 는 오른쪽 ( <마스터파일> ) 결과만 있는 부분을 제거 - Left outer join과 유사 )
-3 는 양쪽에 모두 결과가 있는 부분을 제거 하게 되어 있다.
따라서 -23을 하게 되면 마스터파일에 결과만 있는 경우와, 양쪽 모두에 있는 부분을 제거 하게 되니, 마스터 파일에 등록되지 않은 Traffic 정보를 가지는 로그 데이터 만을 출력하게 되는 것이다.


처음에는 이런 걸 어떻게 개발하나 했는데, 기존에 다른 사람이 개발한 거랑, 구글링의 힘들 빌렸더니 결국 거의 원하는 결과를 추출해주는 SHELL을 작성할 수 있었다.

이렇게 개발해 놓고 나니, 지금 내가 개발해 놓은 로그 분석툴의 CONCURRENT CHECK 부분을 DB 에서 할필요가 없지 않았나 하는 생각이 든다.

이젠 너무 DB만 쓰지 말고 이렇게 SHELL 로 할 수 있는 부분은 SHELL로 많이 처리 해야 할 듯 싶다.

Posted by headiron
,