Upload odoo_log_viewer module

This commit is contained in:
eman 2024-07-28 10:28:36 +03:00
parent 7d4a351761
commit 4da7904bdd
11 changed files with 191 additions and 0 deletions

View File

@ -0,0 +1,2 @@
from . import models
from . import controllers

View File

@ -0,0 +1,22 @@
{
'name': 'Odoo Log Viewer',
'version': '17.0.0.1.0',
'category': 'Tools',
'summary': 'View Odoo log in real-time as a web page',
'sequence': 10,
'author': 'Abdelrahman Eltayar',
'depends': ['base', 'web'],
'data': [
'views/log_viewer_template.xml',
'views/assets.xml',
'data/ir_config_parameter.xml',
],
'assets': {
'web.assets_backend': [
'custom_log_viewer/static/src/css/log_viewer_style.css',
],
},
'installable': True,
'application': False,
'auto_install': False,
}

View File

@ -0,0 +1 @@
from . import main

View File

@ -0,0 +1,25 @@
from odoo import http, _
from odoo.http import request
class LogViewer(http.Controller):
@http.route('/log_viewer', type='http', auth='public')
def log_viewer(self, password=None):
correct_password = request.env['ir.config_parameter'].sudo().get_param('odoo_log_viewer.password')
if password == correct_password:
return request.render('odoo_log_viewer.log_viewer_template', {})
else:
return request.render('odoo_log_viewer.password_template', {})
@http.route('/log_viewer/get_logs', type='json', auth='public')
def get_logs(self, password=None):
correct_password = request.env['ir.config_parameter'].sudo().get_param('odoo_log_viewer.password')
if password == correct_password:
log_entries = request.env['log.handler.manager'].sudo().get_log_entries()
return {'log_content': '\n'.join(log_entries)}
else:
return {'error': 'Invalid password'}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="log_viewer_password" model="ir.config_parameter">
<field name="key">odoo_log_viewer.password</field>
<field name="value">$ecret@)24</field>
</record>
</data>
</odoo>

View File

@ -0,0 +1 @@
from . import log_handler

View File

@ -0,0 +1,46 @@
import logging
from odoo import api, models
from werkzeug._internal import _log
class MemoryLogHandler(logging.Handler):
def __init__(self, max_entries=1000):
super().__init__()
self.max_entries = max_entries
self.entries = []
def emit(self, record):
if '/log_viewer/get_logs' in getattr(record, 'message', ''):
return
self.entries.append(self.format(record))
if len(self.entries) > self.max_entries:
self.entries.pop(0)
class LogHandlerManager(models.AbstractModel):
_name = 'log.handler.manager'
_description = 'Log Handler Manager'
@api.model
def _get_memory_handler(self):
if not hasattr(LogHandlerManager, '_memory_handler'):
LogHandlerManager._memory_handler = MemoryLogHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
LogHandlerManager._memory_handler.setFormatter(formatter)
logging.getLogger().addHandler(LogHandlerManager._memory_handler)
def custom_log(type, message, *args, **kwargs):
if '/log_viewer/get_logs' not in message:
_log(type, message, *args, **kwargs)
import werkzeug
werkzeug._internal._log = custom_log
return LogHandlerManager._memory_handler
@api.model
def _register_hook(self):
self._get_memory_handler()
@api.model
def get_log_entries(self):
return self._get_memory_handler().entries

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,12 @@
form label {
font-weight: 700;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
body {
background-color: #464646;
}

View File

@ -0,0 +1,7 @@
<odoo>
<template id="assets" name="odoo_log_viewer assets" inherit_id="web.assets_frontend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/odoo_log_viewer/static/src/css/log_viewer_style.css"/>
</xpath>
</template>
</odoo>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="password_template" name="Log Viewer Password">
<t t-call="web.layout">
<t t-call-assets="odoo_log_viewer.assets"/>
<t t-set="title">Log Viewer - Login</t>
<div class="container py-5">
<div class="card border-0 mx-auto bg-100 o_database_list" style="max-width: 300px;">
<div class="card-body">
<h2 class="card-title text-center mb-4">Log Viewer</h2>
<form action="/log_viewer" method="get" class="oe_login_form">
<div class="form-group field-login">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" name="password" autofocus="autofocus" required="required" autocomplete="off"/>
</div>
<div class="d-grid gap-2 mt-4">
<button type="submit" class="btn btn-primary btn-block">Log In</button>
</div>
</form>
</div>
</div>
</div>
</t>
</template>
<template id="log_viewer_template" name="Log Viewer">
<t t-call="web.layout">
<t t-set="title">Odoo Log Viewer</t>
<div class="container">
<h1>Odoo Log</h1>
<pre id="log-content"></pre>
</div>
<script type="text/javascript">
var password = "<t t-esc="request.params.get('password')"/>";
function updateLogs() {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/log_viewer/get_logs', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status === 200) {
var result = JSON.parse(xhr.responseText);
if (result.error) {
alert(result.error);
} else {
var logContent = document.getElementById('log-content');
if (logContent) {
logContent.textContent = result.result.log_content;
}
}
}
};
xhr.send(JSON.stringify({
jsonrpc: "2.0",
method: "call",
params: {password: password},
id: new Date().getTime()
}));
}
// Update logs immediately and then every 3 seconds
updateLogs();
setInterval(updateLogs, 3000);
</script>
</t>
</template>
</odoo>