Skip to content

Commit

Permalink
Allow metrics reading
Browse files Browse the repository at this point in the history
  • Loading branch information
KaQuMiQ authored Jan 16, 2025
1 parent c27c6cf commit fb291ce
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 54 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "haiway"
description = "Framework for dependency injection and state management within structured concurrency model."
version = "0.8.4"
version = "0.9.0"
readme = "README.md"
maintainers = [
{ name = "Kacper Kaliński", email = "[email protected]" },
Expand Down
4 changes: 4 additions & 0 deletions src/haiway/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Disposables,
MetricsContext,
MetricsHandler,
MetricsReading,
MetricsRecording,
MetricsScopeEntering,
MetricsScopeExiting,
Expand All @@ -13,6 +14,7 @@
)
from haiway.helpers import (
ArgumentsTrace,
MetricsHolder,
MetricsLogger,
ResultTrace,
asynchronous,
Expand Down Expand Up @@ -61,7 +63,9 @@
"Disposables",
"MetricsContext",
"MetricsHandler",
"MetricsHolder",
"MetricsLogger",
"MetricsReading",
"MetricsRecording",
"MetricsScopeEntering",
"MetricsScopeExiting",
Expand Down
2 changes: 2 additions & 0 deletions src/haiway/context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from haiway.context.metrics import (
MetricsContext,
MetricsHandler,
MetricsReading,
MetricsRecording,
MetricsScopeEntering,
MetricsScopeExiting,
Expand All @@ -15,6 +16,7 @@
"Disposables",
"MetricsContext",
"MetricsHandler",
"MetricsReading",
"MetricsRecording",
"MetricsScopeEntering",
"MetricsScopeExiting",
Expand Down
56 changes: 56 additions & 0 deletions src/haiway/context/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,62 @@ def record(

MetricsContext.record(metric)

@overload
@staticmethod
async def read[Metric: State](
metric: type[Metric],
/,
*,
merged: bool = False,
) -> Metric | None: ...

@overload
@staticmethod
async def read[Metric: State](
metric: type[Metric],
/,
*,
merged: bool = False,
default: Metric,
) -> Metric: ...

@staticmethod
async def read[Metric: State](
metric: type[Metric],
/,
*,
merged: bool = False,
default: Metric | None = None,
) -> Metric | None:
"""
Read metric within current scope context.
Parameters
----------
metric: type[Metric]
type of metric to be read from current context.
merged: bool
control wheather to merge metrics from nested scopes (True)\
or access only the current scope value (False) without combining them
default: Metric | None
default value to return when metric was not recorded yet.
Returns
-------
Metric | None
"""

value: Metric | None = await MetricsContext.read(
metric,
merged=merged,
)
if value is None:
return default

return value

@staticmethod
def log_error(
message: str,
Expand Down
38 changes: 38 additions & 0 deletions src/haiway/context/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
__all__ = [
"MetricsContext",
"MetricsHandler",
"MetricsReading",
"MetricsRecording",
"MetricsScopeEntering",
"MetricsScopeExiting",
Expand All @@ -25,6 +26,18 @@ def __call__(
) -> None: ...


@runtime_checkable
class MetricsReading(Protocol):
async def __call__[Metric: State](
self,
scope: ScopeIdentifier,
/,
*,
metric: type[Metric],
merged: bool,
) -> Metric | None: ...


@runtime_checkable
class MetricsScopeEntering(Protocol):
def __call__[Metric: State](
Expand All @@ -45,6 +58,7 @@ def __call__[Metric: State](

class MetricsHandler(State):
record: MetricsRecording
read: MetricsReading
enter_scope: MetricsScopeEntering
exit_scope: MetricsScopeExiting

Expand Down Expand Up @@ -100,6 +114,30 @@ def record(
exception=exc,
)

@classmethod
async def read[Metric: State](
cls,
metric: type[Metric],
/,
merged: bool,
) -> Metric | None:
try: # catch exceptions - we don't wan't to blow up on metrics
metrics: Self = cls._context.get()

if metrics._metrics is not None:
return await metrics._metrics.read(
metrics._scope,
metric=metric,
merged=merged,
)

except Exception as exc:
LoggerContext.log_error(
"Failed to read metric: %s",
metric.__qualname__,
exception=exc,
)

def __init__(
self,
scope: ScopeIdentifier,
Expand Down
3 changes: 2 additions & 1 deletion src/haiway/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from haiway.helpers.asynchrony import asynchronous, wrap_async
from haiway.helpers.caching import cache
from haiway.helpers.metrics import MetricsLogger
from haiway.helpers.metrics import MetricsHolder, MetricsLogger
from haiway.helpers.retries import retry
from haiway.helpers.throttling import throttle
from haiway.helpers.timeouted import timeout
from haiway.helpers.tracing import ArgumentsTrace, ResultTrace, traced

__all__ = [
"ArgumentsTrace",
"MetricsHolder",
"MetricsLogger",
"ResultTrace",
"asynchronous",
Expand Down
10 changes: 4 additions & 6 deletions src/haiway/helpers/asynchrony.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ async def async_function(*args: Args.args, **kwargs: Args.kwargs) -> Result:


@overload
def asynchronous[**Args, Result]() -> (
Callable[
[Callable[Args, Result]],
Callable[Args, Coroutine[None, None, Result]],
]
): ...
def asynchronous[**Args, Result]() -> Callable[
[Callable[Args, Result]],
Callable[Args, Coroutine[None, None, Result]],
]: ...


@overload
Expand Down
Loading

0 comments on commit fb291ce

Please sign in to comment.