본문 바로가기
Flask

Flask - flask의 다양한 기능

by DGK 2021. 11. 27.

 

Flask 입문 수업을 듣고 중요한 내용을 정리했습니다.
개인 공부 후 자료를 남기기 위한 목적이므로 내용 상에 오류가 있을 수 있습니다.

 

flask의 다양한 기능(Python)

flask의 다양한 기능을 예제를 통해 학습하고 연습하고자 한다.

 

에러(error) 다루기

from flask import Flask 
import requests

app = Flask(__name__)   

@app.errorhandler(404)    
def page_not_found(error):
    return "<h1>404 Error</h1>", 404    # 없는 페이지를 요청했을 때의 에러

@app.route("/google")
def get_google():
    response = requests.get("http://www.google.co.kr")
    return response.text 

if __name__ == "__main__":
    app.run(host="0.0.0.0", port="8080")

 

```

결과 :

(존재하는 웹 페이지를 요청한 경우)

http://localhost:8080/google

참고로, response 객체의 text를 사용하면 해당 객체로 들어온 웹 페이지의 HTML 파일을 웹 브라우저로 오픈할 수 있다.

 

(존재하지 않는 웹 페이지를 요청한 경우)

http://localhost:8080/test

```

 

errorhandler() 함수를 사용하면 HTTP 오류 코드가 나오는 페이지를 정의할 수 있다.

참고로, return의 두 번째 인자에 에러코드를 넘겨주지 않으면 웹 페이지의 요청을 성공(HTTP status code : 200)한 것으로 인지한다.

 

 

로깅(logging) 다루기

서버는 24시간 동작하므로, 문제가 있을 때 어떤 문제가 있었는지 파악하기 위해 로깅 기능을 사용한다.

일반적으로 로깅은 개발 단계에서는 사용하지 않고, 상용화 단계에서 사용자 모니터링 및 해킹 확인 등의 다양한 문제를 파악하기 위해 사용된다.

 

 

*참고

파이썬에는 로그를 다루는 logging 라이브러리를 제공한다.

또한, 로깅 정보에는 레벨이 있으며 로깅 정보는 로그의 레벨에 따라 출력(기록)을 제한할 수 있다.

 

   - DEBUG > INFO > WARNING > ERROR > CRITICAL

 

DEBUG에서 CRITICAL로 갈수록 심각한 문제(에러)임을 의미한다.

 

import logging

# 파일로 남기기 위해서는 filename='test.log' 파라미터, 어느 로그까지 남길 것인지를 level로 설정 가능
logging.basicConfig(filename='test.log', level=logging.ERROR)

# 로그를 남길 부분에 다음과 같이 로그 레벨에 맞추어 출력해주면 해당 내용이 파일에 들어감
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")

 

```

결과 :

test.log 파일

```

 

위의 예시코드에서는 level = logging.ERROR로 로그 레벨이 설정되어 있기 때문에, debug부터 critical까지의 모든 에러를 기록하도록 코드를 작성했음에도 ERROR 이상의 문제만을 해당 파일에 기록하는 것이다.

 

 

*예제 코드

from flask import Flask
import requests

app = Flask(__name__)

if not app.debug:
    import logging
    from logging.handlers import RotatingFileHandler   # 사용할 logging 핸들러 이름을 적어줌
    file_handler = RotatingFileHandler(
        'test_server.log', maxBytes=2000, backupCount=10) 
    file_handler.setLevel(logging.WARNING)             # 어느 단계(level)까지 로깅을 할지를 적어줌
    app.logger.addHandler(file_handler)                # app.logger.addHandler()에 등록시켜줘야 app.logger로 사용 가능


@app.errorhandler(404)
def page_not_found(error):
    app.logger.error('이것은 중요한 에러입니다. page_not_found에서 일어났습니다.')
    return "<h1>해당 경로에 맞는 웹페이지가 없습니다. 문제가 지속되면, 관리자에게 연락해주세요</h1>", 404


if __name__ == "__main__":
    app.run(host="0.0.0.0", port="8080", debug=False)

 

```

결과 :

(존재하지 않는 웹 페이지를 요청한 경우 : 404 에러)

http://localhost:8080/test

 

test_server.log 파일

```

 

  • flask와 logging 기능

logging 라이브러리와 함께 flask logging 기능을 사용할 수 있다.

 

   - 주요 logging 핸들러 종류(어떻게 로그를 다룰 것인지에 대해 미리 구현된 함수들을 제공함)

 

  1. FileHandler : 파일로 로그를 저장함
  2. RotatingFileHandler : 파일로 로그를 저장하되, 파일의 정해진 사이즈를 넘어가면 새로운 파일을 생성하여 로그를 기록함(maxBytes : 하나의 파일 사이즈, backupCount :  생성할 파일 개수, 참고로 모든 파일을 다 쓰면 맨 앞의 파일에 로그 기록을 덮어씌워 저장함)
  3. NTEventLogHandler : 윈도우 시스템에서 로그를 기록함
  4. SysLogHandler : 유닉스 계열(리눅스) 시스템에서 로그를 syslog로 기록함

 

  • 예제 코드 주요내용
  1. 로그를 기록하는 파일(test_server.log)는 해당 파이썬 코드가 실행되는 폴더에 생성된다.
  2. 위의 예제코드처럼 404 에러가 발생하면 errorhandler() 함수의 인자에 404 에러가 들어가고, page_not_found() 함수의 인자(error)로 에러 메세지가 들어간다. 그 이후에는 해당 함수가 실행되며 지정된 파일에 로그를 기록한다. (참고로 웹 페이지에는 retrun 값을 반환하여 띄워준다.) 
  3. 참고로, app.run(host='0.0.0.0', port='8080', debug=False)의 코드에서 debug = False이어야만 에러가 발생했을 때 로깅 기능이 작동한다. (debug가 False이어야만 if절의 not app.debug가 True가 되어 해당 if절이 실행됨 :  로깅 기능 실행)

 

 

다양한 데코레이터의 기능(flask)

*다양한 데코레이터의 종류

 

  1. before_first_request : flask(서버)를 실행한 후, 첫 번째 HTTP 요청에만 앞서 실행되는 데코레이터
  2. before_request : HTTP 요청이 들어올 때마다, 해당 요청에 앞서 실행되는 데코레이터
  3. after_request : HTTP 요청을 처리한 후, 해당 리턴 값을 통해 HTTP 응답 데이터가 만들어지면 이를 웹 브라우저에 전달하기에 앞서 실행되는 데코레이터 (참고로, after_reques는 HTTP 응답 데이터를 인자(response)로 받아서 return 해줘야만 데코레이터를 실행한 후에도 HTTP 응답 데이터를 웹 브라우저로 전달함)

 

 

*예제 코드

from flask import Flask
import requests

app = Flask(__name__)


@app.before_first_request
def before_first_request():
    print("flask 실행 후 첫 요청 때만 실행")


@app.before_request
def before_request():
    print("HTTP 요청이 들어올 때마다 실행")


@app.after_request
def after_request(response):
    print("HTTP 요청 처리가 끝나고 브라우저에 응답하기 전에 실행")
    return response


@app.route("/hello")
def hello():
    print('hello')
    return "<h1>Hello Flask!</h1>"


if __name__ == "__main__":
    app.run(host="0.0.0.0", port="8080")

 

```

결과 :

(첫 번째 HTTP 요청 결과)

 

flask 실행 후 첫 요청 때만 실행
HTTP 요청이 들어올 때마다 실행
hello
HTTP 요청 처리가 끝나고 브라우저에 응답하기 전에 실행
127.0.0.1 - - [27/Nov/2021 15:13:41] "GET /hello HTTP/1.1" 200 -

 

 

(두 번째 HTTP 요청 결과)

 

HTTP 요청이 들어올 때마다 실행
hello
HTTP 요청 처리가 끝나고 브라우저에 응답하기 전에 실행
127.0.0.1 - - [27/Nov/2021 15:15:44] "GET /hello HTTP/1.1" 200 -

 

http://localhost:8080/hello

```

 

*참고

데코레이터의 특성을 고려하여 위의 예제코드 결과를 분석해볼 것

 

 

댓글