Data Engineering/ETC

Bash shell 을 활용한 Tomcat Access Log 분석

star7357 2020. 11. 25. 22:44

회사 내부적으로 서비스되던 시스템 종료에 앞서, 해당 시스템의 실 접속자 수 파악을 위해 Shell 코드 작성을 통해 Tomcat Access Log 를 분석할 일이 있어, 아래와 같이 분석에 활용한 코드 및 간략한 설명을 기술하였습니다.

 

 

1. Tomcat Access Logs

- Tomcat 서버는 기본적으로 server.xml 내 "org.apache.catalina.valves.AccessLogValve" 설정을 통해 Access Log 를 남기는 기능을 제공합니다. Access Log 파일의 prefix/suffix, Log Pattern(Date, userID, RemoteIP, ...) 등을 지정할 수 있습니다.

- 위와 Access Log 를 설정한 경우, 아래 경로 및 파일명으로 access log 가 저장됨을 확인할 수 있었습니다.

- log 파일 내부는 아래와 같이 구성되어 있으며, 이중 접속 IP, 접속 시간 및 접속 Page URL 을 활용해 일별 실 접속자수 및 페이지별 접속자 수를 알아내는 코드를 작성하였습니다.

 

2. Shell Script 작성을 통한 간단한 ETL 작업 진행

- 위와 같이 생성된 Access log 에 대하여, 단계적으로 아래와 같은 절차를 거쳐 분석을 진행하였습니다.

(0) 파일 입출력을 위한 변수 선언부

#!/bin/bash
log_files='/home/tomadm/tomcat8/logs/localhost_access_log*'
working_dir='/home/tomadm/web_activ_user_agg'
prefix='access_log_stage_'
rslt_dir="${working_dir}/results"
stage_cnt=1

mkdir -p ${rslt_dir}

(1) 원하는 Field 추출

- 전체 Access Log 중, 접속 IP, 접속 시간, 접속 Page 만 추출하기 위한 코드입니다.

- 날짜 형식을 yyyy-mmm-dd 에서 yyyymmdd로 맞춰주기 위해 아래 과정을 진행하였습니다.

awk -F\  'BEGIN {
    split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", month, " ")
    for (i=1; i<=12; i++) mdigit[month[i]]=i
  }
  {
    date=substr($4,2,11)
    m=substr(date,4,3)
    newDate=sprintf("%04d%02d%02d",substr(date,8,20),mdigit[m],substr(date,1,2))
    split($11,menuID,"=")
    print newDate,$1,$11,m
}' OFS="," ${log_files} > "${working_dir}/${prefix}01.txt"

 

(2) Cleansing

- grep -v 옵션 지정을 통해 원하지 않는 패턴을 포함하는 행을 버리고, grep -w 옵션 지정을 통해 원하는 패턴을 포함하는 행만 추출할 수 있습니다.

- 정규표현식을 활용해 접속 IP 가 남아있으며, curMenuId 를 통해 Page ID 가 지정된 행만 추출하였습니다.

- 서비스 관리가 아닌 서비스 활용을 위해 해당 서비스에 접속한 IP 를 골라내기 위해, 특정 C Class 대역의 IP 를 포함한 행을 제외하고, redirect 된 log 는 제외하였습니다.

cat "${working_dir}/${prefix}01.txt" |
    grep -w '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' |
    grep -w 'curMenuId' | grep -v "redirect"|
    grep -v "<C Class IP 대역1>" | uniq > "${working_dir}/${prefix}02.txt"

(3) Page ID 추출

- 접속 URL 중 PageId 만 남기고 나머지 부분은 제거하였습니다.

awk -F, '{
  split($3,menuId,"=")
  print $1,$2,substr(menuId[2],1,6)
}' OFS="," "${working_dir}/${prefix}02.txt" | sed 's/.$//' | uniq > "${working_dir}/${prefix}03.txt"

 

3. Shell Script 작성을 통한 간단한 EDA 작업 진행

- dictionary 자료형을 활용하여 날짜/접속자 별, 날짜/PageID 별, 날짜별 접속자수 집계를 진행하였습니다.

awk -F, '{dict[$1","$2]++} END {for (key in dict) print key","dict[key]}' "${working_dir}/${prefix}03.txt" | sort > "${rslt_dir}/agg_by_date_n_user.csv"

awk -F, '{dict[$1","$3]++} END {for (key in dict) print key","dict[key]}' "${working_dir}/${prefix}03.txt" | sort > "${rslt_dir}/agg_by_date_n_page.csv"

awk -F, '{dict[$1]++} END {for (key in dict) print key,","dict[key]}' "${rslt_dir}/agg_by_date_n_user.csv" | sort > "${rslt_dir}/agg_activ_user_per_date.csv"