ivan.siregar@gmail.com +6281809456734

Real-Time Log Watcher for Custom Addons

When developing custom addons in Odoo, logging is one of the simplest and most useful ways to understand what your code is actually doing. However, constantly searching through the main Odoo log can become inconvenient, especially when you are working on a specific customization and want to see only the messages generated by your own code.

In this tutorial, we will create a small Odoo custom addon with its own dedicated development log, development.log. We will add a simple logger, create a test button that generates messages at regular intervals, and use Linux's tail -f command to watch those messages appear in real time.

The goal is not to build a complicated logging framework. Instead, we will create a small and practical setup that can be reused while developing and debugging custom Odoo addons.

This video will help you understand, try, and manage the process step by step. The full code is provided below, so feel free to copy and paste it for your own use.

🎥 VIDEO TUTORIAL

Create a Real-Time Log Watcher for Custom Addons

Follow the tutorial below to create a realtime log watcher for your Odoo custom addons.

â–¶ Watch Tutorial
Linux: Create Development Log
sudo touch /var/log/odoo/development.log
sudo chown odoo:odoo /var/log/odoo/development.log
sudo chmod 640 /var/log/odoo/development.log
sudo systemctl restart odoo
                        

Linux: Create Structure
cd /opt/odoo/odoo-server/custom_addons

sudo mkdir -p custom_logger/models
sudo mkdir -p custom_logger/views
sudo mkdir -p custom_logger/security

Linux: Create Files
#see structure
tree custom_logger

#create __manifest__.py
sudo nano custom_logger/__manifest__.py

#create __init__.py
sudo nano custom_logger/__init__.py

#create ./models/__init__.py
sudo nano custom_logger/models/__init__.py

#create ./models/custom_logger.py
sudo nano custom_logger/models/custom_logger.py

#create ./views/custom_logger_views.xml
sudo nano custom_logger/views/custom_logger_views.xml

#create ./security/ir.model.access.csv
sudo nano custom_logger/security/ir.model.access.csv

#restart odoo
systemctl restart odoo
                        

Python: ./custom_logger/__manifest__.py
#./custom_logger/__manifest__.py
{
    'name': 'Custom Logger',
    'version': '18.0.1.0.0',
    'category': 'Tools',
    'depends': [
        'base',
    ],
    'data': [
        'security/ir.model.access.csv',
        'views/custom_logger_views.xml',
    ],
    'installable': True,
    'application': True,
}

Python: ./custom_logger/__init__.py
#./custom_logger/__init__.py
from . import models

Python: #./models/__init__.py
#./models/__init__.py
from . import custom_logger

Python: #./models/custom_logger.py
#./models/custom_logger.py
import logging
import time
from logging.handlers import RotatingFileHandler
from odoo import models

# ============================================================
# Normal Odoo logger
# ============================================================

_logger = logging.getLogger(__name__)

# ============================================================
# Dedicated Development Logger
# ============================================================

DEVELOPMENT_LOG_FILE = '/var/log/odoo/development.log'
development_logger = logging.getLogger('odoo.development')
development_logger.setLevel(logging.INFO)
development_logger.propagate = False

if not development_logger.handlers:
    handler = RotatingFileHandler(
        DEVELOPMENT_LOG_FILE,
        maxBytes=5 * 1024 * 1024,
        backupCount=3,
    )

    formatter = logging.Formatter(
        '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
    )

    handler.setFormatter(formatter)
    development_logger.addHandler(handler)

# ============================================================
# Test Model
# ============================================================

class CustomLogger(models.Model):
    _name = 'custom.logger'
    _description = 'Custom Logger'

    def action_custom_logger(self):

        development_logger.info(
            '================================================'
        )

        development_logger.info(
            'Development custom logger started.'
        )

        for number in range(1, 11):

            development_logger.info(
                'TEST MESSAGE - number: %s',
                number,
            )

            time.sleep(2)

        development_logger.info(
            'Development custom logger finished.'
        )

        development_logger.info(
            '================================================'
        )

        return True

Python: #./views/custom_logger_views.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ===================================================== -->
<!-- Custom Logger Form -->
<!-- ===================================================== -->

<record id="view_custom_logger_form" model="ir.ui.view">
    <field name="name">custom.logger.form</field>
    <field name="model">custom.logger</field>
    <field name="arch" type="xml">

        <form string="Custom Logger">
            <sheet>

                <div class="oe_title">
                    <h1>Custom Logger</h1>
                </div>

                <button
                    name="action_custom_logger"
                    type="object"
                    string="Run Custom Logger"
                    class="btn-primary"
                />

            </sheet>
        </form>

    </field>
</record>


<!-- ===================================================== -->
<!-- Window Action -->
<!-- ===================================================== -->

<record id="action_custom_logger" model="ir.actions.act_window">
    <field name="name">Custom Logger</field>
    <field name="res_model">custom.logger</field>
    <field name="view_mode">form</field>
    <field name="view_id" ref="view_custom_logger_form"/>
</record>

<!-- ===================================================== -->
<!-- Application Menu -->
<!-- ===================================================== -->

<menuitem
    id="menu_custom_logger"
    name="Custom Logger"
    action="action_custom_logger"
    sequence="10"
/>
</odoo>
                        

Python: #./security/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_custom_logger_user,access.custom.logger.user,model_custom_logger,,1,1,1,1

Python: Run the tail

#command to run the tail
sudo tail -f /var/log/odoo/development.log

                        

Python: Clear and Run
#command to clear and run
clear && sudo truncate -s 0 /var/log/odoo/development.log && sudo tail -f /var/log/odoo/development.log

                        

Python: #./models/custom_logger.py (improved)
#./models/custom_logger.py (improved)
...
import random
...

        for number in range(1, 11):

            random_number = random.randint(1, 100)
            
            development_logger.info(
                'TEST MESSAGE - number: %s of random %s',
                number,
                number_random,
            )

            time.sleep(2)

...
Ready to make Odoo development
more transparent
and easier to debug?
When building custom Odoo addons, knowing what your code is doing makes development faster and troubleshooting much easier. With a dedicated development logger and real-time log watcher, you can see your custom code in action without digging through the entire Odoo log.
  Custom addon development?
We know how to make debugging simpler.
We know how to customize it,
and make Odoo work for you... just contact us!
(+62) 81809456734
www.bandung-odoo.com