Skip to content

Commit 94bbef3

Browse files
authored
✨ Is3200/log user during login/logout (ITISFoundation#3205)
1 parent f90a680 commit 94bbef3

File tree

3 files changed

+58
-20
lines changed

3 files changed

+58
-20
lines changed

packages/service-library/src/servicelib/logging_utils.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""
2-
This codes originates from this article (https://medium.com/swlh/add-log-decorators-to-your-python-project-84094f832181)
2+
This codes originates from this article
3+
https://medium.com/swlh/add-log-decorators-to-your-python-project-84094f832181
4+
5+
SEE also https://github.com/Delgan/loguru for a future alternative
36
"""
47
import asyncio
58
import functools
@@ -181,3 +184,15 @@ def log_catch(logger: logging.Logger, reraise: bool = True):
181184
logger.error("Unhandled exception: %s", f"{exc}", exc_info=True)
182185
if reraise:
183186
raise exc from exc
187+
188+
189+
un_capitalize = lambda s: s[:1].lower() + s[1:] if s else ""
190+
191+
192+
@contextmanager
193+
def log_context(logger: logging.Logger, level: int, msg: str, *args, **kwargs):
194+
# NOTE: preserves original signature https://docs.python.org/3/library/logging.html#logging.Logger.log
195+
msg = un_capitalize(msg.strip())
196+
logger.log(level, "Starting " + msg + " ...", *args, **kwargs)
197+
yield
198+
logger.log(level, "Finished " + msg, *args, **kwargs)

services/web/server/src/simcore_service_webserver/login/handlers.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import logging
2-
from typing import Dict
32

43
from aiohttp import web
54
from servicelib import observer
65
from servicelib.aiohttp.rest_utils import extract_and_validate
6+
from servicelib.logging_utils import log_context
77
from yarl import URL
88

99
from ..db_models import ConfirmationAction, UserRole, UserStatus
@@ -66,7 +66,7 @@ async def register(request: web.Request):
6666

6767
await check_registration(email, password, confirm, db, cfg)
6868

69-
user: Dict = await db.create_user(
69+
user: dict = await db.create_user(
7070
{
7171
"name": username,
7272
"email": email,
@@ -150,12 +150,17 @@ async def login(request: web.Request):
150150
assert user["status"] == ACTIVE, "db corrupted. Invalid status" # nosec
151151
assert user["email"] == email, "db corrupted. Invalid email" # nosec
152152

153-
# user logs in
154-
identity = user["email"]
155-
response = flash_response(cfg.MSG_LOGGED_IN, "INFO")
156-
157-
await remember(request, response, identity)
158-
return response
153+
with log_context(
154+
log,
155+
logging.INFO,
156+
"login of user_id=%s with %s",
157+
f"{user.get('id')}",
158+
f"{email=}",
159+
):
160+
identity = user["email"]
161+
response = flash_response(cfg.MSG_LOGGED_IN, "INFO")
162+
await remember(request, response, identity)
163+
return response
159164

160165

161166
@login_required
@@ -168,8 +173,16 @@ async def logout(request: web.Request) -> web.Response:
168173
if request.can_read_body:
169174
body = await request.json()
170175
client_session_id = body.get("client_session_id", None)
171-
await observer.emit("SIGNAL_USER_LOGOUT", user_id, client_session_id, request.app)
172-
await forget(request, response)
176+
177+
# Keep log message: https://github.com/ITISFoundation/osparc-simcore/issues/3200
178+
with log_context(
179+
log, logging.INFO, "logout of %s for %s", f"{user_id=}", f"{client_session_id=}"
180+
):
181+
await observer.emit(
182+
"SIGNAL_USER_LOGOUT", user_id, client_session_id, request.app
183+
)
184+
await forget(request, response)
185+
173186
return response
174187

175188

services/web/server/src/simcore_service_webserver/socketio/handlers.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

99
import asyncio
1010
import logging
11-
from typing import Any, Dict, List, Optional
11+
from typing import Any, Optional
1212

1313
from aiohttp import web
1414
from servicelib.aiohttp.application_keys import APP_FIRE_AND_FORGET_TASKS_KEY
15+
from servicelib.logging_utils import log_context
1516
from servicelib.observer import emit, observe
1617
from servicelib.utils import fire_and_forget_task, logged_gather
1718
from socketio import AsyncServer
@@ -31,7 +32,7 @@
3132

3233

3334
@register_socketio_handler
34-
async def connect(sid: str, environ: Dict, app: web.Application) -> bool:
35+
async def connect(sid: str, environ: dict, app: web.Application) -> bool:
3536
"""socketio reserved handler for when the fontend connects through socket.io
3637
3738
Arguments:
@@ -60,7 +61,7 @@ async def connect(sid: str, environ: Dict, app: web.Application) -> bool:
6061
log.info("Sending set_heartbeat_emit_interval with %s", emit_interval)
6162

6263
user_id = request.get(RQT_USERID_KEY, ANONYMOUS_USER_ID)
63-
heart_beat_messages: List[SocketMessageDict] = [
64+
heart_beat_messages: list[SocketMessageDict] = [
6465
{
6566
"event_type": SOCKET_IO_HEARTBEAT_EVENT,
6667
"data": {"interval": emit_interval},
@@ -110,7 +111,7 @@ async def set_user_in_rooms(
110111
sio.enter_room(sid, f"{group['gid']}")
111112

112113

113-
async def disconnect_other_sockets(sio, sockets: List[str]) -> None:
114+
async def disconnect_other_sockets(sio, sockets: list[str]) -> None:
114115
log.debug("disconnecting sockets %s", sockets)
115116
logout_tasks = [
116117
sio.emit("logout", to=sid, data={"reason": "user logged out"})
@@ -170,13 +171,22 @@ async def disconnect(sid: str, app: web.Application) -> None:
170171
sio = get_socket_server(app)
171172
async with sio.session(sid) as socketio_session:
172173
if "user_id" in socketio_session:
174+
173175
user_id = socketio_session["user_id"]
174176
client_session_id = socketio_session["client_session_id"]
175-
with managed_resource(user_id, client_session_id, app) as rt:
176-
log.debug("client %s disconnected from room %s", user_id, sid)
177-
await rt.remove_socket_id()
178-
# signal same user other clients if available
179-
await emit("SIGNAL_USER_DISCONNECTED", user_id, client_session_id, app)
177+
178+
with log_context(
179+
log,
180+
logging.INFO,
181+
"disconnection of %s for %s",
182+
f"{user_id=}",
183+
f"{client_session_id=}",
184+
):
185+
with managed_resource(user_id, client_session_id, app) as rt:
186+
log.debug("client %s disconnected from room %s", user_id, sid)
187+
await rt.remove_socket_id()
188+
# signal same user other clients if available
189+
await emit("SIGNAL_USER_DISCONNECTED", user_id, client_session_id, app)
180190

181191
else:
182192
# this should not happen!!

0 commit comments

Comments
 (0)