Skip to content

Commit d4fd74d

Browse files
feat: Add file-based audit logging with rotation
- Add configuration UI for file logging settings - Implement RotatingFileHandler with JSON Lines format - Support dual-mode: file or database logging - Skip chatter messages when file logging enabled - Add 15 comprehensive tests for all scenarios - Maintain full backward compatibility (defaults to DB mode)
1 parent cf9a829 commit d4fd74d

File tree

14 files changed

+1286
-8
lines changed

14 files changed

+1286
-8
lines changed

.cursor/plans/audit-log-file-migration-plan.md

Lines changed: 385 additions & 0 deletions
Large diffs are not rendered by default.

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,15 @@ docs/_build/
7979

8080
# Local release planning files (ignored)
8181
.release/
82+
83+
# Cursor generated files
84+
.cursor/generated/
85+
.cursor/notes/
86+
.cursor/temp/
87+
.cursor/chat/
88+
.cursor/composer/
89+
.cursor/generated/
90+
.cursor/memos/
91+
.cursor/*.db
92+
.cursor/*.json
93+
.cursor/*.md

spp_audit_log/__manifest__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
"depends": ["base", "mail", "g2p_registry_membership"],
1313
"external_dependencies": {},
1414
"data": [
15+
"data/ir_config_parameter_data.xml",
1516
"security/audit_log_security.xml",
1617
"security/ir.model.access.csv",
1718
"views/spp_audit_rule_views.xml",
1819
"views/spp_audit_log_views.xml",
20+
"views/res_config_settings_views.xml",
1921
],
2022
"assets": {},
2123
"demo": [],
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo>
3+
4+
<!-- Default configuration for audit log file settings -->
5+
<record id="audit_log_to_file_default" model="ir.config_parameter">
6+
<field name="key">spp.audit_log_to_file</field>
7+
<field name="value">False</field>
8+
</record>
9+
10+
<record id="audit_log_file_path_default" model="ir.config_parameter">
11+
<field name="key">spp.audit_log_file_path</field>
12+
<field name="value">/var/log/odoo/audit.log</field>
13+
</record>
14+
15+
<record id="audit_log_file_max_bytes_default" model="ir.config_parameter">
16+
<field name="key">spp.audit_log_file_max_bytes</field>
17+
<field name="value">10</field>
18+
</record>
19+
20+
<record id="audit_log_file_backup_count_default" model="ir.config_parameter">
21+
<field name="key">spp.audit_log_file_backup_count</field>
22+
<field name="value">5</field>
23+
</record>
24+
25+
</odoo>

spp_audit_log/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from . import spp_audit_rule
22
from . import spp_audit_log
33
from . import group
4+
from . import res_config_settings
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from odoo import fields, models
2+
3+
4+
class ResConfigSettings(models.TransientModel):
5+
_inherit = "res.config.settings"
6+
7+
audit_log_to_file = fields.Boolean(
8+
string="Enable File Logging",
9+
config_parameter="spp.audit_log_to_file",
10+
help="Enable logging audit records to JSON file instead of database",
11+
)
12+
13+
audit_log_file_path = fields.Char(
14+
string="Audit Log File Path",
15+
default="/var/log/odoo/audit.log",
16+
config_parameter="spp.audit_log_file_path",
17+
help="Full path to the audit log file (JSON Lines format)",
18+
)
19+
20+
audit_log_file_max_bytes = fields.Integer(
21+
string="Max File Size (MB)",
22+
default=10,
23+
config_parameter="spp.audit_log_file_max_bytes",
24+
help="Maximum size of log file in megabytes before rotation",
25+
)
26+
27+
audit_log_file_backup_count = fields.Integer(
28+
string="Backup Count",
29+
default=5,
30+
config_parameter="spp.audit_log_file_backup_count",
31+
help="Number of backup files to keep during rotation",
32+
)

spp_audit_log/models/spp_audit_rule.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from odoo import _, api, fields, models
44
from odoo.exceptions import ValidationError
55

6-
from ..tools import audit_decorator
6+
from ..tools import audit_decorator, is_file_logging_enabled, log_audit_to_file
77

88

99
class SppAuditRule(models.Model):
@@ -255,8 +255,8 @@ def get_audit_log_vals(self, res_id, method, data):
255255

256256
def log(self, method, old_values=None, new_values=None):
257257
"""
258-
The function logs changes made to a model's records by creating an audit log entry with
259-
information about the user, model, record, method, and data.
258+
The function logs changes made to a model's records by creating an audit log entry.
259+
Logs are written to file if file logging is enabled, otherwise to database.
260260
261261
:param method: The "method" parameter is a string that represents the action or method being
262262
logged. It could be a create, write, or delete action, for example
@@ -272,9 +272,18 @@ def log(self, method, old_values=None, new_values=None):
272272
if old_values or new_values:
273273
fields_to_log = self.field_to_log_ids.mapped("name")
274274
data = self._format_data_to_log(old_values, new_values, fields_to_log)
275-
audit_log = self.env["spp.audit.log"].sudo()
276-
for rec in self:
277-
for res_id in data:
278-
audit_log_vals = rec.get_audit_log_vals(res_id, method, data)
279-
audit_log.create(audit_log_vals)
275+
276+
# Check if file logging is enabled
277+
if is_file_logging_enabled(self.env):
278+
# Write to file for each audit rule and resource
279+
for rec in self:
280+
for res_id in data:
281+
log_audit_to_file(self.env, rec, method, res_id, data[res_id])
282+
else:
283+
# Fallback to database logging
284+
audit_log = self.env["spp.audit.log"].sudo()
285+
for rec in self:
286+
for res_id in data:
287+
audit_log_vals = rec.get_audit_log_vals(res_id, method, data)
288+
audit_log.create(audit_log_vals)
280289
return

0 commit comments

Comments
 (0)