mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
chore: improve analytics (#11714)
* chore: improve analytics * lint * log more events, add note in UPDATING.md * handling base class * more events\! * get ref through * right before @expose * fix context * touchups
This commit is contained in:
committed by
GitHub
parent
9215a31fa2
commit
0504cf1a00
@@ -30,15 +30,35 @@ from sqlalchemy.exc import SQLAlchemyError
|
||||
from superset.stats_logger import BaseStatsLogger
|
||||
|
||||
|
||||
def strip_int_from_path(path: Optional[str]) -> str:
|
||||
"""Simple function to remove ints from '/' separated paths"""
|
||||
if path:
|
||||
return "/".join(["<int>" if s.isdigit() else s for s in path.split("/")])
|
||||
return ""
|
||||
|
||||
|
||||
class AbstractEventLogger(ABC):
|
||||
@abstractmethod
|
||||
def log(
|
||||
self, user_id: Optional[int], action: str, *args: Any, **kwargs: Any
|
||||
def log( # pylint: disable=too-many-arguments
|
||||
self,
|
||||
user_id: Optional[int],
|
||||
action: str,
|
||||
dashboard_id: Optional[int],
|
||||
duration_ms: Optional[int],
|
||||
slice_id: Optional[int],
|
||||
path: Optional[str],
|
||||
path_no_int: Optional[str],
|
||||
ref: Optional[str],
|
||||
referrer: Optional[str],
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
@contextmanager
|
||||
def log_context(self, action: str) -> Iterator[Callable[..., None]]:
|
||||
def log_context(
|
||||
self, action: str, ref: Optional[str] = None, log_to_statsd: bool = True,
|
||||
) -> Iterator[Callable[..., None]]:
|
||||
"""
|
||||
Log an event while reading information from the request context.
|
||||
`kwargs` will be appended directly to the log payload.
|
||||
@@ -69,7 +89,8 @@ class AbstractEventLogger(ABC):
|
||||
except (TypeError, ValueError):
|
||||
slice_id = 0
|
||||
|
||||
self.stats_logger.incr(action)
|
||||
if log_to_statsd:
|
||||
self.stats_logger.incr(action)
|
||||
|
||||
# bulk insert
|
||||
try:
|
||||
@@ -86,18 +107,38 @@ class AbstractEventLogger(ABC):
|
||||
slice_id=slice_id,
|
||||
duration_ms=round((time.time() - start_time) * 1000),
|
||||
referrer=referrer,
|
||||
path=request.path,
|
||||
path_no_int=strip_int_from_path(request.path),
|
||||
ref=ref,
|
||||
)
|
||||
|
||||
def log_this(self, f: Callable[..., Any]) -> Callable[..., Any]:
|
||||
def _wrapper(
|
||||
self, f: Callable[..., Any], **wrapper_kwargs: Any
|
||||
) -> Callable[..., Any]:
|
||||
action_str = wrapper_kwargs.get("action") or f.__name__
|
||||
ref = f.__qualname__ if hasattr(f, "__qualname__") else None
|
||||
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
with self.log_context(f.__name__) as log:
|
||||
with self.log_context(action_str, ref, **wrapper_kwargs) as log:
|
||||
value = f(*args, **kwargs)
|
||||
log(**kwargs)
|
||||
return value
|
||||
|
||||
return wrapper
|
||||
|
||||
def log_this(self, f: Callable[..., Any]) -> Callable[..., Any]:
|
||||
"""Decorator that uses the function name as the action"""
|
||||
return self._wrapper(f)
|
||||
|
||||
def log_this_with_context(self, **kwargs: Any) -> Callable[..., Any]:
|
||||
"""Decorator that can override kwargs of log_context"""
|
||||
|
||||
def func(f: Callable[..., Any]) -> Callable[..., Any]:
|
||||
return self._wrapper(f, **kwargs)
|
||||
|
||||
return func
|
||||
|
||||
def log_manually(self, f: Callable[..., Any]) -> Callable[..., Any]:
|
||||
"""Allow a function to manually update"""
|
||||
|
||||
@@ -162,16 +203,23 @@ def get_event_logger_from_cfg_value(cfg_value: Any) -> AbstractEventLogger:
|
||||
class DBEventLogger(AbstractEventLogger):
|
||||
"""Event logger that commits logs to Superset DB"""
|
||||
|
||||
def log( # pylint: disable=too-many-locals
|
||||
self, user_id: Optional[int], action: str, *args: Any, **kwargs: Any
|
||||
def log( # pylint: disable=too-many-arguments,too-many-locals
|
||||
self,
|
||||
user_id: Optional[int],
|
||||
action: str,
|
||||
dashboard_id: Optional[int],
|
||||
duration_ms: Optional[int],
|
||||
slice_id: Optional[int],
|
||||
path: Optional[str],
|
||||
path_no_int: Optional[str],
|
||||
ref: Optional[str],
|
||||
referrer: Optional[str],
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
from superset.models.core import Log
|
||||
|
||||
records = kwargs.get("records", list())
|
||||
dashboard_id = kwargs.get("dashboard_id")
|
||||
slice_id = kwargs.get("slice_id")
|
||||
duration_ms = kwargs.get("duration_ms")
|
||||
referrer = kwargs.get("referrer")
|
||||
|
||||
logs = list()
|
||||
for record in records:
|
||||
@@ -188,6 +236,9 @@ class DBEventLogger(AbstractEventLogger):
|
||||
duration_ms=duration_ms,
|
||||
referrer=referrer,
|
||||
user_id=user_id,
|
||||
path=path,
|
||||
path_no_int=path_no_int,
|
||||
ref=ref,
|
||||
)
|
||||
logs.append(log)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user