⚠️ Warning: tested on Odoo 11.0, 13.0, 15.0, 16.0, 17.0, and 18.0.

⚠️ Warning: Seq logging captures user data, starting the service may lock the users and partners tables, which can block or even crash updates. To prevent this, temporarily disable Seq logging during any update operations.

Install the pygelf package

⚠️ Warning: the latest release of pygelf is version 0.4.2, and it has not been updated since October 2021.

Install the pygelf package using pip:

pip install pygelf

Update the Odoo configuration

In the __init__(self, fname=None) method from the configmanager class, add this line to introduce a new logging option for Seq::

group.add_option('--log-seq', dest='log_seq', help="Logging to seq")

When starting the Odoo server, you can specify the Seq server in one of two ways:

  • Command Line:
    ./odoo-bin --log-seq=seq-server:port
    
  • Configuration File:
    Add the following to your odoo.conf file:
    log_seq = seq-server:port
    

Modify the Odoo Logger

Add Custom Logging Filters and Formatter. In the file odoo/netsvc.py , include the following classes:

class uidFilterSeq(logging.Filter):
    def filter(self, record):
        if odoo and odoo.http and odoo.http.request:
            if odoo.http.request.uid or odoo.http.request.session.uid:
                if odoo.http.request.uid:
                    user_id = odoo.http.request.uid
                elif odoo.http.request.session.uid:
                    user_id = odoo.http.request.session.uid
                if odoo.http.request.uid or odoo.http.request.session.uid:
                    record.user_id = user_id
                    # res = get_partner_user(user_id)
                    # if res:
                    #     record.user_partner = {'user_id': res['user_id'],
                    #                            'user_login': res['user_login'],
                    #                            'partner_id': res['partner_id'],
                    #                            'partner_name': res['partner_name']}
            if odoo.http.request.httprequest.cookies and 'visitor_uuid' in odoo.http.request.httprequest.cookies:
                record.visitor_id = odoo.http.request.httprequest.cookies['visitor_uuid']
            if odoo.http.request.httprequest.remote_addr:
                record.client_address = odoo.http.request.httprequest.remote_addr
        return True

class PerfFilterSeq(logging.Filter):
    def filter(self, record):
        if hasattr(threading.current_thread(), "query_count"):
            query_count = threading.current_thread().query_count
            query_time = threading.current_thread().query_time
            perf_t0 = threading.current_thread().perf_t0
            remaining_time = time.time() - perf_t0 - query_time
            record.perf_info = {'query_count': "%d" % query_count,
                                'query_time': "%.3f" % query_time,
                                'remaining_time': "%.3f" % remaining_time}
            delattr(threading.current_thread(), "query_count")
        return True

class DBFormatterSeq(logging.Formatter):
    def format(self, record):
        record.pid = os.getpid()
        return logging.Formatter.format(self, record)

Integrate the Seq Logging Handler. After the blocks handling tools.config['syslog']: and elif tools.config['logfile']:, add this snippet to configure Seq logging:

elif tools.cronfig['log_seq']:
    loghost = tools.config['log_seq']

    def record_factory_seq(*args, **kwargs):
        record = old_factory(*args, **kwargs)
        # We need to change the runbot to info level because seq don't have a runbot level
        if record.levelno == logging.RUNBOT:
            record.levelno = logging.INFO
        return record

    logging.setLogRecordFactory(record_factory_seq)
    handler = GelfUdpHandler(
        host=str(loghost.split(':')[0]), port=int(loghost.split(':')[1]),
        include_extra_fields=True, debug=True
    )

Then, between the block that checks for a POSIX system with a TTY stream and the else: clause, insert the following code:

elif isinstance(handler, GelfUdpHandler):
    formatter = DBFormatterSeq(format)
    perf_filter = PerfFilterSeq()
    handler.addFilter(uidFilterSeq())