Zope 5 Log To Error Log From Python Script

30 Views Asked by At

Normally when an exception occurs, Zope automatically logs it to the error_log via the Products.SiteErrorLog package, however I have a python script with a try/except block because I need to return json whether or not the script succeeds. Unfortunately, the exception block overrides Zope's default logging to the error_log, and since I cannot use raise, because it halts execution of the rest of the script (including, a finally block or the rest of the exception block), I need a way to make Zope still log the error to the error_log.

From what I can tell this is done via the SiteErrorLog.raising() method, and since in restricted python I can't find a way to allow the use of the raising method, even though I have allowed the entire SiteErrorLog module and the SiteErrorLog class, I used an external method, but can't get it to work.

For reference, in my __init__.py to allow the module and class I used:

allow_module(Products.SiteErrorLog.SiteErrorLog)
from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog
allow_class(SiteErrorLog)

which does allow the SiteErrorLog class and module but does not allow the use of the raising method from within the ZMI via a python script.

If using SiteErrorLog is not the correct answer and there's an easier way, I'm all ears.

Here's an example of my python script:

import json

try:
    context.my_zsql_method()
    def returnjson():
        value = {"output": "success"}
        return json.dumps(value)
    return returnjson()

except Exception as e:
    def returnjson():
        value = {"output": "failure"}
        return json.dumps(value)
    return returnjson()

I do not want a custom error message or anything other than the standard exception error that is normally logged to the zope error_log, and I only want it to be logged in the except block.

As I mentioned, I tried writing an external method so I could use the SiteErrorLog.raising() like this:

from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog

def logError(error):
    errorType = type(error).__name__
    errorStr = str(error)
    error_info = (errorType, errorStr, None)
    SiteErrorLog.raising(None, error_info)

and updating my except block like this:

except Exception as e:
    context.logError(e)
    def returnjson():
        value = {"output": "failure"}
        return json.dumps(value)
    return returnjson()

but nothing logs to the error log. SiteErrorLog.raising() requires 2 parameters (self, info) and supposedly calling the external method is automatically supposed to pass self, but that doesn't seem to be happening. I've tried passing context.error_log into the external method (doesn't work), as well using SiteErrorLog as self (doesn't work).

I saw an answer to a question about using both raise and return from a long time ago saying to use a finally block, so of course, I also tried:

except Exception as e:
    raise
finally:
    def returnjson():
        value = {"output": "failure"}
        return json.dumps(value)
    return returnjson()

even though I knew that was incorrect. Of course, as soon as raise is called, the rest of the script stops all execution so the json is never returned, but I thought I'd at least give it a try.

Again, I do not want to log to a log file, write a custom log message, or anything else. I just want the exception error to be logged to zope's error log as normal, while still allowing me to return json.

Seems like this should be a lot simpler than everything I'm doing, but I can't find an answer anywhere and would love some assistance. Thanks!

2

There are 2 best solutions below

1
Rafa Bermúdez On

Just from my reply in https://community.plone.org/t/zope-5-logging-to-error-log/18701/5

You can use python logging:

from logging import getLogger

logger = getLogger("TESTING LOGS")

logger.info("This is a info log entry")
logger.warning("This is a warning")
logger.error("This is an error")
logger.critical("This is a critical error")



2024-02-01 08:36:37,263 INFO    [TESTING LOGS:5][waitress-2] This is a info log entry
2024-02-01 08:36:37,271 WARNING [TESTING LOGS:6][waitress-2] This is a warning
2024-02-01 08:36:37,273 ERROR   [TESTING LOGS:7][waitress-2] This is an error
2024-02-01 08:36:37,274 CRITICA [TESTING LOGS:8][waitress-2] This is a critical error
0
kittonian On

I got it all working. Here's how to do it (it's actually quite simple).

  1. Create an external method called log_error like this:
import sys
from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog

def logError(error_context):
        SiteErrorLog.raising(error_context, sys.exc_info())
  1. In your ZMI based python script, inside the except block write this (assuming log_error resides within the context of your python script - in my case I placed it in the site's root folder so I could access it from anywhere in the site): context.log_error(context.error_log)

So, for a full example of using a try/except you would write something like this:

import json

try:
    # Whatever code you wish to run goes here
    def returnjson():
        value = {"output": "success"}
        return json.dumps(value)
    return returnjson()
except:
    context.log_error(context.error_log)
    def returnjson():
        value = {"output": "failure"}
        return json.dumps(value)
    return returnjson()

That will log the error to the error_log just like it always does and still provide you a way to return whatever you wish from the python script.