-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlogging_config.py
154 lines (138 loc) · 5.17 KB
/
logging_config.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import logging
import sqlite3
import os
from datetime import datetime
LOG_DB_PATH = os.getenv("LOG_DB_PATH", "logs.db")
MAX_LOG_ENTRIES = 10000 # Maximum number of log entries to keep
class SQLiteHandler(logging.Handler):
"""
Custom logging handler to store log messages in an SQLite database.
"""
def __init__(self, db_path=LOG_DB_PATH, max_entries=MAX_LOG_ENTRIES):
super().__init__()
self.db_path = db_path
self.max_entries = max_entries
self.create_table()
def create_table(self):
"""Creates the logs table if it doesn't exist."""
conn = sqlite3.connect(self.db_path)
try:
cursor = conn.cursor()
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
level TEXT NOT NULL,
message TEXT NOT NULL,
module TEXT,
exception TEXT
)
"""
)
# Create an index on the id column to optimize deletion queries
cursor.execute(
"""
CREATE INDEX IF NOT EXISTS idx_logs_id ON logs (id DESC)
"""
)
conn.commit()
finally:
conn.close()
def emit(self, record):
"""
Inserts a log record into the SQLite database and enforces max log entries.
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# Prepare log data
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
"exception": record.exc_text,
}
# Insert log into database
cursor.execute(
"""
INSERT INTO logs (timestamp, level, message, module, exception)
VALUES (:timestamp, :level, :message, :module, :exception)
""",
log_entry
)
# Enforce maximum number of log entries
cursor.execute("SELECT COUNT(*) FROM logs")
count = cursor.fetchone()[0]
if count > self.max_entries:
# Calculate number of logs to delete
excess = count - self.max_entries
# Delete the oldest 'excess' logs
cursor.execute(
"""
DELETE FROM logs
WHERE id IN (
SELECT id FROM logs
ORDER BY id ASC
LIMIT ?
)
""",
(excess,)
)
conn.commit()
conn.commit()
except Exception as e:
# If logging to the database fails, print to stderr as a last resort
print(f"Failed to log to SQLite database: {e}")
finally:
conn.close()
def setup_logging(debug_mode: bool):
"""
Configures logging handlers based on the debug_mode:
- debug_mode=True : console & SQLite logs at DEBUG level.
- debug_mode=False: console logs at INFO level, skip database logging
(or set DB to CRITICAL if you still want only critical logs stored).
"""
# Get the root logger
logger = logging.getLogger()
# Remove any existing handlers to avoid duplicate logs
while logger.handlers:
logger.removeHandler(logger.handlers[0])
# Set the base logger level according to debug_mode
if debug_mode:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
# 1) Console handler
console_handler = logging.StreamHandler()
if debug_mode:
console_handler.setLevel(logging.DEBUG)
else:
console_handler.setLevel(logging.INFO)
console_formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
# 2) SQLite handler
# Option A: If debug_mode=False, skip adding the SQLite handler entirely
# Option B: Add it but set to CRITICAL (only store critical logs)
if debug_mode:
sqlite_handler = SQLiteHandler(db_path=LOG_DB_PATH, max_entries=MAX_LOG_ENTRIES)
sqlite_handler.setLevel(logging.DEBUG)
sqlite_formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
sqlite_handler.setFormatter(sqlite_formatter)
logger.addHandler(sqlite_handler)
else:
# If you want to store only CRITICAL logs in production, do:
# sqlite_handler = SQLiteHandler(db_path=LOG_DB_PATH, max_entries=MAX_LOG_ENTRIES)
# sqlite_handler.setLevel(logging.CRITICAL)
# sqlite_formatter = logging.Formatter(
# "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# )
# sqlite_handler.setFormatter(sqlite_formatter)
# logger.addHandler(sqlite_handler)
pass