Skip to content

Commit fa2edc4

Browse files
Merge pull request #5 from vectornguyen76/develop
Develop
2 parents 7f2c62e + 1a956a3 commit fa2edc4

File tree

8 files changed

+55
-76
lines changed

8 files changed

+55
-76
lines changed

app/controllers/user_controller.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import logging
12
from app.services import user_service
23
from flask_jwt_extended import jwt_required, get_jwt
34
from flask.views import MethodView
45
from flask_smorest import Blueprint
56
from flask_principal import Permission, RoleNeed
67
from app.schemas.user_schema import *
78

9+
# Create logger for this module
10+
logger = logging.getLogger(__name__)
11+
812
# Define permissions
913
read_permission = Permission(RoleNeed('read'))
1014
write_permission = Permission(RoleNeed('write'))
@@ -50,6 +54,7 @@ def put(self, user_data, user_id):
5054
class Login(MethodView):
5155
@blp.arguments(UserSchema)
5256
def post(self, user_data):
57+
logger.info(f"User: {user_data['username']} login...")
5358
result = user_service.login_user(user_data)
5459
return result
5560

app/utils/logging.py

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,37 @@
1+
import pytz
12
import logging
3+
from flask import Flask
4+
from datetime import datetime
25

6+
def configure_logging(app: Flask):
7+
# Set the logging level
8+
logging.basicConfig(level=logging.DEBUG)
39

4-
def configure_logging(app):
5-
del app.logger.handlers[:]
10+
# Create a logger instance
11+
logger = logging.getLogger(app.name)
12+
13+
# Set the timezone to Vietnam
14+
vietnam_timezone = pytz.timezone('Asia/Ho_Chi_Minh')
615

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

10-
console_handler = logging.StreamHandler()
11-
console_handler.setFormatter(verbose_formatter(app))
12-
if (app.config['APP_ENV'] == app.config['APP_ENV_TESTING']) or (
13-
app.config['APP_ENV'] == app.config['APP_ENV_DEVELOP']):
14-
console_handler.setLevel(logging.DEBUG)
15-
elif (app.config['APP_ENV'] == app.config['APP_ENV_LOCAL']) or (
16-
app.config['APP_ENV'] == app.config['APP_ENV_PRODUCTION']):
17-
console_handler.setLevel(logging.INFO)
18-
handlers.append(console_handler)
19-
20-
if (app.config['APP_ENV'] == app.config['APP_ENV_TESTING']) or (
21-
app.config['APP_ENV'] == app.config['APP_ENV_DEVELOP']):
22-
file_handler = logging.FileHandler(app.config['LOG_FILE_API'], encoding="utf-8")
23-
file_handler.setFormatter(verbose_formatter(app))
24-
file_handler.setLevel(logging.DEBUG)
25-
handlers.append(file_handler)
26-
elif (app.config['APP_ENV'] == app.config['APP_ENV_LOCAL']) or (
27-
app.config['APP_ENV'] == app.config['APP_ENV_PRODUCTION']):
28-
file_handler = logging.FileHandler(app.config['LOG_FILE_API'], encoding="utf-8")
29-
file_handler.setFormatter(verbose_formatter(app))
30-
file_handler.setLevel(logging.INFO)
31-
handlers.append(file_handler)
32-
33-
for logger in loggers:
34-
for handler in handlers:
35-
logger.addHandler(handler)
36-
logger.propagate = False
37-
logger.setLevel(logging.DEBUG)
19+
# Define the log format
20+
console_log_format = '%(asctime)s - %(levelname)s - %(message)s'
21+
file_log_format = '%(asctime)s - %(levelname)s - %(message)s - (%(filename)s:%(lineno)d)'
3822

39-
40-
def verbose_formatter(app):
41-
return logging.Formatter(app.config['FTM'], datefmt=app.config['DATE_FMT'])
23+
# Create a console handler
24+
console_handler = logging.StreamHandler()
25+
console_handler.setLevel(logging.DEBUG)
26+
console_handler.setFormatter(logging.Formatter(console_log_format, datefmt=app.config['DATE_FMT']))
27+
logger.addHandler(console_handler)
28+
29+
# Create a file handler
30+
file_handler = logging.FileHandler(filename=app.config['LOG_FILE_API'], encoding="utf-8")
31+
file_handler.setLevel(logging.DEBUG)
32+
file_handler.setFormatter(logging.Formatter(file_log_format, datefmt=app.config['DATE_FMT']))
33+
logger.addHandler(file_handler)
34+
35+
# Disable the INFO log messages from werkzeug
36+
# werkzeug_logger = logging.getLogger('werkzeug')
37+
# werkzeug_logger.setLevel(logging.ERROR) # Set the level to ERROR to turn off INFO messages

config.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ class DefaultConfig:
1010
"""
1111
# Flask Configuration
1212
APP_NAME = os.environ.get('APP_NAME')
13-
SECRET_KEY = secrets.token_urlsafe(64)
13+
SECRET_KEY = "e42ebf32a22c7cef7f4a33c71f90f0d8ea65e63144f952e57e1b39b26cc26a6f"
1414
PROPAGATE_EXCEPTIONS = True
1515
DEBUG = False
1616
TESTING = False
1717

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

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

5958

docker-compose.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ services:
4040

4141
nginx_service:
4242
container_name: nginx_container
43-
image: nginx:1.25.1-alpine
44-
volumes:
45-
- ./services/server/nginx.conf:/etc/nginx/conf.d/default.conf
43+
image: nginx_image
44+
build:
45+
context: ./services/server
46+
dockerfile: Dockerfile
4647
ports:
4748
- 8080:80
4849
depends_on:

entrypoint.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ if [ "$APP_ENV" = "local" ]; then
2929
echo "Done init user-admin"
3030

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

3535
if [ "$APP_ENV" = "production" ]; then
3636
echo "Run app with gunicorn server..."
37-
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 1;
37+
gunicorn --bind $API_HOST:$API_PORT $API_ENTRYPOINT --timeout 10 --workers 4;
3838
fi

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Pygments==2.13.0
5353
PyJWT==2.6.0
5454
python-dateutil==2.8.2
5555
python-dotenv==1.0.0
56+
pytz==2023.3
5657
pyzmq==24.0.1
5758
six==1.16.0
5859
SQLAlchemy==2.0.7

services/server/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM nginx:1.25.1-alpine
2+
3+
RUN rm /etc/nginx/conf.d/default.conf
4+
COPY nginx.conf /etc/nginx/conf.d

tests/postman/flask-api-rest-template.postman_collection.json

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"_postman_id": "03bd1377-f65e-4a5d-b478-2af9d4f41f18",
44
"name": "Template REST API",
55
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
6-
"_exporter_id": "20498029"
6+
"_exporter_id": "20498029",
7+
"_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"
78
},
89
"item": [
910
{
@@ -64,34 +65,6 @@
6465
},
6566
"response": []
6667
},
67-
{
68-
"name": "Delete",
69-
"request": {
70-
"auth": {
71-
"type": "bearer",
72-
"bearer": [
73-
{
74-
"key": "token",
75-
"value": "{{TOKEN}}",
76-
"type": "string"
77-
}
78-
]
79-
},
80-
"method": "DELETE",
81-
"header": [],
82-
"url": {
83-
"raw": "{{HOST}}/user/8",
84-
"host": [
85-
"{{HOST}}"
86-
],
87-
"path": [
88-
"user",
89-
"8"
90-
]
91-
}
92-
},
93-
"response": []
94-
},
9568
{
9669
"name": "Update",
9770
"request": {
@@ -300,7 +273,7 @@
300273
"header": [],
301274
"body": {
302275
"mode": "raw",
303-
"raw": "{\r\n \"username\": \"admin\",\r\n \"password\": \"123456\"\r\n}",
276+
"raw": "{\r\n \"username\": \"member\",\r\n \"password\": \"123456\"\r\n}",
304277
"options": {
305278
"raw": {
306279
"language": "json"
@@ -566,7 +539,7 @@
566539
"header": [],
567540
"body": {
568541
"mode": "raw",
569-
"raw": "{\r\n \"name\": \"User Management\",\r\n \"route\": \"user_management\"\r\n}",
542+
"raw": "{\r\n \"name\": \"read\",\r\n \"description\": \"Read data\"\r\n}",
570543
"options": {
571544
"raw": {
572545
"language": "json"
@@ -602,7 +575,7 @@
602575
"header": [],
603576
"body": {
604577
"mode": "raw",
605-
"raw": "{\r\n \"name\": \"User Management\",\r\n \"route\": \"user_management\"\r\n}",
578+
"raw": "{\r\n \"name\": \"read\",\r\n \"description\": \"Read data\"\r\n}",
606579
"options": {
607580
"raw": {
608581
"language": "json"

0 commit comments

Comments
 (0)