Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions modin/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@
"get_logger",
"enable_logging",
"disable_logging",
"emit_telemetry_event",

Check failure

Code scanning / CodeQL

Explicit export is not defined Error

The name 'emit_telemetry_event' is exported by __all__ but is not defined.
"add_telemetry_handler",

Check failure

Code scanning / CodeQL

Explicit export is not defined Error

The name 'add_telemetry_handler' is exported by __all__ but is not defined.
"clear_telemetry_handler"

Check failure

Code scanning / CodeQL

Explicit export is not defined Error

The name 'clear_telemetry_handler' is exported by __all__ but is not defined.
]
10 changes: 7 additions & 3 deletions modin/logging/logger_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@

``enable_logging`` is used for decorating individual Modin functions or classes.
"""

import time
from __future__ import annotations

from functools import wraps
from types import FunctionType, MethodType
from typing import Any, Callable, Dict, Optional, Tuple, TypeVar, overload

from modin.config import LogMode
from modin.logging.telemetry import emit_telemetry_event

from .config import LogLevel, get_logger

Expand Down Expand Up @@ -121,8 +122,9 @@

assert isinstance(modin_layer, str), "modin_layer is somehow not a string!"

start_line = f"START::{modin_layer.upper()}::{name or obj.__name__}"
stop_line = f"STOP::{modin_layer.upper()}::{name or obj.__name__}"
api_call_name = f"{modin_layer.upper()}::{name or obj.__name__}"
start_line = f"START::{api_call_name}"
stop_line = f"STOP::{api_call_name}"

@wraps(obj)
def run_and_log(*args: Tuple, **kwargs: Dict) -> Any:
Expand All @@ -145,8 +147,10 @@

logger = get_logger()
logger.log(log_level, start_line)
start_time = time.time()
try:
result = obj(*args, **kwargs)
emit_telemetry_event('', api_call_name, time.time() - start_time)

Check failure

Code scanning / CodeQL

Wrong number of arguments in a call Error

Call to
function emit_telemetry_event
with too many arguments; should be no more than 2.
except BaseException as e:
# Only log the exception if a deeper layer of the modin stack has not
# already logged it.
Expand Down
27 changes: 27 additions & 0 deletions modin/logging/telemetry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import logging
from modin.utils import timeout

_telemetry_handlers = []

# Telemetry hooks can be implemented by plugin engines
# to collect discrete data on how modin is performing at the
# high level moden layer.
def emit_telemetry_event(msg:str, value:int|float):
_telemetry_handlers

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.
handlers = _telemetry_handlers.copy()
for fn in handlers:
try:
with timeout(seconds=1):
fn(f"modin::{msg}", value)
except:

Check notice

Code scanning / CodeQL

Except block handles 'BaseException' Note

Except block directly handles BaseException.
logging.ERROR("telemetry handler threw exception, removing handler: " + e)
_telemetry_handlers.remove(fn)
pass

Check warning

Code scanning / CodeQL

Unnecessary pass Warning

Unnecessary 'pass' statement.

def add_telemetry_handler(handler:callable):
_telemetry_handlers.append(handler)

def clear_telemetry_handler(handler):
_telemetry_handlers = []

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable _telemetry_handlers is not used.


14 changes: 14 additions & 0 deletions modin/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import json
import os
import re
import signal
import sys
import types
import warnings
Expand Down Expand Up @@ -980,3 +981,16 @@ def reload_modin() -> None:
for name, module in modules.items():
if name.startswith("modin"):
importlib.reload(module)

# context manager for timing out functions
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)
Loading