Skip to content

Commit

Permalink
feat: Added 29.md, 31.md
Browse files Browse the repository at this point in the history
  • Loading branch information
chavokim committed Sep 12, 2023
1 parent 3319090 commit 59caa34
Show file tree
Hide file tree
Showing 3 changed files with 536 additions and 2 deletions.
221 changes: 221 additions & 0 deletions 29.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# Logging: What’s It For, Anyway?

일반적이지 않은 동작를 logging하고 주기적으로 log를 체크하는 것은 서버의 안정성을 보장하는데에 굉장히 중요하다.

## 29.1 Application Logs vs Other Logs

Django web application에서 발생하는 로그는 application log로 볼 수 있다. Application Log를 제외하고도 server log, database log, network log도 같은 정도로 중요하게 여겨야 한다.

## 29.2 Why Bother With Logging?

예상하지 못했던 오류가 부딪힐 때, 로깅은 무엇이 실제로 일어나는지에 대한 인사이트를 제공한다.

## 29.3 When to User Each Log Level

Log level은 DEBUG, INFO, WARNING, ERROR, CRITICAL 레벨로 나뉘어진다.
production 서버에서는 DEBUG를 제외한 모든 log level을 사용하는 것을 추천한다.

*Example of each log level*

| Log Level| Example |
|----------|:-------------|
| INFO | 빨간 아이스크림 컵이 열렸다. |
| WARNING | 쿠키 장식이 충분하지 않다. |
| ERROR | 아이스크림이 스푼과 함께 나가야하는데, 칼과 함께 나갔다. |
| CRITICAL | 아이스크림이 콘에서 떨어졌다. |

### 29.3.1 Log Catastrophes With CRITICAL

자연재해급 버그가 생겼을 때는 CRITICAL log level을 사용한다. 이런 버그는 서버가 죽을 수 있기 때문에, 이런 버그가 생겼을 때는 즉각적으로 대응해야 한다.

예를 들어, 우리 서비스가 내부의 웹서비스를 이용하는데 해당 웹사이트가 작동하지 않을 때는 CRITICAL log level을 사용해서 이를 알린다.

Django core code에는 CRITICAL log level이 사용되지 않았지만, application log를 기록할 때는 중요하다면 사용해도 좋다.

### 29.3.2 Log Production Errors With ERROR

> [!NOTE]
> Example 29.1: Logging Production Errors
```python
logger.error('Internal Server Error: %s', request.path,
exc_info=exc_info,
extra={
'status_code': 500,
'request': request
}
)
```

setting을 DEBUG=False로 하는 경우 admin으로 등록된 유저의 이메일로

- 에러 설명
- [traceback](https://docs.python.org/3/library/traceback.html)
- 에러를 일으킨 HTTP request의 정보

그렇기 때문에 어드민에게 이메일을 보낼만한 에러가 발생했을 때는 ERROR log level을 사용한다.
만약에 너의 view가 필요한 써드파티 API에 접근하지 못했을 때 ERROR log level을 사용한다.

### 29.3.3 Log Lower-Priority Problems With WARNING

WARNING log level은 에러가 아니지만, 주의해야할 문제가 발생했을 때 사용한다.

> [!NOTE]
> Example 29.2: Logging Mission CSRF
```python
logger.warning('Forbidden (%s): %s',
REASON_NO_CSRF_COOKIE, request.path,
extra={
'status_code': 403,
'request': request,
} )
```

### 29.3.4 Log Useful State Information Messages With INFO

우리는 해당 INFO 로그 레벨을 분석이 필요할 때 중요한 정보를 기록하기 위해 사용한다.

- 중요한 컴포넌트의 시작과 끝
- 중요한 이벤트의 상태가 변경ㄷ될 때
- permission이 변경될 때 ex. 해당 유저가 admin 권한으로 변경될 때

### 29.3.5 Log Debug-Related Messages to DEBUG

개발 환경에서 DEBUG 로깅 레벨을 사용하고, 가끔씩 INFO 레벨을 사용해서 정보를 로깅하는 것을 추천한다.

**print로 디버깅하지 마라**

> [!WARNING]
> Example 29.3: Using Print to Display Data
```python
from django.views.generic import TemplateView
from .helpers import pint_counter

class PintView(TemplateView):
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
pints_remaining = pint_counter()
print(f'Only {pints_remaining} pints of ice cream left.')
return context

```

> [!NOTE]
> Example 29.4: Using Logging to Display Data
```python
import logging

from django.views.generic import TemplateView
from .helpers import pint_counter

logger = logging.getLogger(__name__)

class PintView(TemplateView):
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
pints_remaining = pint_counter()
logger.debug('Only %d pints of ice cream left.' %pints_remaining) return context
```

> [!NOTE]
> TIP: Don’t use f-strings in logging statements
`print`를 디버그용으로 사용하면 안되나?

- `print`를 메인 코드에 깜빡하고 푸쉬하면 성능 저하를 일으킬 수 있다.
- `print`는 기록되지 않아서 이후에 디버깅을 위해 찾아보기 어렵다.

그래서 우리는

- `print`를 사용하지 않고 `logging`의 DEBUG level을 사용한다.
- `logging`을 사용하면 `print`보다 더 많은 정보를 기록할 수 있다. 그리고 이러한 점들이 오류가 터졌을 때 Sentry로 전송될 수 있다!

## 29.4 Log Tracebacks When Catching Exceptions

try except 구문에서의 traceback을 기록하는 것은 매우 중요하다. 왜냐하면 이를 통해 오류가 발생한 곳을 찾을 수 있기 때문이다.

1. `Logger.exception()`을 사용하면 자동으로 traceback을 **ERROR level**로 기록할 수 있다.
2. 다른 log level에서는 `exc_info` argument로 traceback을 기록할 수 있다.

> [!NOTE]
> Example 29.5: Capturing Tracebacks with exc_info
```python
import logging
import requests

logger = logging.getLogger(__name__)


def get_additional_data():
try:
r = requests.get('http://example.com/something-optional/')
except requests.HTTPError as e:
logger.exception(e)
logger.debug('Could not get additional data', exc_info=True)
return None

return r
```

## 29.5 One Logger Per Module That Uses Logging

각각의 모듈은 자신만의 logger를 가져야 한다. 이렇게 하면 모듈의 이름을 사용해서 로그를 구분할 수 있다.

**절대 다른 곳의 logger를 import해서 쓰지마라**

> [!NOTE]
> Example 29.6: One Logger Per Module
```python
import logging

logger = logging.getLogger(__name__)
```

이를 통해 현재 필요한 특정 logger만 켜고 끌 수 있다. 프로덕션 환경에서 로컬로 복제할 수 없는 이상한 문제가 발생하는 경우 해당 문제와 관련된 모듈에 대해서만 일시적으로 DEBUG level logging을 켤 수 있습니다.

> [!NOTE]
> Example: Temporarily Enabling Debug Logging
```python
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
```

그런 다음 문제를 파악하면 프로덕션 환경에서 해당 logger를 다시 끌 수 있습니다.

## 29.6 Log Locally to Rotating Files

따로 log를 써드파티나 이메일에 기록한다해도, 로컬에도 log를 기록하는 것이 좋다. 왜냐하면 로컬에 기록된 log를 통해 문제를 파악할 수 있기 때문이다. 로컬에 기록된 log는 용량 부족을 일으킬 수 있기 때문에 UNIX의 `logrotate`와 같은 도구를 사용해서 로그를 자동으로 삭제하도록 설정해야 한다.

## 29.7 Other Logging Tips

- logging에 대한 [Django 설명서](https://docs.djangoproject.com/ko/3.2/topics/logging/)에 따라 logging 설정 파일을 제어해라.
- 디버그는 logger의 DEBUG level을 사용해라.
- `logging`은 사용하고 있는 외부 라이브러리의 오류를 빠르게 알아챌 수 있게 해준다.
- 로깅에 늦은 때는 없다. 기다리지 말고 지금 바로 시작해라.
- ERROR 레벨 이상의 로그가 발생했을 때 이를 알려주는 알림을 설정해라. [PagerDuty](https://pagerduty.com)은 조치를 취할 때까지 반복적으로 회원님과 팀에게 알림을 보낸다.

## 29.8 Necessary Reading Material

- https://docs.djangoproject.com/en/3.2/topics/logging/
- https://docs.python.org/3/library/logging.html
- https://docs.python.org/3/library/logging.config.html
- https://docs.python.org/3/library/logging.handlers.html
- https://docs.python.org/3/howto/logging-cookbook.html

## 29.9 Useful Third-Party Packages

- [Sentry](https://sentry.io)는 오류를 집계하는 로깅 툴이다. Dropbox, AirBnB 및 기타 여러 회사에서 신뢰한다. 제품은 오픈 소스이며, 다양한 개발자들을 오픈 소스로 지원해온 훌륭한 역사를 가지고 있다.
- [loggly.com](https://loggly.com)은 로그 관리를 간소화하고 다양한 쿼리 도구를 제공한다.

## 29.10 Summary

Django는 logging을 위한 다양한 기능을 제공한다. 이를 통해 우리는 오류를 파악하고, 오류가 발생했을 때 즉각적으로 대응할 수 있다. 또한, 로그를 통해 우리는 서버의 안정성을 보장할 수 있다.

Loading

0 comments on commit 59caa34

Please sign in to comment.