journalctl - linux systemd (systemctl, service) log 보는 법 개발 이것저것

이 글을 읽기 전에 Linux 의 sytstmed 에 대해 잘 모르시는 분은 여기 를 먼저 한번 보고 오시는걸 추천 드립니다.

sudo service MY_APP status

라는 명령어를 치면 기본적으로 데몬 정보와 아래쪽에 간략한 로그정보들이 뜬다

예를들어 sudo service gunicorn status 이라고 하면 아래처럼 뜬다.


자 위 같은경우 gunicorn 서비스에 대한 내용인데 아래쪽에 보이는 로그는 gunicorn에서 제공하는 error log 도 아니고  access log 도 아니다.
어디서 보여지는 로그일까? 

바로 gunicorn 을 데몬화 하여 실행해주는 systemd 프로세스에서 찍히는 로그이다.
그럼 이것은 어떻게 보아야 하나?

journalctl 이라는 linux 명령어가 있다.

man page 에서 보면 아래와 같이 기술하고 있다.

journalctl may be used to query the contents of the systemd(1)
journal as written by systemd-journald.service(8).

해석 해보면
= systemd-journald.service 에 의해 기록된 systemd journal 에 대한 컨텐츠를 query 할때 사용한다

즉, systemd 데몬의 동작로그를 볼 수 있다는 것이다.

옵션이 다양한데 (내 입장에서) 자주 사용되는 것은 주로 아래와 같다.

-u SERVICE_NAME : 특정 서비스의 저널만을 본다
-f : 출력되는 저널을 follow 한다 (App 에서 뿜어져 나오는 console log 를 볼 수 있음)

정리하자면,
내가 만일 gunicorn service 로그를 실시간(=follow)으로 보고싶다면 아래 명령어를 날릴 수 있다.

journalctl -u gunicorn -f



[운전 노하우] 차로 변경법

은근.. 차로 변경 무서워 하시는 분들이 많이 있다.
그래서 내 운전법을 바탕으로 가이드를 한번 적어보았다.

<차로변경 5 Steps>

1. 일단 변경하려는 방향으로 깜박이를 킨다

2. 옆차선을 살짝 바라봐서 나란히 주행중인 차가 없는지 확인한다. (백미러 사각지대이므로 육안으로 확인 필요)

3. 끼어들고자 하는 방향에 백미러를 바라본다

4. 백미러에 비치는 옆 차선 주행 차량이 짤려보이지 않고 차체 전체가 거울안에 다 들어오는지(=공간이 충분하다는 뜻) 확인한다

5. 핸들 방향을 틀고 약 3초 정도 (너무 오래걸려도 안됨) 안에 옆차선으로 완전히 이동한다



<+ 주의사항>

- 내가 변경하려는 차로의 맞은편에 있는 차도 차로변경을 하려고 하는것은 아닌지 확인
   * 예를들어, 내가 1 -> 2차로 변경 하려는데 3차로 주행 차량이 2차로로 들어오려고 시도중이거나 깜빡이를 넣지는 않았는지

- 핸들을 꺾기 직전에 사이드 미러 흘끗 한번 봐서 뒤에 오토바이 혹은 과속차량이 오지 않는지 확인
   * 이건 우회전, 좌회전 할때도 마찬가지 !!

- 변경할 차로의 전방 차량이 급브레이크를 밟을 수도 있으므로 현재 내 차로 + 변경할 차로의 전방을 수시로 주시하도록 하자
   * 도로 위에서는 누구나 언제든 브레이크를 밟을 수 있다. 
   * 차로 변경 시, 속도가 높으면 앞차가 급 브레이크를 밟았을 시 추돌사고를 낼 수도 있다.


<+ 각종 예외 상황>

일단 5스텝이라고 적어놓긴 했는데...
막상 상황에 따라 내 맘대로 안될때가 있다. 아래 경우들인데... 

각각의 경우 대처 방법을 적어보았다.

1. 변경하려는 차로에 계속 차가 있거나 공간이 충분히 나오지 않는경우 
   : 속도를 줄여서 옆차를 먼저 보내준 뒤, 그 뒤로 들어가자





[django] DRF Serializer 최적화 (=Best Practice) Python

Serializer 이해하기

  • model object ↔︎ data (dict) 변환을 위한 도구

  • 입력받는 데이터의 필드별 Validation + 가공 을 제공

  • 출력하는 데이터의 포맷과 형식을 커스터마이징 할 수 있음

  • ModelSerializer 의 경우 Model 과 직접적으로 연결하여 활용 가능

  • 1개의 요청을 처리하는데 일반적으로 약 12%의 처리시간을 소요함

ModelSerializer 가 느리다… 왜? 그럼 어떻게 해야?

  • 단순히 (un)serializing 만을 제공하는 함수를 만들어 사용하는것보다 약 370배 가까이 느림

  • 원인: 내부적으로 django.utils.functional 모듈이 validation 을 처리하는데 시간이 많이 소요되기때문

    • 해결책- 필드 validation 은 writable 일때만 적용되므로 조회만 필요한 필드들은 반드시 read-only 지정을 해줄것

  • 원인: ModelSerializer 가 각 필드값을 생성해내고 검증할때 수많은 metadata 를 사용하기때문

    • 해결책: “Regular(=일반)” Serializer 를 사용할 것

    • 일반 ModelSerializer를 사용하는것보다 약 1/6 배 빨라짐

  • 원인: DRF 의 field validation 에서 lazy 함수를 사용함

    • python functional 패키지의 lazy 함수는 proxy 를 통해 wrapped function 이 실제로 호출될때까지 함수를 evaluate 하지 않도록 만들어 놨는데 이게 캐싱이 되지 않기때문에 심각한 성능 저하를 만들게 된다

    • cached function(일반 함수) 이 lazy-wrapped function 보다 약 33배 빠름

    • DRF 에서 이에 대한 패치를 하여 ModelSerializer 의 속도 저하를 개선함

    • 해결책: Django + DRF 최신버전을 사용할 것 (릴리즈 안됨)

      1pip install git+https://github.com/encode/django-rest-framework2pip install git+https://github.com/django/django

 

동일 연산에 대한 Serializer 별 속도비교

ModelSerializer < ModelSerializer + ReadOnly < Serializer = Serializer + ReadOnly
< 직접만든 custom serializer

결론

  • read_only_fields 로 최대한 writable field 수를 줄여라

  • ModelSerializer 보다 일반 Serializer 를 사용하라

  • 반드시 써야하는게 아니면 굳이 Serializer 를 사용할 필요는 없다 (By. DRF 제작자)

  • DRF 의 ModelSerializer - field validation 에서 lazy 함수를 사용하는것에 대한 패치가 완료된 Django, DRF 최신버전을 사용하라

  • 2개 이상의 Model 이 섞인 Nested Serializer 일경우, queryset 에서 prefetch_related 또는 selected_related 함수를 사용하여 미리 join 된 데이터를 얻도록 처리한다 (안할경우 N+1 query problem 발생)

참고자료



[AWS] S3 Presigned URL 이용하여 다운로드시, Signature Version4 관련 오류해결: Please use AWS4-HMAC-SHA256 개발 삽질이야기

나는 Python Django 로 웹 서비스를 유지보수 하고있다.

Public Access 가 차단된 S3 버킷에 대하여 다운로드를 위해 서버단에서 presigned url 을 발급받아 처리를 하려고 했는데 아래와 같은 오류가 났음

---
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidRequest</Code>
<Message>The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.</Message><RequestId>FM219905MB2HVRKQ</RequestId><HostId>bOaTyZWMLg+nDQnmvINVj31vE6xgx+r4E8kWwL+HcK0VfqFd/4FmLsvqVLTsF4pZ1kBP5ZEP3tE=</HostId>
</Error>
---

요거 관련 내용을 찾아보면, Request 날릴때 Signature 를 version 4 방식으로 바꾸는 소스코드들을 언어별로 막 소개하면서 그런 문서들이 나오는데...

Presigned URL 방식은 s3 client 생성시, 최초에 설정만 잘 하면
presigned URL 에 Signature Version 4 가 적용된 완성된 형태로 발급을 받을 수 있다.

요기 공식문서를 보면 완벽해결!!!

간단한 Python 코드를 첨부한다.

import logging
from urllib.parse import urlparse

import boto3
from botocore.config import Config
from botocore.exceptions import ClientError
from django.conf import settings
from django.core.files.storage import default_storage
from rest_framework.exceptions import NotFound

logger = logging.getLogger(__name__)

# AWS signature version 4 를 지원하기위해 아래와 같이 전용 설정 Object 생성
s3_client_config = Config(
    region_name=settings.AWS_REGION,
    signature_version='s3v4',
    retries={
        'max_attempts': 10,
        'mode': 'standard'
    }
)


def get_presigned_url_from_private_bucket(resource_url: str) -> str:
    """
    일시적으로 Public 에게 공개되는 URL 생성
    """
    cv_url_obj = urlparse(resource_url)
    s3_obj_key = cv_url_obj.path[1:]
    s3_client = boto3.client('s3', config=s3_client_config)
    try:
        presigned_url = s3_client.generate_presigned_url(
            ClientMethod='get_object',
            Params={'Bucket': settings.AWS_STORAGE_BUCKET_NAME_PRIVATE, 'Key': s3_obj_key},
            ExpiresIn=600
        )
        return presigned_url

    except ClientError as e:
        logger.error(e)


[Django] session 기본 기능 소개 Python

태초에 HTTP 의 stateless 한 속성으로인해, 각 웹서비스들은 들어오는 요청들이 "누구" 로부터 오는지 식별할 방법을 찾아 해매었고, 그 중 하나가 쿠키 + 세션이었습니다.

자, 그 2가지의 기본 정의를 일단 알아볼까요?


쿠키
: 하이퍼 텍스트의 기록서(HTTP)의 일종으로서 인터넷 사용자가 어떠한 웹사이트를 방문할 경우 그 사이트가 사용하고 있는 서버를 통해 인터넷 사용자의 컴퓨터에 설치되는 작은 기록 정보 파일을 일컫는다


세션
: 컴퓨터 과학에서, 특히 네트워크 분야에서 반영구적이고 상호작용적인 정보 교환을 전제하는 둘 이상의 통신 장치나 컴퓨터와 사용자 간의 대화나 송수신 연결상태를 의미하는 보안적인 다이얼로그(dialogue) 및 시간대를 가리킨다. 컴퓨터 시스템의 관리자(또는 OS 또는 서버)가 자신의 자산을 이용하는것을 허락한 사용자 (컴퓨팅)를 인식한 일정한 기간을 가리키는것으로 광범위하게 이해될 수 있다.


Django 에도 이러한 세션관리 기능이 있습니다.

장고 세션의 기본 작동 원리도 위 2가지 개념과 같습니다.


서비스에 로그인을 하게되면 쿠키에 sessionid 가 저장되고 이를 이후 모든 동일 도메인 페이지에서 발생하는 request 에 포함시켜, 서버단에서 유저를 식별 할 수 있게 되지요..


그러면! 장고는 이 세션 컨트롤에 있어서 어떤 기본 기능들을 제공하고 있는지 알아봅시다.

  • SESSION_CACHE_ALIAS
    • session storage 로 캐시를 사용중일때 어떤 캐시를 쓸것인지 지정 (default: 'default')
  • SESSION_COOKIE_AGE
    • 세션ID 가 발급될때 해당 쿠키의 expire 까지 걸리는 시간(초)
    • 기본값: 1209600초 = 2주
    • 요걸로 세션 타임아웃을 지정할 수 있습니다
  • SESSION_COOKIE_DOMAIN
    • 세션 쿠키의 도메인을 지정
    • 크로스 도메인으로 서비스 하고자 할때 사용 (ex) .example.com
    • 기본값: None (=발급과 동시에 full 도메인 자동등록)
  • SESSION_COOKIE_HTTPONLY
    • client-side js 가 세션 쿠키 접근 못하도록 막는 조치
    • 기본값: True
  • SESSION_COOKIE_NAME
    • 세션 쿠키 명 (기본값: sessionid)
  • SESSION_COOKIE_PATH
    • 세션 쿠키 Path (기본값: /)
    • 호스트 하나에 여러개 장고서비스가 붙어야 될 경우 유용함
    • 예를들어 아래처럼 될 수 있겠죠
      • mysite.com/shopping : 커머스 서비스 제공하는 장고 프로젝트
      • mysite.com/platform : 제품 성분 분석 서비스 제공하는 장고 프로젝트
  • SESSION_COOKIE_SAMESITE
    • 세션 쿠키의 SameSite 속성을 지정
    • 기본값: Lax(= 기본적으로 모든 cross-site sub request에 쿠키를 보내지 않음. 직접 navigate 하는경우 제외)
  • SESSION_COOKIE_SECURE
    • True 일경우, HTTPS 환경일때만 쿠키가 전송됨
    • 기본값: False
    • 세션 hi-jacking 공격때문에 True 로 하는것을 추천
  • SESSION_ENGINE
    • 세션 정보를 저장할 백엔드 스토리지 종류 지정 가능
    • RDB(=기본값), file, cache, cache DB, signed cookie
  • SESSION_EXPIRE_AT_BROWSER_CLOSE
    • 브라우저가 닫힐때 세션 종료 여부
    • 기본값: False
  • SESSION_FILE_PATH
    • session engine 이 파일일때 세션 정보 저장할 파일 Path
  • SESSION_SAVE_EVERY_REQUEST
    • 매번 request 가 들어올때마다 session 정보를 갱신해줄 것인지 여부
    • 기본값: False
    • 이것으로 유저 동작이 있을때마다 세션 타임아웃 시간을 연장해줄 수 있음
  • SESSION_SERIALIZER
    • 세션 data 를 세션 엔진에 넣고 빼고 할때 사용할 serializer 를 지정
    • 기본값: django.contrib.sessions.serializers.JSONSerializer

참고자료


https://docs.djangoproject.com/en/3.2/topics/http/sessions/

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite


1 2 3 4 5 6 7 8 9 10 다음


통계 위젯 (블랙)

6045
703
304558

GoogleAdsenseResponsive

Cluster map