Skip to content

Commit 2023973

Browse files
committed
Add ddog logger.
1 parent e50e95b commit 2023973

File tree

6 files changed

+1358
-157
lines changed

6 files changed

+1358
-157
lines changed

config.py

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Config:
1313

1414
# General Config
1515
ENVIRONMENT = environ.get("ENVIRONMENT")
16+
APP_NAME = "flask_sqlalchemy_tutorial"
1617

1718
# Flask Config
1819
FLASK_APP = "wsgi.py"
@@ -23,3 +24,6 @@ class Config:
2324
SQLALCHEMY_DATABASE_URI = environ.get("SQLALCHEMY_DATABASE_URI")
2425
SQLALCHEMY_ECHO = False
2526
SQLALCHEMY_TRACK_MODIFICATIONS = False
27+
28+
29+
settings = Config

gunicorn.conf.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
bind = ["127.0.0.1:8000"]
2525
elif ENVIRONMENT == "production":
2626
daemon = True
27-
accesslog = "/var/log/flasksession/access.log"
28-
errorlog = "/var/log/flasksession/error.log"
27+
accesslog = "/var/log/flasksqlalchemy/access.log"
28+
errorlog = "/var/log/flasksqlalchemy/error.log"
2929
loglevel = "trace"
30-
dogstatsd_tags = "env:prod,service:flasksession,language:python"
30+
dogstatsd_tags = "env:prod,service:flasksqlalchemy,language:python"
3131
else:
3232
raise ValueError(f"Unknown environment provided: `{ENVIRONMENT}`. Must be `development` or `production`.")

logger.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""Custom logger."""
2+
3+
import json
4+
from os import path
5+
from sys import stdout
6+
7+
from loguru import logger
8+
9+
from config import settings
10+
11+
12+
def json_formatter(record: dict) -> str:
13+
"""
14+
Pass raw log to be serialized.
15+
16+
:param dict record: Dictionary containing logged message with metadata.
17+
18+
:returns: str
19+
"""
20+
21+
def serialize(log: dict) -> str:
22+
"""
23+
Parse log message into Datadog JSON format.
24+
25+
:param dict log: Dictionary containing logged message with metadata.
26+
27+
:returns: str
28+
"""
29+
subset = {
30+
"time": log["time"].strftime("%m/%d/%Y, %H:%M:%S"),
31+
"message": log["message"],
32+
"level": log["level"].name,
33+
"function": log.get("function"),
34+
"module": log.get("name"),
35+
}
36+
if log.get("exception", None):
37+
subset.update({"exception": log["exception"]})
38+
return json.dumps(subset)
39+
40+
record["extra"]["serialized"] = serialize(record)
41+
return "{extra[serialized]},\n"
42+
43+
44+
def log_formatter(record: dict) -> str:
45+
"""
46+
Formatter for .log records
47+
48+
:param dict record: Key/value object containing log message & metadata.
49+
50+
:returns: str
51+
"""
52+
if record["level"].name == "TRACE":
53+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #d2eaff>{level}</fg #d2eaff>: <light-white>{message}</light-white>\n"
54+
if record["level"].name == "INFO":
55+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #98bedf>{level}</fg #98bedf>: <light-white>{message}</light-white>\n"
56+
if record["level"].name == "WARNING":
57+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #b09057>{level}</fg #b09057>: <light-white>{message}</light-white>\n"
58+
if record["level"].name == "SUCCESS":
59+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #6dac77>{level}</fg #6dac77>: <light-white>{message}</light-white>\n"
60+
if record["level"].name == "ERROR":
61+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #a35252>{level}</fg #a35252>: <light-white>{message}</light-white>\n"
62+
if record["level"].name == "CRITICAL":
63+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #521010>{level}</fg #521010>: <light-white>{message}</light-white>\n"
64+
return "<fg #5278a3>{time:MM-DD-YYYY HH:mm:ss}</fg #5278a3> | <fg #98bedf>{level}</fg #98bedf>: <light-white>{message}</light-white>\n"
65+
66+
67+
def create_logger() -> logger:
68+
"""
69+
Configure custom logger.
70+
71+
:returns: logger
72+
"""
73+
logger.remove()
74+
logger.add(
75+
stdout,
76+
colorize=True,
77+
catch=True,
78+
level="TRACE",
79+
format=log_formatter,
80+
)
81+
if settings.ENVIRONMENT == "production" and path.isdir(f"/var/log/{settings.APP_NAME}"):
82+
# Datadog JSON logs
83+
logger.add(
84+
f"/var/log/{settings.APP_NAME}/info.json",
85+
format=json_formatter,
86+
rotation="200 MB",
87+
level="TRACE",
88+
compression="zip",
89+
)
90+
# Readable logs
91+
logger.add(
92+
f"/var/log/{settings.APP_NAME}/info.log",
93+
colorize=True,
94+
catch=True,
95+
level="TRACE",
96+
format=log_formatter,
97+
rotation="200 MB",
98+
compression="zip",
99+
)
100+
else:
101+
logger.add(
102+
"./logs/error.log",
103+
colorize=True,
104+
catch=True,
105+
format=log_formatter,
106+
rotation="200 MB",
107+
compression="zip",
108+
level="ERROR",
109+
)
110+
return logger
111+
112+
113+
# Custom logger
114+
LOGGER = create_logger()

0 commit comments

Comments
 (0)