Upload odoo_log_viewer module
This commit is contained in:
parent
7d4a351761
commit
4da7904bdd
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import models
|
||||||
|
from . import controllers
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
from . import main
|
||||||
|
|
@ -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'}
|
||||||
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
from . import log_handler
|
||||||
|
|
@ -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 |
|
|
@ -0,0 +1,12 @@
|
||||||
|
form label {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #464646;
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
Loading…
Reference in New Issue