예약 포털 (Vue3 + Firebase) - 서비스 오픈까지

42. Vue3 + Firebase 프로젝트 '우리 동네' - 시스템 운영 로그의 중요성

그랜파 개발자 2025. 7. 1. 20:22

시스템 운영 로그의 중요성

 

웹 서비스에 있어서 시스템 로그(system log)는 단순한 기록이 아니라,

서비스의 건강 상태를 보여주는 청진기이자, 문제 해결을 위한 블랙박스입니다. 

 

시스템 운영에서 로그는 정말 핵심 자산으로
운영 안정성과 문제 해결, 서비스 개선을 위한 거의 모든 활동에 필수적이라 할 수 있죠.

 

https://my-project-bd617.web.app/

 

우리 동네 - Vue + Firebase 사이드 프로젝트

 

my-project-bd617.web.app

https://github.com/inetsos/downtown

 

GitHub - inetsos/downtown: 동네 포털 - Vue 3 + Firebase

동네 포털 - Vue 3 + Firebase. Contribute to inetsos/downtown development by creating an account on GitHub.

github.com

시스템 운영에서 로그가 중요한 이유

1️⃣ 문제 원인 분석과 신속 대응

  • 시스템 장애, 오류, 성능 저하가 발생했을 때
  • 언제, 어디서, 어떤 상황에서 문제가 발생했는지 추적 가능
  • 재현이 어려운 버그도 로그로 상세히 분석 가능
  • 빠른 대응과 복구에 결정적 도움

2️⃣ 보안 감사와 이상 탐지

  • 비정상 로그인 시도, 권한 변경, 데이터 접근 기록 등 감시 가능
  • 해킹 시도나 내부자 부정행위 탐지
  • 보안 사고 발생 시 사고 원인 규명과 증거 확보

3️⃣ 서비스 품질 및 사용자 경험 개선

  • 사용자가 어떤 기능을 자주/드물게 사용하는지 분석
  • 에러 발생 빈도와 유형 파악 → UX 개선 반영
  • 성능 지표 수집 → 병목 구간 발견 및 최적화

4️⃣ 규정 준수 및 법적 대응

  • 금융, 의료 등 규제가 엄격한 산업에서는 로그 기록이 법적 의무
  • 감사, 컴플라이언스, 소송 대응 자료로 활용

5️⃣ 운영 자동화와 알림

  • 장애 발생 시 자동 알림(메일, 슬랙, SMS) 전송
  • 운영자 개입 없이 조기 대응 가능

요약

중요 포인트 설명
신속 문제 해결 장애 발생 즉시 로그로 원인 파악
보안 및 감사 공격 탐지 및 추적, 증거 확보
서비스 개선 사용자 행동 분석, UX/성능 최적화
규제 준수 법적 요구사항 대응
자동화 지원 알림 및 모니터링 자동화
 

결론

로그가 없거나 부실하면,
문제 발생 시 원인 불명, 대응 지연, 보안 사고 확대, 서비스 품질 저하로 이어져
결국 기업 신뢰도와 매출에 악영향을 미칩니다.


시스템 운영 로그 설계 방법

운영 로그 설계는 시스템 안정성과 문제 해결의 근간이 됩니다.

잘 설계된 로그는 장애 원인 파악과 예방, 성능 개선, 보안 감사 등 모든 운영 업무의 기반이 되죠.

아래는 운영 로그 설계 방법을 단계별로 정리한 내용입니다.

1️⃣ 로그 설계 기본 원칙

  • 목적 기반 설계
    → 무작정 로그를 남기지 말고, 왜, 누가, 언제, 무엇을 알아야 하는지 명확히 한다.
  • 일관성 유지
    → 로그 형식, 필드명, 레벨 체계를 팀 전체가 통일해서 사용.
  • 구조화된 로그
    → JSON 등 파싱 가능한 형태로 저장해 쉽게 검색/분석 가능하게 설계.
  • 중요 정보 포함
    → 사용자 ID, 요청 ID, 시간, 위치, 에러 코드 등 문제 분석에 필수적인 정보를 꼭 포함.
  • 민감정보 배제
    → 개인정보, 비밀번호, 카드번호 등은 절대 로그에 포함하지 않도록 주의.

2️⃣ 로그 레벨 설계

레벨 목적 예시
DEBUG 개발 중 상세 추적용 함수 진입/종료, 변수 상태
INFO 정상 동작 상태 기록 사용자 로그인, 페이지 이동
WARN 주의 필요 상황 성능 저하, 재시도 발생
ERROR 오류 발생, 장애 전 단계 API 호출 실패, DB 오류
FATAL 치명적 장애 서버 다운, 데이터 손상
 

3️⃣ 로그 필드 설계 예시

{
  "timestamp": "2025-07-01T10:00:00Z",
  "level": "ERROR",
  "service": "payment-service",
  "userId": "user_123",
  "requestId": "req_abc123",
  "message": "결제 API 호출 실패",
  "errorCode": "PAYMENT_TIMEOUT",
  "stackTrace": "...",
  "clientIp": "203.0.113.5",
  "userAgent": "Mozilla/5.0 ..."
}
 

4️⃣ 수집 및 저장 전략

  • 중앙 집중형 저장소 활용 (예: ELK, Cloud Logging, BigQuery)
  • 자동 수집/분석 가능한 구조 (파싱 용이, 태깅 필드 포함)
  • 로그 보존 정책 수립 (예: 중요 로그는 1년, 일반 로그는 30일 보관)
  • 비용 관리를 위한 적절한 필터링과 샘플링 적용

5️⃣ 운영 시 알림과 대시보드

  • 알림 체계 구축
    → ERROR 이상 로그 실시간 Slack, 이메일, PagerDuty 알림
  • 대시보드 구성
    → 장애 추세, 에러 유형 통계, 성능 지표 시각화
  • 주기적 리뷰
    → 로그 분석을 통한 문제점 개선 및 신규 이벤트 정의

6️⃣ 보안 및 개인정보 고려사항

  • 민감 데이터 로그 제외
  • 로그 접근 권한 관리 엄격히 적용
  • 암호화 및 안전한 전송 채널 사용

마무리

운영 로그 설계는 단순히 “많이 남기는 것”이 아니라,
‘필요한 정보를 명확하고 일관되게 남겨서 운영과 개발이 쉽게 활용할 수 있게 하는 것’이 핵심입니다.


로그는 어디에 어떻게 심으면 좋을까?

1. 로그 심을 위치 (Where)

구분 구체 위치 및 예시 이유 및 목적
사용자 행동 - 주요 버튼 클릭, 페이지 진입, 폼 제출 사용자 행동 분석, UX 개선
오류 처리 지점 - try/catch 예외 발생 구간
- Vue 전역 에러 핸들러
문제 원인 신속 파악 및 대응
API 호출부 - 요청 시작, 응답 실패, 응답 시간 지연 등 서버-클라이언트 통신 상태 확인
인증/권한 검증 - 로그인, 로그아웃, 권한 거부 에러 보안 감사, 사용자 상태 추적
서버/클라우드 함수 - 함수 진입, 처리 결과, 오류 발생 백엔드 문제 감지, 상태 모니터링
성능 측정 포인트 - 페이지 로딩 완료, 주요 기능 수행 시간 측정 성능 최적화 및 병목 구간 발견
관리자·운영 기능 - 설정 변경, 데이터 삭제, 관리자 행위 감시 및 감사 기록

 

2. 로그 심는 방법 (How)

자동 로그 삽입

  • 페이지 진입, 라우터 이벤트: Vue Router의 afterEach 훅에 삽입해 모든 페이지 방문 로그 자동 생성
  • 전역 에러 처리: Vue 전역 에러 핸들러(app.config.errorHandler), window.onerror에 삽입
  • 네트워크 요청 감시: Axios 인터셉터에 로그 삽입해 요청/응답 자동 기록

수동 로그 삽입

  • 중요 버튼 클릭, 핵심 기능 호출 시 logEvent('click', ...) 같이 명시적 호출
  • 예외처리 구간 catch 내에서 에러 로그 기록
  • 관리자 기능, 보안 관련 이벤트 별도 로그 남기기

3. 로그 기록 시 고려 사항

  • 필수 정보 포함: level, message, userId, timestamp, context(예: 함수명, 경로)
  • 민감 정보는 제외: 비밀번호, 신용카드 번호 등 절대 기록하지 말 것
  • 일관된 포맷 유지: JSON 형태로 구조화해 나중에 분석 용이하도록
  • 로그 레벨 구분: INFO, WARN, ERROR, DEBUG 등으로 구분해 필터링 가능하게

4. 예시

// Vue Router 자동 페이지 방문 로그
router.afterEach((to, from) => {
  logEvent('info', '페이지 진입', { path: to.fullPath, userId: authStore.userId })
})

// 버튼 클릭 수동 로그
function onClickOrder() {
  logEvent('click', '주문 버튼 클릭', { userId: authStore.userId, productId: 123 })
}

// API 요청 예외 처리 내 에러 로그
try {
  await api.submitOrder(data)
} catch (e) {
  logEvent('error', '주문 API 실패', { userId: authStore.userId, error: e.message })
}
 

5. 결론

  • 모든 동작을 다 찍기보다는, 핵심 이벤트와 오류 중심으로 심는다
  • 자동화 가능한 부분은 최대한 자동화해서 빠뜨리지 않게 한다
  • 명확한 목적과 일관된 포맷으로 기록해서, 나중에 분석·대응에 활용한다

Vue + Firebase 기반 자동 로그 삽입 템플릿

 

아래는 Vue 3 + Firebase 환경에서 자동으로 로그를 수집하는 템플릿 예시입니다.

  • 페이지 이동 시 자동 로그
  • 전역 에러 자동 수집
  • 수동 클릭 로그 함수 제공
  • Firebase Cloud Functions로 로그 저장

1. 공통 로그 전송 함수 (src/utils/logger.js)

export async function logEvent(level, message, data = {}) {
  try {
    await fetch('https://us-central1-<PROJECT_ID>.cloudfunctions.net/logEvent', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        level,
        message,
        data,
        userAgent: navigator.userAgent,
        timestamp: new Date().toISOString(),
      }),
    })
  } catch (e) {
    console.warn('로그 전송 실패:', e)
  }
}
 

2. 로그 자동 삽입 및 수동 호출 훅 (src/composables/useLogger.js)

import { onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { logEvent } from '@/utils/logger'
import { useAuthStore } from '@/stores/authStore'

export function useLogger() {
  const route = useRoute()
  const authStore = useAuthStore()

  // 페이지 진입 시 자동 로그
  onMounted(() => {
    logEvent('info', '페이지 진입', {
      path: route.fullPath,
      userId: authStore.userId || 'guest',
    })
  })

  // 클릭 로그 함수
  function logClick(action, extra = {}) {
    logEvent('click', action, {
      path: route.fullPath,
      userId: authStore.userId || 'guest',
      ...extra,
    })
  }

  // 에러 로그 함수
  function logError(message, error = {}) {
    logEvent('error', message, {
      path: route.fullPath,
      userId: authStore.userId || 'guest',
      ...error,
    })
  }

  return { logClick, logError }
}
 

3. 전역 에러 핸들러 설정 (src/main.js)

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { logEvent } from '@/utils/logger'

const app = createApp(App)

app.config.errorHandler = (err, vm, info) => {
  logEvent('error', 'Vue 전역 에러', {
    message: err.message,
    stack: err.stack,
    component: info,
  })
}

window.onerror = (msg, src, line, col, err) => {
  logEvent('error', 'JS 전역 에러', {
    message: msg,
    source: src,
    line,
    col,
    stack: err?.stack,
  })
}

app.use(router)
app.mount('#app')
 

4. Cloud Functions 로그 저장 예시 (Node.js)

const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()

const db = admin.firestore()

exports.logEvent = functions.https.onRequest(async (req, res) => {
  try {
    const log = req.body
    log.createdAt = admin.firestore.FieldValue.serverTimestamp()

    await db.collection('logs').add(log)

    res.status(200).send('Logged')
  } catch (e) {
    console.error('로그 저장 실패:', e)
    res.status(500).send('Internal Server Error')
  }
})

 

logEvent() 함수는 Firebase Cloud Functions에 직접 구현해야 합니다.

왜 Cloud Functions를 구현해야 하나요?

  • 웹 앱에서 직접 Firestore에 쓰면 클라이언트 권한 문제가 생기거나,
  • 무분별한 쓰기 방지,
  • 데이터 변환,
  • 에러 알림 연동 (예: Slack 알림) 등 부가 처리를 하기 위해
  • 서버 측에서 로그 수신/처리용 API 역할을 하는 함수가 필요합니다.

5. 사용 예 (src/components/MyButton.vue)

<script setup>
import { useLogger } from '@/composables/useLogger'
const { logClick } = useLogger()

function onClick() {
  logClick('주문 버튼 클릭', { productId: 123 })
}
</script>

<template>
  <button @click="onClick">주문하기</button>
</template>
 

Vue 프론트엔드에서 로그 데이터를 Excel로 export하는 방법

✅ 1. 라이브러리 설치

npm install exceljs file-saver

 

✅ 2. 유틸 함수 작성 (exportToExcel.js 등)

// utils/exportToExcel.js
import ExcelJS from 'exceljs';
import { saveAs } from 'file-saver';

export async function exportLogsToExcel(logs, filename = 'logs.xlsx') {
  const workbook = new ExcelJS.Workbook();
  const worksheet = workbook.addWorksheet('Logs');

  // 📌 헤더 설정
  const columns = Object.keys(logs[0]).map(key => ({
    header: key.charAt(0).toUpperCase() + key.slice(1),
    key: key,
    width: 20,
  }));
  worksheet.columns = columns;

  // 📌 데이터 행 추가
  logs.forEach(log => {
    worksheet.addRow(log);
  });

  // 📌 스타일 (선택사항)
  worksheet.getRow(1).font = { bold: true };

  // 📌 파일 생성 및 저장
  const buffer = await workbook.xlsx.writeBuffer();
  const blob = new Blob([buffer], {
    type:
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  });

  saveAs(blob, filename);
}
 

✅ 3. 사용 예시 (Vue 컴포넌트 내부에서)

<script setup>
import { exportLogsToExcel } from '@/utils/exportToExcel'

const logs = [
  { date: '2025-07-01', user: '홍길동', action: '로그인' },
  { date: '2025-07-01', user: '김철수', action: '데이터 삭제' },
]

const downloadExcel = () => {
  exportLogsToExcel(logs, '시스템로그.xlsx')
}
</script>

<template>
  <v-btn color="primary" @click="downloadExcel">📥 Excel 다운로드</v-btn>
</template>
 

🔍 특징

  • exceljs: 스타일, 너비, 셀 병합 등 Excel 파일의 세밀한 제어 가능
  • file-saver: 브라우저에서 Blob 파일을 다운로드하게 해줌