Gradio and logging library conflicts

Hello there!

I am trying to combine gradio with a backend based on python classes that inherit from a parent class that allow them to have customized logs and clean the context manager after finishing the execution of the class.

This is a snippet of the error I get when trying to do so:

``
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\site-packages\requests\sessions.py”, line 589, in request
resp = self.send(prep, **send_kwargs)
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\site-packages\requests\sessions.py”, line 703, in send
r = adapter.send(request, **kwargs)
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\site-packages\requests\adapters.py”, line 486, in send
resp = conn.urlopen(
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\site-packages\urllib3\connectionpool.py”, line 714, in urlopen
httplib_response = self._make_request(
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\site-packages\urllib3\connectionpool.py”, line 473, in make_request
log.debug(
Message: ‘%s://%s:%s “%s %s %s” %s %s’
Arguments: (‘https’, ‘api.gradio.app’, 443, ‘POST’, ‘/gradio-launched-telemetry/’, ‘HTTP/1.1’, 200, None)
— Logging error —
Traceback (most recent call last):
File "C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init
.py", line 440, in format
return self.format(record)
File "C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init
.py", line 436, in _format
return self._fmt % values
KeyError: ‘process_name’

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging\handlers.py”, line 73, in emit
if self.shouldRollover(record):
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging\handlers.py”, line 196, in shouldRollover
msg = “%s\n” % self.format(record)
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init_.py”, line 943, in format
return fmt.format(record)
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init_.py”, line 681, in format
s = self.formatMessage(record)
File “C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init_.py”, line 650, in formatMessage
return self.style.format(record)
File "C:\Users\AnaGonzalezGuerra\anaconda3\envs\RPA\lib\logging_init
.py", line 442, in format
raise ValueError(‘Formatting field not found in record: %s’ % e)
ValueError: Formatting field not found in record: ‘process_name’

``
I cannot send the full message because it is an infinite loop. You can see that is saying that cannot reach the process_name argument , this is because I am adding some extra arguments in the LogDBHandler class (I customized the class adding some arguments and logging to a DB).

This happens when I try to call the following class from main:

``
class SimpleGradioInterface(activities):
def init(self, process, log_level=None):
super().init(process = process, log_level = log_level) # Call the parent constructor
self.interface = self.create_interface()

@staticmethod
def simple_function(word=""):
    return "hi"

def create_interface(self):
    
    interface = gr.Interface(
        fn=self.simple_function,
        inputs=gr.Textbox(label="Input", elem_classes="textbox"),
        outputs=gr.Textbox(label="Output", elem_classes="textbox")
    )
    
    return interface

def launch(self):
    
    self.interface.launch()

``
Using this code in main:

``
if name == ‘main’:

gr_interface = SimpleGradioInterface(process=process_name, log_level='DEBUG')
 gr_interface.launch()

``

My best guest is there is some kind of conflict between python context manager definition, the definition I have in my parent class and the one defined in gradio, because if I do this test it seems possible the combination with the backend logs:

``
class HitActivity(activities):
@log_decorator()
def say_hello(self):
print(“Hello from HitActivity!”)
return “Greeting done!”

def wrapped_hit_activity_function(_=None):
    activity = HitActivity()
    try:
        activity.__enter__()
        result = activity.say_hello()
    finally:
        activity.__exit__(None, None, None)
    return result
    
interface = gr.Interface(

    fn=wrapped_hit_activity_function,
    inputs=gr.Textbox(label="Input", elem_classes="textbox"),
    outputs=gr.Textbox(label="Output", elem_classes="textbox")
    )
interface.launch()

``
And then I get the expected output:

``
2023-10-16 17:38:36,432 - INFO - RPA Highlighter - HitActivity - Running: [Level 1] HitActivity is running - anagongue

2023-10-16 17:38:36,433 - DEBUG - RPA Highlighter - HitActivity - Running: [Level 1] Method say_hello running - anagongue

2023-10-16 17:38:36,435 - DEBUG - RPA Highlighter - HitActivity - Ended: [Level 1] Method say_hello ended successfully - anagongue

2023-10-16 17:38:36,437 - INFO - RPA Highlighter - HitActivity - Ended: [Level 1] HitActivity ended - anagongue
``
Is there some kind of consideration I should have about how gradio uses the python context manager? In my case I am using this code for defining it in the parent class and make the child classes inherit:

``
class activities(LoggingMixin, EmailNotificationMixin):
‘’’
activities class is the parent class of
the set of activities
that forms the RPA process.
It inherits from Mixins LogginMixin and EmailNotificationMixin.
All activities inherit the same arguments:
process_name, activity (activity name) and status (Start,
Running, Ended)

'''

_activity_stack = []  # list to be used to stack activities 
                      # and keep a record of current activities in use.
                      # This list allows us to organize activity log sublevels
_stack_lock = Lock() # lock object

def __init__(self, process = process_name, log_level=None):
    self.process = process  # RPA process name
    # Activity name of the RPA process, step of the process
    # automatically set to the name of the class
    self.activity = self.__class__.__name__
    self.configure_logger(log_level)
   
def __enter__(self):
    with self._stack_lock:  # Acquire the lock
        self._activity_stack.append(self.activity)  # add activity to the stack
    self.log_start()
    self.log_running()
    return self

def __exit__(self, exc_type, exc_val, exc_tb):
    
    if exc_type and issubclass(exc_type, CriticalException):  # Check if it's a critical exception
        self.send_error_notification(exc_type, exc_val, exc_tb)
        with self._stack_lock:  # Acquire the lock
            self._activity_stack.pop()  # remove activity from stack to release resources
        sys.exit(f"Terminating due to critical error: {exc_val}")

    elif exc_type and issubclass(exc_type, GeneralException):
        self.send_error_notification(exc_type, exc_val, exc_tb)
        with self._stack_lock:  # Acquire the lock
            self._activity_stack.pop()  # remove activity from stack to release resources

    elif exc_type and issubclass(exc_type, WarningException):
        with self._stack_lock:  # Acquire the lock
            self._activity_stack.pop()  # remove activity from stack to release resources
    else:
        self.log_end(exc_type, exc_val, exc_tb)
        with self._stack_lock:  # Acquire the lock
            self._activity_stack.pop()  # remove activity from stack to release resources

``

Best regards,
Ana González Guerra

1 Like