[Sprint] 로그 파이프라인

💡 Bare Minimum Requirements

1. 파서(parser) 작성

#!/usr/bin/env node

const dayjs = require('dayjs')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)

process.stdin.on("data", data => {
  let raw = data.toString()
	//박찬규 정규 표현식
  let regex = /^(S+) S+ S+ [([w:/]+s[+-]d{4})] "(S+) S+s*S*" (d{3}) (d+) "([^"]*)" "([^"]*)"/
  //오태경 정규 표현식
  let regex = /^([d.]+) .+ [(.+)] "(w+) (.+) .+" (d+) (d+) "([^"]+)" "([^"]+)"/

  let source_ip = regex.exec(raw)[1]
  let method = regex.exec(3)
  let status_code = regex.exec(5)
  let path = regex.exec(4)
  let timestamp = regex.exec(2)

  let accessTime = dayjs(timestamp, 'DD/MMM/YYYY:hh:mm:ss +ZZ').toISOString()

  let jsonString = `
{
  "source_ip": "${source_ip}",
  "method": "${method}",
  "status_code": ${status_code},
  "path": "${path}",
  "timestamp": "${accessTime}"
}`

  process.stdout.write(jsonString)
})

2. 데이터베이스 연결 테스트

.env 파일 생성

HOSTNAME=ruby.db.elephantsql.com
USERNAME=ztwarhqq
PASSWORD=iNdkZVP1ODKWDDr5_tvC39JmMmKrBqqj
DATABASE=ztwarhqq

SQL Test

Trouble Shooting .env 설정시 OS 환경 변수와 KEY 중복이 되지 않는지 확인 필수

3. 수집기(collector) 작성

#!/usr/bin/env node

const dotenv = require('dotenv')
const { Client } = require('pg')
dotenv.config()

const { HOSTNAME, USERNAME, PASSWORD, DATABASE } = process.env
const client = new Client({
  host: HOSTNAME,
  user: USERNAME,
  password: PASSWORD,
  database: DATABASE
})

client.connect().then(() => {

  process.stdin.on("data", async data => {
    let raw = data.toString()
    let json = JSON.parse(raw)

    let queryString = `
      INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)
      VALUES (
        '${json.source_ip}',
        '${json.method}',
        '${json.status_code}',
        '${json.path}',
        '${json.timestamp}'
      );
    `

    console.log(queryString)
    try {
      await client.query(queryString)
    }
    catch(e) {
      console.log(e)
    }
  })

}).catch(err => console.log('연결 오류', err.stack))


// Ctrl+C가 입력되면, 데이터베이스를 닫습니다
process.on('SIGINT', async (sig) => {
  console.log('n데이터베이스 연결 닫는 중...')
  await client.end()
  console.log('데이터베이스 연결 종료')
  process.exit(1)
})

4. 데이터 지우기

데이터 삭제 쿼리 작성

SQL Test

5. 파이프라인 완성

ETL 파이프라인

  1. 먼저 nginx가 실행중이어야 합니다.
  1. access.log 파일을 관찰합니다. tail -f 명령어를 사용합니다.
  1. 웹 서버에 다양한 접속 기록을 생성합니다. Postman이든 curl이든 웹 브라우저든 상관없습니다.
  1. 접속 시, access.log 파일에 새로운 로그가 출력되는 지 확인합니다.
  1. 4번에 성공했다면, tail -f access.log 의 표준 출력(stdout)이 파서의 표준 입력(stdin)이 되도록 파이프(|)를 이용해 연결합니다.

파이프라인 명령어

$ tail -0f /var/log/nginx/access.log | ./parser.js | ./collector.js

적재 결과 확인

$ ./sql-runner.js < sql/3_display_table_data.sql

Leave a Comment