Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/controllers/user_controller.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import logging
from app.services import user_service
from flask_jwt_extended import jwt_required, get_jwt
from flask.views import MethodView
from flask_smorest import Blueprint
from flask_principal import Permission, RoleNeed
from app.schemas.user_schema import *

# Create logger for this module
logger = logging.getLogger(__name__)

# Define permissions
read_permission = Permission(RoleNeed('read'))
write_permission = Permission(RoleNeed('write'))
Expand Down Expand Up @@ -50,6 +54,7 @@ def put(self, user_data, user_id):
class Login(MethodView):
@blp.arguments(UserSchema)
def post(self, user_data):
logger.info(f"User: {user_data['username']} login...")
result = user_service.login_user(user_data)
return result

Expand Down
66 changes: 31 additions & 35 deletions app/utils/logging.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import pytz
import logging
from flask import Flask
from datetime import datetime

def configure_logging(app: Flask):
# Set the logging level
logging.basicConfig(level=logging.DEBUG)

def configure_logging(app):
del app.logger.handlers[:]
# Create a logger instance
logger = logging.getLogger(app.name)

# Set the timezone to Vietnam
vietnam_timezone = pytz.timezone('Asia/Ho_Chi_Minh')

loggers = [app.logger, ]
handlers = []
# Configure logging with the Vietnam timezone
logging.Formatter.converter = lambda *args: pytz.utc.localize(datetime.utcnow()).astimezone(vietnam_timezone).timetuple()

console_handler = logging.StreamHandler()
console_handler.setFormatter(verbose_formatter(app))
if (app.config['APP_ENV'] == app.config['APP_ENV_TESTING']) or (
app.config['APP_ENV'] == app.config['APP_ENV_DEVELOP']):
console_handler.setLevel(logging.DEBUG)
elif (app.config['APP_ENV'] == app.config['APP_ENV_LOCAL']) or (
app.config['APP_ENV'] == app.config['APP_ENV_PRODUCTION']):
console_handler.setLevel(logging.INFO)
handlers.append(console_handler)

if (app.config['APP_ENV'] == app.config['APP_ENV_TESTING']) or (
app.config['APP_ENV'] == app.config['APP_ENV_DEVELOP']):
file_handler = logging.FileHandler(app.config['LOG_FILE_API'], encoding="utf-8")
file_handler.setFormatter(verbose_formatter(app))
file_handler.setLevel(logging.DEBUG)
handlers.append(file_handler)
elif (app.config['APP_ENV'] == app.config['APP_ENV_LOCAL']) or (
app.config['APP_ENV'] == app.config['APP_ENV_PRODUCTION']):
file_handler = logging.FileHandler(app.config['LOG_FILE_API'], encoding="utf-8")
file_handler.setFormatter(verbose_formatter(app))
file_handler.setLevel(logging.INFO)
handlers.append(file_handler)

for logger in loggers:
for handler in handlers:
logger.addHandler(handler)
logger.propagate = False
logger.setLevel(logging.DEBUG)
# Define the log format
console_log_format = '%(asctime)s - %(levelname)s - %(message)s'
file_log_format = '%(asctime)s - %(levelname)s - %(message)s - (%(filename)s:%(lineno)d)'


def verbose_formatter(app):
return logging.Formatter(app.config['FTM'], datefmt=app.config['DATE_FMT'])
# Create a console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(logging.Formatter(console_log_format, datefmt=app.config['DATE_FMT']))
logger.addHandler(console_handler)

# Create a file handler
file_handler = logging.FileHandler(filename=app.config['LOG_FILE_API'], encoding="utf-8")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(logging.Formatter(file_log_format, datefmt=app.config['DATE_FMT']))
logger.addHandler(file_handler)

# Disable the INFO log messages from werkzeug
# werkzeug_logger = logging.getLogger('werkzeug')
# werkzeug_logger.setLevel(logging.ERROR) # Set the level to ERROR to turn off INFO messages
7 changes: 3 additions & 4 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class DefaultConfig:
"""
# Flask Configuration
APP_NAME = os.environ.get('APP_NAME')
SECRET_KEY = secrets.token_urlsafe(64)
SECRET_KEY = "e42ebf32a22c7cef7f4a33c71f90f0d8ea65e63144f952e57e1b39b26cc26a6f"
PROPAGATE_EXCEPTIONS = True
DEBUG = False
TESTING = False

# Configuration of Flask-JWT-Extended
JWT_SECRET_KEY = secrets.token_urlsafe(64)
JWT_SECRET_KEY = "d7da6e940725de5a15b7e48f5a71f535a315c72a5372c1d3bb8691b38b5f29a1"
# Determines the minutes that the access token remains active
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(minutes=30)
# Determines the days that the refresh token remains active
Expand Down Expand Up @@ -52,8 +52,7 @@ class DefaultConfig:
APP_ENV = ''

# Logging
FTM = '[%(asctime)s.%(msecs)d]\t %(levelname)s \t[%(name)s.%(funcName)s:%(lineno)d]\t %(message)s'
DATE_FMT = '%d/%m/%Y %H:%M:%S'
DATE_FMT = '%Y-%m-%d %H:%M:%S'
LOG_FILE_API = f'{basedir}/logs/api.log'


Expand Down
7 changes: 4 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ services:

nginx_service:
container_name: nginx_container
image: nginx:1.25.1-alpine
volumes:
- ./services/server/nginx.conf:/etc/nginx/conf.d/default.conf
image: nginx_image
build:
context: ./services/server
dockerfile: Dockerfile
ports:
- 8080:80
depends_on:
Expand Down
4 changes: 2 additions & 2 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ if [ "$APP_ENV" = "local" ]; then
echo "Done init user-admin"

echo "Run app with gunicorn server..."
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 1;
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 4;
fi

if [ "$APP_ENV" = "production" ]; then
echo "Run app with gunicorn server..."
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 1;
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 4;
fi
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Pygments==2.13.0
PyJWT==2.6.0
python-dateutil==2.8.2
python-dotenv==1.0.0
pytz==2023.3
pyzmq==24.0.1
six==1.16.0
SQLAlchemy==2.0.7
Expand Down
4 changes: 4 additions & 0 deletions services/server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM nginx:1.25.1-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
37 changes: 5 additions & 32 deletions tests/postman/flask-api-rest-template.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"_postman_id": "03bd1377-f65e-4a5d-b478-2af9d4f41f18",
"name": "Template REST API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "20498029"
"_exporter_id": "20498029",
"_collection_link": "https://dark-escape-873868.postman.co/workspace/My-Workspace~fd59678e-5c9a-4e36-8407-3c2ba6dcae38/collection/20498029-03bd1377-f65e-4a5d-b478-2af9d4f41f18?action=share&creator=20498029&source=collection_link"
},
"item": [
{
Expand Down Expand Up @@ -64,34 +65,6 @@
},
"response": []
},
{
"name": "Delete",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{TOKEN}}",
"type": "string"
}
]
},
"method": "DELETE",
"header": [],
"url": {
"raw": "{{HOST}}/user/8",
"host": [
"{{HOST}}"
],
"path": [
"user",
"8"
]
}
},
"response": []
},
{
"name": "Update",
"request": {
Expand Down Expand Up @@ -300,7 +273,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"username\": \"admin\",\r\n \"password\": \"123456\"\r\n}",
"raw": "{\r\n \"username\": \"member\",\r\n \"password\": \"123456\"\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -566,7 +539,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"User Management\",\r\n \"route\": \"user_management\"\r\n}",
"raw": "{\r\n \"name\": \"read\",\r\n \"description\": \"Read data\"\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -602,7 +575,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"User Management\",\r\n \"route\": \"user_management\"\r\n}",
"raw": "{\r\n \"name\": \"read\",\r\n \"description\": \"Read data\"\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down