파이썬 로깅과 에러 알림: 봇이 죽지 않게 지키기
지난 편에서 스케줄러로 봇을 자동으로 돌리기 시작했잖아요. 매일 아침 9시에 알아서 뉴스를 긁어오고 메일을 보내고. 처음엔 진짜 신기하고 뿌듯해요. 내가 안 켜도 알아서 돌아가니까요.
그런데 며칠 지나고 문득 이런 생각이 드는 거예요.
"어? 오늘 메일 안 왔네?"
확인해보니 봇이 죽어있어요. 그것도 사흘 전부터. 안 보는 사이에 조용히 멈춰있었던 거죠. 언제 죽었는지, 왜 죽었는지, 아무것도 남아있지 않아요. 화면엔 그냥 커서만 깜빡이고 있고요.
이게 자동화 봇의 가장 무서운 점이에요. 내가 안 보고 있으니까 죽어도 모른다는 것. 오늘은 이 "밤중에 조용히 죽는" 문제를 두 가지로 막아볼게요. 하나는 로깅(무슨 일이 있었는지 기록 남기기), 또 하나는 에러 알림(죽으면 바로 연락 오게 하기)이에요.
print 대신 파이썬 로깅(python logging)으로 기록 남기기
여기서 아마 이런 생각 하실 거예요. "그냥 print로 상황 찍어두면 되는 거 아니에요?"
저도 처음엔 그렇게 생각했거든요. 근데 결정적인 문제가 있어요.
print는 터미널 창을 닫으면 그냥 증발해요.
print는 화면에 글자를 잠깐 띄웠다 사라지는 거예요. 스케줄러로 백그라운드에서 봇이 도는 상황을 떠올려 보세요. 나는 화면을 안 보고 있잖아요. 애초에 화면이 열려있지도 않고요. 그러니 print로 아무리 "10건 처리 완료!"를 찍어봤자 아무 데도 안 남아요. 나중에 "어젯밤에 무슨 일이 있었지?" 하고 찾아봐도 흔적이 없는 거죠.
logging은 여기에 세 가지가 붙은 버전이에요. (1) 파일에 저장되고, (2) 언제 일어났는지 시각이 찍히고, (3) 얼마나 중요한지 레벨까지 같이 남아요.
비유하자면 print는 창밖에 대고 소리치는 거예요. 그 순간 지나가면 끝. 반면에 로깅은 비행기 블랙박스 같은 거예요. 평소엔 아무도 안 봐요. 근데 사고가 나면 "언제, 무슨 일이, 어떤 순서로" 있었는지 블랙박스에 다 적혀있으니까 원인을 찾을 수 있잖아요. 봇 로그도 딱 그 역할이에요.
일단 제일 간단한 형태부터 볼게요.
import logging
logging.basicConfig(level=logging.INFO) # 기본 설정 (맨 위에서 딱 한 번만!)
logging.info("봇을 시작합니다") # print("봇을 시작합니다") 대신 이렇게
logging.info("데이터 10건을 처리했어요")
# 실행 결과:
INFO:root:봇을 시작합니다
INFO:root:데이터 10건을 처리했어요
print를 쓰던 자리를 logging.info로 바꾼 것뿐이에요. 별거 없죠. 이게 로깅의 첫걸음이에요.
로그 레벨과 파일로 저장하기
logging.info 말고도 상황에 맞게 골라 쓰는 함수들이 있어요. 이걸 로그 레벨이라고 해요. 총 5단계인데, 병원 응급실에서 환자를 분류하는 거랑 비슷해요. 가벼운 감기 환자랑 당장 수술이 급한 환자를 똑같이 대하진 않잖아요.
DEBUG: 개발할 때만 보는 세세한 정보 (평소엔 안 봐요)INFO: 평상시 정상 흐름 ("봇 시작", "12건 처리 완료")WARNING: 문제는 아닌데 좀 이상함 ("검색 결과가 0건이네?")ERROR: 실제로 실패함 ("메일 발송 실패")CRITICAL: 프로그램이 못 돌 정도로 치명적
처음엔 이 다섯 개 다 외우려고 하지 마세요. 정상 흐름은 INFO, 실패는 ERROR. 이 두 개만 확실히 잡아도 충분해요. 나머지는 쓰다 보면 감이 와요.
이제 진짜 중요한 부분이에요. 파일로 저장하기.
import logging
logging.basicConfig(
filename="bot.log", # 이 파일에 기록이 쌓여요
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",# 시각 [레벨] 메시지
encoding="utf-8" # 한글 안 깨지게 (중요!)
)
logging.info("봇을 시작합니다")
이걸 실행하면 화면엔 아무것도 안 떠요. 대신 bot.log라는 파일이 생기고, 그 안에 이렇게 쌓여요.
# bot.log 내용:
2025-11-20 09:00:01,123 [INFO] 봇을 시작합니다
%(asctime)s는 시각, %(levelname)s는 레벨(INFO 같은 거), %(message)s는 내가 쓴 메시지예요. 이 세 개만 알면 돼요. 언제, 얼마나 중요한 일이, 무슨 내용으로 있었는지가 한 줄에 다 담기는 거죠.
그리고 encoding="utf-8" 이거 꼭 넣으세요. 안 넣으면 윈도우에서 한글 로그가 ì\x95… 이런 식으로 다 깨져요. 저도 이거 몰라서 로그 열었다가 외계어 보고 당황했던 적 있거든요.
에러 알림 자동화: 봇이 죽으면 슬랙으로 통보
로그는 파일에 "남겨두는" 거예요. 근데 여기 함정이 있어요. 내가 파일을 열어봐야 안다는 거죠.
봇이 죽었을 땐 파일을 뒤져볼 게 아니라 바로 알아야 하잖아요. 로그(블랙박스)가 사후에 원인을 찾는 도구라면, 지금 필요한 건 화재경보기예요. 불이 나는 즉시 스스로 울려서 나를 부르는 거요.
먼저 try/except로 에러를 잡고, 상세 내역까지 로그에 남기는 법부터 볼게요.
import logging, traceback
try:
result = 10 / 0 # 일부러 에러 내보기 (0으로 나누기)
except Exception:
logging.error("계산 중 에러 발생")
logging.error(traceback.format_exc()) # 어디서 왜 났는지 상세히 기록
traceback.format_exc()가 핵심이에요. 이게 에러가 어느 줄에서 왜 났는지를 문자열로 쫙 뽑아줘요. 그냥 "에러남"만 남기면 나중에 "그래서 어디서 났는데?"를 알 방법이 없거든요. 상세 내역까지 같이 남겨야 원인을 찾아요.
이제 여기에 19에서 만든 슬랙 알림 함수를 붙여볼게요. 에러가 나면 파일에 남기는 동시에 슬랙으로 "삐용" 하고 즉시 날아오게요.
import requests, logging, traceback
def notify_slack(text):
webhook_url = "https://hooks.slack.com/services/..." # 19에서 발급받은 URL
requests.post(webhook_url, json={"text": text})
try:
do_bot_work() # 봇의 실제 작업
except Exception:
err = traceback.format_exc()
logging.error(err) # 파일에도 남기고
notify_slack(f"봇이 멈췄어요!\n{err}") # 슬랙으로도 즉시 알림
이러면 봇이 죽는 순간 내 폰에 슬랙 알림이 떠요. 파일에 원인도 남아있고요. (슬랙 말고 13에서 배운 메일 발송으로 바꿔도 똑같이 돼요.)
봇 전체를 감싸는 안전장치
여기까지 오면 마인드가 하나로 정리돼요.
에러가 나도 조용히 죽게 두지 않는다. 무조건 기록하고, 무조건 알린다.
이걸 봇 전체에 적용하는 게 오늘의 결론이에요. 봇이 하는 진짜 작업을 통째로 try/except로 감싸는 거죠. 서커스 안전망 같은 거예요. 곡예사(봇)가 떨어져도(에러 나도) 바닥에 처박히지 않게(프로그램이 통째로 종료되지 않게) 아래에 그물을 쳐두는 거요.
import logging, traceback, requests
logging.basicConfig(
filename="bot.log", level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s", encoding="utf-8"
)
def notify_slack(text):
requests.post("https://hooks.slack.com/services/...", json={"text": text})
def run_bot():
logging.info("봇 작업 시작")
try:
do_bot_work() # 진짜 하고 싶은 일
logging.info("봇 작업 정상 완료")
except Exception:
err = traceback.format_exc()
logging.error("봇 작업 실패\n" + err) # 파일에 남기고
notify_slack(f"봇이 멈췄어요!\n{err}") # 슬랙으로 알리고
run_bot()
이 run_bot() 하나 안에 로깅이랑 에러 알림이 다 들어있어요. 봇이 정상이면 "정상 완료"가 로그에 남고, 실패하면 원인이 파일에 남고 슬랙으로도 날아와요. 그 "밤중에 조용히 죽어있는데 몰랐던" 상황이 이제 사라지는 거죠.
그리고 이걸 지난 편의 스케줄러에 그대로 얹으면 끝이에요.
import schedule, time
# run_bot() 안에 로깅+알림이 이미 다 들어있으니 그대로 등록만
schedule.every().day.at("09:00").do(run_bot)
logging.info("스케줄러 시작")
while True:
schedule.run_pending()
time.sleep(1)
매일 자동으로 돌고, 실패하면 알아서 기록하고 알려줘요. 완성이에요.
참고로 봇을 몇 달씩 돌리면 bot.log 파일이 계속 커져요. 수백 MB까지 불어나기도 하고요. 그럴 땐 RotatingFileHandler라는 게 있어요. 파일이 일정 크기를 넘으면 새 파일로 갈아끼워 주는 도구인데, 지금 당장은 몰라도 돼요. "로그가 너무 커지면 이런 게 있구나" 정도만 기억해 두세요.
처음에 이런 실수 많이 하시더라고요
print만 쓰다가 아무 기록도 없는 경우. 밤새 돌린 봇이 새벽에 죽었는데, print로만 찍어놔서 남은 게 하나도 없어요. 원인 파악이 불가능하죠. 그래서 처음부터 로깅으로 파일에 남기는 게 중요해요.
try/except 없이 돌리다가 봇 전체가 멈추는 경우. 에러가 한 번 나면 프로그램이 통째로 종료돼요. 그럼 다음 날 예약도 다 무산이에요. 작업을 감싸서 "기록하고 알린 뒤 넘어가게" 해야 해요.
basicConfig를 여러 번 부르거나 늦게 부르는 경우. 로그를 이미 한 번 찍은 뒤에 basicConfig를 부르면 설정이 안 먹혀요. 무조건 프로그램 맨 위에서 딱 한 번만 부르세요. "시작하자마자 한 번" 이 규칙만 지키면 돼요.
filename 줘놓고 화면만 보면서 "안 되네?" 하는 경우. filename을 지정하면 로그가 화면이 아니라 파일로 가요. 화면엔 당연히 아무것도 안 떠요. bot.log 파일을 열어봐야 보인답니다.
오늘 직접 해볼 거리
- 지금까지 만든 봇 하나(뉴스 메일이든 AI 요약이든)를 골라서, 안에 있는
print를 전부logging.info로 바꿔보세요. 그리고bot.log파일에 잘 쌓이는지 열어서 확인해 보세요. (힌트: 맨 위에basicConfig부터 넣는 거 잊지 마세요.filename="bot.log",encoding="utf-8"꼭이요.) - 봇 작업을 try/except로 감싼 다음, except 자리 위에 일부러
10 / 0같은 에러를 넣어보세요. 슬랙(또는 메일)으로 알림이 진짜 오는지 테스트하는 거예요. 오면 성공이에요. (힌트:traceback.format_exc()를 알림 메시지에 같이 넣으면 어디서 났는지도 보여요.)
이 두 개까지 붙이고 나면, 이제 봇을 켜두고 마음 편히 딴 일 해도 돼요. 죽으면 알아서 연락 오니까요.
지금까지 다룬 게 대부분 텍스트랑 데이터였잖아요. 근데 우리가 다루는 파일 중엔 이미지도 정말 많아요. 사진 수십 장을 한 번에 크기 줄이고 워터마크 넣는 일, 손으로 하면 진짜 지겹거든요. 다음 편에서는 파이썬으로 그 귀찮은 이미지 작업을 한 방에 해치우는 걸 해볼 거예요. 봇을 안전하게 돌리는 기초는 잡았으니, 잠깐 쉬어가는 느낌으로요. (참고로 컴퓨터를 아예 안 켜도 봇이 24시간 도는 건 조금 뒤 클라우드에 올리는 편에서 다뤄요. 오늘 배운 로깅이 그때 진가를 발휘한답니다.)
제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀
'Application > Python' 카테고리의 다른 글
| [Python] 26. 파이썬 자동화 봇 24시간 돌리기 (무료 클라우드 호스팅) (0) | 2026.08.18 |
|---|---|
| [Python] 25. 파이썬 Pillow로 이미지 일괄 처리하기 (리사이즈와 워터마크) (0) | 2026.08.14 |
| [Python] 23. 파이썬 스케줄링: schedule 모듈로 정기 실행하기 (0) | 2026.08.10 |
| [Python] 22. 파이썬으로 AI 문서 요약과 번역 봇 만들기 - 긴 문서도 통째로 (0) | 2026.08.07 |
| [Python] 21. 파이썬으로 ChatGPT API 호출하기 - AI에게 텍스트 처리 자동으로 시키기 (0) | 2026.08.04 |