✨Build Up
이번에 회사에서맡은 일을 해결하는 과정에서 Python FastAPI 서버를 구축하게 되었다.
Llama3 모델을 활용하기 위해서 Kotlin + Spring 프로젝트에서는 유연하지 못한 것 같아 모델에 관련된 처리를 Python 서버에서 해결하기로 했고, 완전히 새로운 프로젝트를 만드는 상황이라 Logging과 배포에 관련된 문제를 모두 스스로 해결해야했다.
이번에는 그 과정 중에서도 로깅에 관한 문제를 해결해야한다.
어플리케이션 밑에 찍히는 로그도 필요하지만 프로덕션에서는 Opensearch를 통해서 더 손쉽게 로그를 탐색할 수 있어야 하고 나중에는 DataDog을 활용하여 트래픽 분석도 할 수 있어야 한다.
그 중에서도 이번에는 Python FastAPI에서의 Logging에 대해서 먼저 다루고, LogStash에 대해서 다루어보겠다.
🕊️ FastAPI에서의 Logging
1. Loguru 라이브러리(로깅 라이브러리)
Spring에서 Slf4j을 활용하여 로깅을 했듯이, Python에서도 로깅을 할 때 제공해주는 라이브러리가 있다.
왜 로깅을 하는가?
물론 print()문을 통해서 로깅을 할 수 있지만, thread나 여러므로 성능에 크게는 100배정도까지 영향을 주기 때문에 팀 프로젝트나 회사 프로젝트에서는 print() 문에 의존하는 것은 좋지 않다. 또한 앞서 내가 작성한 글처럼, log가 제공해주는 데이터가 현저히 많다.
Python에서의 로깅
파이썬에서는 공식적으로 logging라이브러리를 제공한다.
https://docs.python.org/ko/3/library/logging.html
그러나 여러므로 내가 편한대로 커스텀해서 사용하려고 하니 복잡하고 프로젝트에 로깅에 많은 시간을 투자할 여유가 없는 상황이기 때문에 loguru라는 로깅 오픈소스를 사용하였다.
https://github.com/Delgan/loguru
from loguru import logger
이 라이브러리는 설정없이 바로 의존성을 주입하면 사용할 수 있으며, handler, formatter, filter를 하나의 함수에서 저의가 가능하다. 또한 로깅 파일을 저장할 수 있는 간편한 method를 제공하며, 색상도 있어서 예쁘다.
그리고 무엇보다 파이썬에서 제공하는 로깅 라이브러리와 다르게 비동기식으로 동작하며, 다중 프로세스에 안전하다.
2. Middleware(미들웨어)
FastAPI Application에는 Middleware를 붙일 수 있다.
Middleware는, 특정 경로 작업에 의해 처리되기 전 모든 요청을 다루며, 반환되기 전 모든 응답을 다루는 함수다.
- 따라서, 이는 애플리케이션으로 들어오는 각 요청을 받아들이고, 해당 요청에 대해 무언가 수행하거나 필요한 코드를 실행할 수 있다.
- 그 다음 요청을 애플리케이션의 나머지 부분으로 전달하여 처리하게 한다.
- 이후 애플리케이션에 의해 생성된 응답을 받는다.
- 응답에 무언가를 수행하거나 필요한 코드를 실행할 수 있다.
- 그리고 응답을 반환한다.
여기서 왜 Middleware에 대해 언급했냐면,
이번에 내가 해야할 일은 하나의 요청을 여러 계층에 걸쳐 동일한 UUID를 로그로 남기기 위해서다. 즉, 각 요청이 처리될 때 요청마다 고유한 UUID를 생성하고, 이를 요청의 생명주기 동안 유지하여 사용하기 하기 위해서다. 이렇게 로깅을 할 경우에는 오류 추적을 효과적으로 할 수 있다.
이때 파이썬에서 일반적으로는 미들웨어를 사용하며, 요청이 들어올 때 미들웨어에서 UUID를 생성하고, 이를 요청의 컨텍스트에 저장한 다음, 요청 처리가 끝날 때까지 이 정보를 유지한다. 이러면 모든 로그에 UUID를 남길 수 있다.
3. Correlation ID(요청의 흐름을 추적하기 위한 키값)
UUID를 왜 굳이 남기려고 하는가?
내가 UUID를 남기려고 하는 이유는, 요청의 흐름을 추적하기 위해서다. uuid, trace_id와 같은 값들은 복잡한 시스템 내에서 여러 서비스나 구성요소를 거치는 요청의 흐름을 추적할 때 사용된다.
각 요청이나 트랜잭션이 시작될 때 생성된 이 고유한 식별자는 요청이 시스템의 여러 부분을 거치면서 일관성 있게 유지되어 로깅, 모니터링, 디버깅에서 매우 중요한 역할을 하게 된다.
- 트랜잭션 추적: 서로 다른 시스템이나 서비스 간의 요청을 연결하여 전체 트랜잭션을 쉽게 추적할 수 있게 한다.
- 디버깅 용이: 오류 발생 시, correlation ID를 통해 관련 로그를 신속하게 검색하고 문제의 원인을 분석할 수 있다.
- 성능 모니터링: 시스템의 성능 이슈를 진단할 때, 특정 요청에 대한 처리 시간과 경로를 추적하는 데 유용하다.
FastAPI 또는 기타 웹 프레임워크에서는 이러한 correlation ID를 요청의 시작에서 생성하고, 요청에 관련된 모든 처리 과정에서 로그에 포함시켜 요청의 생명주기를 효과적으로 관리할 수 있다. 이를 통해 전체 시스템을 통한 요청의 흐름을 보다 명확하게 이해하고 관리할 수 있다.
MiddleWare에서 UUID를 관리한다는 것
전체 웹 요청 및 응답 주기에 걸쳐 각 요청을 고유하게 식별하고 추적하기 위해서 Middleware에서 uuid를 관리하도록 설계했다.
이것은 특히 대규모 및 복잡한 애플리케이션에서의 로깅, 모니터링, 디버깅 및 보안에 유용하다고 한다.
장점
1. 요청 추적 및 로깅
- 투명한 로깅: 각 요청에 대한 UUID를 로그에 포함함으로써, 발생한 문제를 손쉽게 추적하고 원인을 분석할 수 있다. 이는 시스템 내부에서 발생하는 이벤트의 상황을 명확하게 이해하는 데 도움이 된다.
- 디버깅 용이성: 오류가 발생했을 때, 해당 요청의 UUID를 통해 로그 파일에서 관련 정보를 신속하게 찾아낼 수 있다. 이는 문제 해결 시간을 단축시키는 데 큰 도움이 된다.
2. 성능 모니터링
- 효과적인 모니터링: 각 요청의 시작과 종료를 UUID로 매핑함으로써, 시스템의 성능을 측정하고 분석하는 데 필요한 데이터를 제공한다. 이를 통해 어떤 요청이 성능 저하의 원인이 되는지 파악할 수 있다.
3. 보안 강화
- 보안 감사: 요청에 UUID를 연결함으로써, 보안 위협이나 비정상적인 접근을 시도한 요청을 추적하고 분석하는 데 도움이 된다. 각 요청의 경로를 따라갈 수 있으므로, 보안 감사 및 모니터링이 강화된다.
4. 분산 시스템에서의 트랜잭션 관리
- 트랜잭션 일관성 유지: 복잡한 분산 시스템에서 여러 서비스를 거치는 요청을 UUID로 추적함으로써, 전체 트랜잭션에 대한 일관성과 정확성을 보장할 수 있다. 각 서비스가 동일한 요청 ID를 참조하므로, 서비스 간의 연결과 데이터 흐름을 명확하게 할 수 있다.
하지만, 단점으로는, 시스템의 복잡성이 증가하고 처리에 오버헤드가 걸릴 수 있으며, 데이터 스토리지 및 관리관점에서 좋지 않을 수 있다. 또한 시스템의 다른 부분이 UUID 생성 및 관리 메커니즘에 의존하게 된다면 이런 부분들도 일종의 관리포인트가 되어 추가적인 유지보수 작업들이 필요할 수도 있다.
따라서, 이런 기술을 도입할 때는 성능 테스트와 최적화가 필요하고, 적절한 로그 정책을 설정해야하며 시스템 설계를 검토하여야 한다.
'Backend > FastAPI' 카테고리의 다른 글
FastAPI PostgreSQL DB 트랜잭션 동기/비동기 처리 (0) | 2024.05.11 |
---|---|
CGI, WSGI, ASGI 에 대하여 (0) | 2024.05.10 |
Precommit Test (0) | 2024.03.18 |
AID backend project 추가 정리 (1) | 2024.03.18 |
DockerCompose & MongoDB (4) | 2024.03.18 |