Comments (7)
Hi @Thermaltech, thanks for reaching out!
I'm struggling to reproduce the error. Your code is missing some imports like modules
, ui_footer
and ui_header
. So I reduced it to this:
import logging
from time import localtime, strftime
from nicegui import ui
class LogElementHandler(logging.Handler):
def __init__(self, element: ui.log, level: int = logging.NOTSET) -> None:
self.element = element
super().__init__(level)
def emit(self, record: logging.LogRecord) -> None:
try:
msg = f'{strftime("%A, %B %d, %Y, %H:%M:%S", localtime(record.created))} - {record.levelname} - {record.name} - {record.message}'
self.element.push(msg)
except Exception:
self.handleError(record)
@ui.page('/')
def page():
ui_logger = logging.getLogger('wm')
log = ui.log(max_lines=10)
ui_logger.addHandler(LogElementHandler(log))
ui.button('Clear', on_click=log.clear)
But I don't get any exception when closing the page. Maybe because there is no log happening?
from nicegui.
@falkoschindler I saw this log on our https://nicegui.io website:
WARNING:nicegui:Client has been deleted but is still being used. This is most likely a bug in your application code. See https://github.com/zauberzeug/nicegui/issues/3028 for more information.
Stack (most recent call last):
File "/app/main.py", line 62, in <module>
ui.run(uvicorn_reload_includes='*.py, *.css, *.html', reload=not on_fly, reconnect_timeout=10.0)
File "/app/nicegui/ui_run.py", line 177, in run
Server.instance.run()
await super().__call__(scope, receive, send)
--- Logging error ---
Traceback (most recent call last):
File "/app/website/documentation/content/log_documentation.py", line 33, in emit
self.element.push(msg)
File "/app/nicegui/elements/log.py", line 29, in push
self.remove(0)
File "/app/nicegui/element.py", line 525, in remove
self.client.remove_elements(elements)
File "/app/nicegui/client.py", line 310, in remove_elements
del self.elements[element_id]
~~~~~~~~~~~~~^^^^^^^^^^^^
from nicegui.
Falko,
Thanks for the quick reply. The ui_header and ui_footer didn't have anything to do with the problem at hand, so I didn't include them. Sorry if it caused any confusion.
The logging events are happening all over the program in different modules, and are being monitored / displayed by this page by attaching to the global logger "wm" by name. So the LogElementHandler would still be registered with in the logging module, and would still be firing events...
Honestly, what I think is happening is due to my software not being aware that the page is gone, and the logging handler is still trying to send / delete data for the nicegui logging element by way of the LogElementHandler, what I may have to do is add and remove the handler based on client connect disconnect, or just push a copy of the log file on demand.
In short, I may be misguided in my thoughts as to how the nicegui log implementation is intended to be used. I am quite sure if all the logging is happening on the page that is pushing the data to the same page, all would be OK. This would mean that when the page is closed, the events inherently stop.
Since the logging events are happening elsewhere within my program, and the logging handler is attempting to push / remove data from a now non-existent element, is where the problem lies.... What has me a little confused is that the logging events being pushed to a non-existent logging element does not cause an error, but when the following code executes to remove old items from the log element, all hell breaks loose...
while self.max_lines is not None and len(self.default_slot.children) > self.max_lines:
self.remove(0)
Is there some simple method that could be used to determine when the page is closed so that I can automatically remove the LogElementHandler instance?
Cheers.
from nicegui.
Just a FYI. Problem solved by addming client connect / disconnect handlers to automatically add and remove the LogElemenHandler to the logger. The nicegui Client class made this really easy. Thanks for making a great library!
Revised code:
import logging
from time import strftime, localtime
from nicegui import ui, Tailwind, Client
import modules.tts_config_loader as cfg
import ui_header
import ui_footer
logger = logging.getLogger('wm.ui.event_log')
class LogElementHandler(logging.Handler):
"""A logging handler that emits messages to a log element."""
def __init__(self, element: ui.log, level: int = logging.NOTSET) -> None:
self.element = element
super().__init__(level)
def emit(self, record: logging.LogRecord) -> None:
try:
msg = f'{strftime("%A, %B %d, %Y, %H:%M:%S", localtime(record.created))} - {record.levelname} - {record.name} - {record.message}'
self.element.push(msg)
except Exception:
self.handleError(record)
'''
UI - EVENT_LOG
'''
@ui.page('/event_log')
def content(client: Client):
wm_config = cfg.configs['wm'].config
def connected():
# Add log event handler
logging.getLogger('wm').addHandler(log_handler)
def disconnected():
# Remove log event handler
logging.getLogger('wm').removeHandler(log_handler)
def clear_log():
logger.debug(f'Client cleared local event log with id: {client.id}')
log_element.clear()
client.on_connect(connected)
client.on_disconnect(disconnected)
# Page Configuration
ui.page_title(f"{wm_config['SETTINGS']['TITLE']} - Event Log")
ui_header.content()
ui_footer.content()
with ui.card().classes('w-full'):
# Title
lbl_log = ui.label('Event Log')
lbl_log.tailwind('font-bold')
# Log viewer
log_element = ui.log(max_lines = 50)
log_element.tailwind('h-[500px]')
log_handler : LogElementHandler = LogElementHandler(log_element)
# Clear log button
ui.button('CLEAR EVENT LOG', on_click=lambda : clear_log())
from nicegui.
Thanks for the clarification, @Thermaltech! Just recently we ran into a similar problem. Let me explain:
When you register some UI code (like adding a line of text to ui.log
) to some long-living non-UI event, you're basically creating a memory leak. The event holds a reference to the UI code, which includes the UI elements which in turn hold a reference to the client. When the client disconnects, it gets removed from NiceGUI's client dictionary and all its child elements get removed, too. But the reference from the event remains in memory and the client is still receiving events. This would remain unnoticed, because nobody cares about a disconnected client being updated in the background. But the memory consumption grows with every newly disconnected client. And when deleting UI elements (which happens when reaching the maximum number of lines in ui.log
), a KeyError happens because the client had already lost all its children during the disconnect.
Since a memory leak can be pretty critical and it happens so easily, we should implement some safety net. We already experimented with detecting access to any client attribute after it disconnected, but this felt like a bit too strict. Something similar would be a useful feature though.
from nicegui.
There is some other kind of log entries appearing which may be related:
lax [info]ERROR:nicegui:'90452107-61de-4c71-9b05-d5b9050d15f4'
lax [info]Traceback (most recent call last):
lax [info] File "/app/nicegui/background_tasks.py", line 52, in _handle_task_result
lax [info] task.result()
lax [info] File "/app/nicegui/client.py", line 265, in handle_disconnect
lax [info] self.delete()
lax [info] File "/app/nicegui/client.py", line 324, in delete
lax [info] del Client.instances[self.id]
lax [info] ~~~~~~~~~~~~~~~~^^^^^^^^^
lax [info]KeyError: '90452107-61de-4c71-9b05-d5b9050d15f4'
lax [info]--- Logging error ---
lax [info]Traceback (most recent call last):
lax [info] File "/app/nicegui/background_tasks.py", line 52, in _handle_task_result
lax [info] task.result()
lax [info] File "/app/nicegui/client.py", line 265, in handle_disconnect
lax [info] self.delete()
lax [info] File "/app/nicegui/client.py", line 324, in delete
lax [info] del Client.instances[self.id]
lax [info] ~~~~~~~~~~~~~~~~^^^^^^^^^
lax [info]KeyError: '90452107-61de-4c71-9b05-d5b9050d15f4'
lax [info]During handling of the above exception, another exception occurred:
lax [info]Traceback (most recent call last):
lax [info] File "/app/website/documentation/content/log_documentation.py", line 33, in emit
lax [info] self.element.push(msg)
lax [info] File "/app/nicegui/elements/log.py", line 29, in push
lax [info] self.remove(0)
lax [info] File "/app/nicegui/element.py", line 525, in remove
lax [info] self.client.remove_elements(elements)
lax [info] File "/app/nicegui/client.py", line 310, in remove_elements
lax [info] del self.elements[element_id]
lax [info] ~~~~~~~~~~~~~^^^^^^^^^^^^
lax [info]KeyError: 221
lax [info]Call stack:
lax [info] File "/app/main.py", line 62, in <module>
lax [info] ui.run(uvicorn_reload_includes='*.py, *.css, *.html', reload=not on_fly, reconnect_timeout=10.0)
lax [info] File "/app/nicegui/ui_run.py", line 177, in run
lax [info] Server.instance.run()
lax [info] File "/app/nicegui/server.py", line 36, in run
lax [info] super().run(sockets=sockets)
lax [info] File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 65, in run
lax [info] return asyncio.run(self.serve(sockets=sockets))
lax [info] File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
lax [info] return runner.run(main)
lax [info] File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
lax [info] return self._loop.run_until_complete(task)
lax [info] File "/app/nicegui/background_tasks.py", line 56, in _handle_task_result
lax [info] core.app.handle_exception(e)
lax [info] File "/app/nicegui/app/app.py", line 118, in handle_exception
lax [info] result = handler() if not inspect.signature(handler).parameters else handler(exception)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1524, in exception
lax [info] self.error(msg, *args, exc_info=exc_info, **kwargs)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1518, in error
lax [info] self._log(ERROR, msg, args, **kwargs)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1634, in _log
lax [info] self.handle(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1644, in handle
lax [info] self.callHandlers(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1706, in callHandlers
lax [info] hdlr.handle(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 978, in handle
lax [info] self.emit(record)
lax [info] File "/app/website/documentation/content/log_documentation.py", line 35, in emit
lax [info] self.handleError(record)
lax [info]Message: KeyError('90452107-61de-4c71-9b05-d5b9050d15f4')
lax [info]Arguments: ()
lax [info]--- Logging error ---
lax [info]Traceback (most recent call last):
lax [info] File "/app/nicegui/background_tasks.py", line 52, in _handle_task_result
lax [info] task.result()
lax [info] File "/app/nicegui/client.py", line 265, in handle_disconnect
lax [info] self.delete()
lax [info] File "/app/nicegui/client.py", line 324, in delete
lax [info] del Client.instances[self.id]
lax [info] ~~~~~~~~~~~~~~~~^^^^^^^^^
lax [info]KeyError: '90452107-61de-4c71-9b05-d5b9050d15f4'
lax [info]During handling of the above exception, another exception occurred:
lax [info]Traceback (most recent call last):
lax [info] File "/app/website/documentation/content/log_documentation.py", line 33, in emit
lax [info] self.element.push(msg)
lax [info] File "/app/nicegui/elements/log.py", line 29, in push
lax [info] self.remove(0)
lax [info] File "/app/nicegui/element.py", line 525, in remove
lax [info] self.client.remove_elements(elements)
lax [info] File "/app/nicegui/client.py", line 310, in remove_elements
lax [info] del self.elements[element_id]
lax [info] ~~~~~~~~~~~~~^^^^^^^^^^^^
lax [info]KeyError: 68440
lax [info]Call stack:
lax [info] File "/app/main.py", line 62, in <module>
lax [info] ui.run(uvicorn_reload_includes='*.py, *.css, *.html', reload=not on_fly, reconnect_timeout=10.0)
lax [info] File "/app/nicegui/ui_run.py", line 177, in run
lax [info] Server.instance.run()
lax [info] File "/app/nicegui/server.py", line 36, in run
lax [info] super().run(sockets=sockets)
lax [info] File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 65, in run
lax [info] return asyncio.run(self.serve(sockets=sockets))
lax [info] File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
lax [info] return runner.run(main)
lax [info] File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
lax [info] return self._loop.run_until_complete(task)
lax [info] File "/app/nicegui/background_tasks.py", line 56, in _handle_task_result
lax [info] core.app.handle_exception(e)
lax [info] File "/app/nicegui/app/app.py", line 118, in handle_exception
lax [info] result = handler() if not inspect.signature(handler).parameters else handler(exception)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1524, in exception
lax [info] self.error(msg, *args, exc_info=exc_info, **kwargs)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1518, in error
lax [info] self._log(ERROR, msg, args, **kwargs)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1634, in _log
lax [info] self.handle(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1644, in handle
lax [info] self.callHandlers(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 1706, in callHandlers
lax [info] hdlr.handle(record)
lax [info] File "/usr/local/lib/python3.11/logging/__init__.py", line 978, in handle
lax [info] self.emit(record)
lax [info] File "/app/website/documentation/content/log_documentation.py", line 35, in emit
lax [info] self.handleError(record)
lax [info]Message: KeyError('90452107-61de-4c71-9b05-d5b9050d15f4')
lax [info]Arguments: ()
This seems to also make the server unstable (eg. not responding to health checks). I still don't know the real cause...
from nicegui.
@rodja This clearly points to our "Attach to a logger" demo, which is exactly what we created this warning for.
I fixed it in bc37d78.
from nicegui.
Related Issues (20)
- [Pycharm Problem] Raise asyncio error when reload HOT 1
- local_file_picker Example error in version 1.4.25: HOT 5
- custom vue.js component not updated after modification HOT 3
- non-existing on_pointer parameter in InteractiveImage HOT 1
- `ui.chip` textcolor stays black on dark background HOT 2
- Bump plotly.js to 2.32.0 version supporting zindex HOT 4
- Lifespan state is not passed when a FastAPI app mount a Nicegui app HOT 3
- plotly is missing from docker image HOT 2
- How to get the value of a cell slot within a table?
- how can nicegui upload all files and subdirectory in an directory?
- auto-reload make pyinstaller build failed HOT 2
- `ui.codemirror` does not work via NiceGUI On Air
- Audio with hashtags in filenames are not loaded HOT 1
- Native mode raises 'webview' has not attribute 'settings' HOT 1
- Pytest: recursive dependency in fixtures HOT 2
- `ui.number`: change event argument differs from `value` property HOT 1
- Confusing desync with blocking calls HOT 15
- while running smoothly after few minutes this issue occurred..please help HOT 1
- Breaking change trapping await javascript in version 1.4.26 HOT 12
- Packaging with nicegui-package makes process hang HOT 12
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nicegui.