haiway 0.18.0__tar.gz → 0.18.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {haiway-0.18.0 → haiway-0.18.2}/PKG-INFO +1 -1
- {haiway-0.18.0 → haiway-0.18.2}/junit/test-results.xml +1 -1
- {haiway-0.18.0 → haiway-0.18.2}/pyproject.toml +1 -1
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/__init__.py +6 -2
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/__init__.py +4 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/access.py +37 -5
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/observability.py +85 -3
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/__init__.py +3 -6
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/observability.py +28 -2
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/tracing.py +12 -35
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/opentelemetry/observability.py +34 -2
- {haiway-0.18.0 → haiway-0.18.2}/uv.lock +194 -194
- {haiway-0.18.0 → haiway-0.18.2}/.github/workflows/ci.yml +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/.github/workflows/publish.yml +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/.gitignore +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/LICENSE +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/Makefile +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/README.md +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/config/pre-push +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/.dockerignore +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/Dockerfile +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/Makefile +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/README.md +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/config/.env.example +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/config/unit.json +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/docker-compose.yml +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/pyproject.toml +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/__int__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/todos/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/todos/config.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/todos/state.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/todos/types.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/features/todos/user_tasks.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/postgres/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/postgres/client.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/postgres/config.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/postgres/state.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/integrations/postgres/types.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/__main__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/postgres/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/postgres/execution.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/postgres/migration_0.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/migrations/postgres/types.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/__main__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/application.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/config.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/middlewares/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/middlewares/context.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/routes/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/routes/technical.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/server/routes/todos.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/user_tasks/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/user_tasks/config.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/user_tasks/postgres.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/user_tasks/state.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/src/solutions/user_tasks/types.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/examples/fastAPI/uv.lock +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/guidelines/functionalities.md +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/guidelines/packages.md +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/disposables.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/identifier.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/state.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/tasks.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/context/types.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/asynchrony.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/caching.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/retries.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/throttling.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/helpers/timeouted.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/opentelemetry/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/py.typed +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/attributes.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/path.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/requirement.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/structure.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/state/validation.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/types/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/types/default.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/types/frozen.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/types/missing.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/always.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/collections.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/env.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/freezing.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/logs.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/mimic.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/noop.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/queue.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/src/haiway/utils/stream.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/__init__.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_async_queue.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_async_stream.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_attribute_path.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_auto_retry.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_cache.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_context.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_state.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_streaming.py +0 -0
- {haiway-0.18.0 → haiway-0.18.2}/tests/test_timeout.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: haiway
|
3
|
-
Version: 0.18.
|
3
|
+
Version: 0.18.2
|
4
4
|
Summary: Framework for dependency injection and state management within structured concurrency model.
|
5
5
|
Project-URL: Homepage, https://miquido.com
|
6
6
|
Project-URL: Repository, https://github.com/miquido/haiway.git
|
@@ -1 +1 @@
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="88" time="1.
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite name="pytest" errors="0" failures="0" skipped="0" tests="88" time="1.116" timestamp="2025-05-12T15:57:41.113378+00:00" hostname="pkrvmberfyhpb9w"><testcase classname="tests.test_async_queue" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_queue" name="test_buffers_values_when_not_reading" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_buffer_when_streaming_fails" time="0.001" /><testcase classname="tests.test_async_queue" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_queue" name="test_fails_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_queue" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_when_stream_fails" time="0.001" /><testcase classname="tests.test_async_stream" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ends_when_stream_ends" time="0.001" /><testcase classname="tests.test_async_stream" name="test_finishes_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_fails_without_buffer" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_updates_when_sending" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_sending_to_failed" time="0.001" /><testcase classname="tests.test_async_stream" name="test_ignores_when_finishing_when_finished" time="0.001" /><testcase classname="tests.test_async_stream" name="test_delivers_all_when_sending_async" time="0.001" /><testcase classname="tests.test_attribute_path" name="test_id_path_points_to_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_points_to_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_path_points_to_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_points_to_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_id_path_set_updates_self" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_attribute_path_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_nested_attribute_path_set_updates_nested_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_recursive_attribute_set_updates_attribute" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_list_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_tuple_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_mixed_tuple_item_set_updates_item" time="0.000" /><testcase classname="tests.test_attribute_path" name="test_dict_item_path_set_updates_item" time="0.000" /><testcase classname="tests.test_auto_retry" name="test_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_logs_issue_with_errors" time="0.007" /><testcase classname="tests.test_auto_retry" name="test_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_returns_value_without_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_exceeding_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_cancellation" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_when_cancelled" time="0.021" /><testcase classname="tests.test_auto_retry" name="test_async_uses_delay_with_errors" time="0.102" /><testcase classname="tests.test_auto_retry" name="test_async_uses_computed_delay_with_errors" time="0.107" /><testcase classname="tests.test_auto_retry" name="test_async_logs_issue_with_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_retries_with_selected_errors" time="0.001" /><testcase classname="tests.test_auto_retry" name="test_async_fails_with_not_selected_errors" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_cache_value_with_same_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_different_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_limit_exceed" time="0.000" /><testcase classname="tests.test_cache" name="test_returns_same_value_with_repeating_argument" time="0.000" /><testcase classname="tests.test_cache" name="test_fails_with_error" time="0.001" /><testcase classname="tests.test_cache" name="test_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_returns_cache_value_with_same_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_different_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_limit_exceed" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_same_value_with_repeating_argument" time="0.001" /><testcase classname="tests.test_cache" name="test_async_returns_fresh_value_with_expiration_time_exceed" time="0.021" /><testcase classname="tests.test_cache" name="test_async_cancel_waiting_does_not_cancel_task" time="0.502" /><testcase classname="tests.test_cache" name="test_async_expiration_does_not_cancel_task" time="0.021" /><testcase classname="tests.test_cache" name="test_async_fails_with_error" time="0.001" /><testcase classname="tests.test_context" name="test_state_is_available_according_to_context" time="0.001" /><testcase classname="tests.test_context" name="test_state_update_updates_local_context" time="0.001" /><testcase classname="tests.test_context" name="test_exceptions_are_propagated" time="0.001" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments" time="0.002" /><testcase classname="tests.test_state" name="test_basic_initializes_with_defaults" time="0.001" /><testcase classname="tests.test_state" name="test_basic_equals_checks_properties" time="0.000" /><testcase classname="tests.test_state" name="test_basic_initializes_with_arguments_and_defaults" time="0.000" /><testcase classname="tests.test_state" name="test_parametrized_initializes_with_proper_parameters" time="0.000" /><testcase classname="tests.test_state" name="test_nested_initializes_with_proper_arguments" time="0.001" /><testcase classname="tests.test_state" name="test_dict_skips_missing_properties" time="0.000" /><testcase classname="tests.test_state" name="test_initialization_allows_missing_properties" time="0.001" /><testcase classname="tests.test_state" name="test_generic_subtypes_validation" time="0.002" /><testcase classname="tests.test_state" name="test_copying_leaves_same_object" time="0.001" /><testcase classname="tests.test_streaming" name="test_fails_when_generator_fails" time="0.001" /><testcase classname="tests.test_streaming" name="test_cancels_when_iteration_cancels" time="0.001" /><testcase classname="tests.test_streaming" name="test_ends_when_generator_ends" time="0.001" /><testcase classname="tests.test_streaming" name="test_delivers_updates_when_generating" time="0.001" /><testcase classname="tests.test_streaming" name="test_streaming_context_variables_access_is_preserved" time="0.001" /><testcase classname="tests.test_streaming" name="test_nested_streaming_streams_correctly" time="0.001" /><testcase classname="tests.test_timeout" name="test_returns_result_when_returning_value" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_error" time="0.001" /><testcase classname="tests.test_timeout" name="test_raises_with_cancel" time="0.011" /><testcase classname="tests.test_timeout" name="test_raises_with_timeout" time="0.011" /></testsuite></testsuites>
|
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
|
5
5
|
[project]
|
6
6
|
name = "haiway"
|
7
7
|
description = "Framework for dependency injection and state management within structured concurrency model."
|
8
|
-
version = "0.18.
|
8
|
+
version = "0.18.2"
|
9
9
|
readme = "README.md"
|
10
10
|
maintainers = [
|
11
11
|
{ name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
|
@@ -4,6 +4,8 @@ from haiway.context import (
|
|
4
4
|
MissingContext,
|
5
5
|
MissingState,
|
6
6
|
Observability,
|
7
|
+
ObservabilityAttribute,
|
8
|
+
ObservabilityAttributesRecording,
|
7
9
|
ObservabilityContext,
|
8
10
|
ObservabilityEventRecording,
|
9
11
|
ObservabilityLevel,
|
@@ -17,7 +19,7 @@ from haiway.context import (
|
|
17
19
|
ctx,
|
18
20
|
)
|
19
21
|
from haiway.helpers import (
|
20
|
-
|
22
|
+
LoggerObservability,
|
21
23
|
ResultTrace,
|
22
24
|
asynchronous,
|
23
25
|
cache,
|
@@ -63,7 +65,6 @@ from haiway.utils import (
|
|
63
65
|
|
64
66
|
__all__ = (
|
65
67
|
"MISSING",
|
66
|
-
"ArgumentsTrace",
|
67
68
|
"AsyncQueue",
|
68
69
|
"AsyncStream",
|
69
70
|
"AttributePath",
|
@@ -72,10 +73,13 @@ __all__ = (
|
|
72
73
|
"DefaultValue",
|
73
74
|
"Disposable",
|
74
75
|
"Disposables",
|
76
|
+
"LoggerObservability",
|
75
77
|
"Missing",
|
76
78
|
"MissingContext",
|
77
79
|
"MissingState",
|
78
80
|
"Observability",
|
81
|
+
"ObservabilityAttribute",
|
82
|
+
"ObservabilityAttributesRecording",
|
79
83
|
"ObservabilityContext",
|
80
84
|
"ObservabilityEventRecording",
|
81
85
|
"ObservabilityLevel",
|
@@ -3,6 +3,8 @@ from haiway.context.disposables import Disposable, Disposables
|
|
3
3
|
from haiway.context.identifier import ScopeIdentifier
|
4
4
|
from haiway.context.observability import (
|
5
5
|
Observability,
|
6
|
+
ObservabilityAttribute,
|
7
|
+
ObservabilityAttributesRecording,
|
6
8
|
ObservabilityContext,
|
7
9
|
ObservabilityEventRecording,
|
8
10
|
ObservabilityLevel,
|
@@ -20,6 +22,8 @@ __all__ = (
|
|
20
22
|
"MissingContext",
|
21
23
|
"MissingState",
|
22
24
|
"Observability",
|
25
|
+
"ObservabilityAttribute",
|
26
|
+
"ObservabilityAttributesRecording",
|
23
27
|
"ObservabilityContext",
|
24
28
|
"ObservabilityEventRecording",
|
25
29
|
"ObservabilityLevel",
|
@@ -18,7 +18,12 @@ from typing import Any, final, overload
|
|
18
18
|
|
19
19
|
from haiway.context.disposables import Disposable, Disposables
|
20
20
|
from haiway.context.identifier import ScopeIdentifier
|
21
|
-
from haiway.context.observability import
|
21
|
+
from haiway.context.observability import (
|
22
|
+
Observability,
|
23
|
+
ObservabilityAttribute,
|
24
|
+
ObservabilityContext,
|
25
|
+
ObservabilityLevel,
|
26
|
+
)
|
22
27
|
from haiway.context.state import ScopeState, StateContext
|
23
28
|
from haiway.context.tasks import TaskGroupContext
|
24
29
|
from haiway.state import State
|
@@ -462,6 +467,7 @@ class ctx:
|
|
462
467
|
/,
|
463
468
|
*args: Any,
|
464
469
|
exception: BaseException | None = None,
|
470
|
+
**extra: Any,
|
465
471
|
) -> None:
|
466
472
|
"""
|
467
473
|
Log using ERROR level within current scope context. When there is no current scope\
|
@@ -488,6 +494,7 @@ class ctx:
|
|
488
494
|
message,
|
489
495
|
*args,
|
490
496
|
exception=exception,
|
497
|
+
**extra,
|
491
498
|
)
|
492
499
|
|
493
500
|
@staticmethod
|
@@ -496,6 +503,7 @@ class ctx:
|
|
496
503
|
/,
|
497
504
|
*args: Any,
|
498
505
|
exception: Exception | None = None,
|
506
|
+
**extra: Any,
|
499
507
|
) -> None:
|
500
508
|
"""
|
501
509
|
Log using WARNING level within current scope context. When there is no current scope\
|
@@ -522,6 +530,7 @@ class ctx:
|
|
522
530
|
message,
|
523
531
|
*args,
|
524
532
|
exception=exception,
|
533
|
+
**extra,
|
525
534
|
)
|
526
535
|
|
527
536
|
@staticmethod
|
@@ -529,6 +538,7 @@ class ctx:
|
|
529
538
|
message: str,
|
530
539
|
/,
|
531
540
|
*args: Any,
|
541
|
+
**extra: Any,
|
532
542
|
) -> None:
|
533
543
|
"""
|
534
544
|
Log using INFO level within current scope context. When there is no current scope\
|
@@ -552,6 +562,7 @@ class ctx:
|
|
552
562
|
message,
|
553
563
|
*args,
|
554
564
|
exception=None,
|
565
|
+
**extra,
|
555
566
|
)
|
556
567
|
|
557
568
|
@staticmethod
|
@@ -560,6 +571,7 @@ class ctx:
|
|
560
571
|
/,
|
561
572
|
*args: Any,
|
562
573
|
exception: Exception | None = None,
|
574
|
+
**extra: Any,
|
563
575
|
) -> None:
|
564
576
|
"""
|
565
577
|
Log using DEBUG level within current scope context. When there is no current scope\
|
@@ -582,10 +594,7 @@ class ctx:
|
|
582
594
|
"""
|
583
595
|
|
584
596
|
ObservabilityContext.record_log(
|
585
|
-
ObservabilityLevel.DEBUG,
|
586
|
-
message,
|
587
|
-
*args,
|
588
|
-
exception=exception,
|
597
|
+
ObservabilityLevel.DEBUG, message, *args, exception=exception, **extra
|
589
598
|
)
|
590
599
|
|
591
600
|
@staticmethod
|
@@ -594,6 +603,7 @@ class ctx:
|
|
594
603
|
/,
|
595
604
|
*,
|
596
605
|
level: ObservabilityLevel = ObservabilityLevel.INFO,
|
606
|
+
**extra: Any,
|
597
607
|
) -> None:
|
598
608
|
"""
|
599
609
|
Record event within current scope context.
|
@@ -611,6 +621,7 @@ class ctx:
|
|
611
621
|
ObservabilityContext.record_event(
|
612
622
|
event,
|
613
623
|
level=level,
|
624
|
+
**extra,
|
614
625
|
)
|
615
626
|
|
616
627
|
@staticmethod
|
@@ -620,6 +631,7 @@ class ctx:
|
|
620
631
|
*,
|
621
632
|
value: float | int,
|
622
633
|
unit: str | None = None,
|
634
|
+
**extra: Any,
|
623
635
|
) -> None:
|
624
636
|
"""
|
625
637
|
Record metric within current scope context.
|
@@ -642,4 +654,24 @@ class ctx:
|
|
642
654
|
metric,
|
643
655
|
value=value,
|
644
656
|
unit=unit,
|
657
|
+
**extra,
|
658
|
+
)
|
659
|
+
|
660
|
+
@staticmethod
|
661
|
+
def attributes(**attributes: ObservabilityAttribute) -> None:
|
662
|
+
"""
|
663
|
+
Record attributes within current scope context.
|
664
|
+
|
665
|
+
Parameters
|
666
|
+
----------
|
667
|
+
**attributes: ObservabilityAttribute,
|
668
|
+
attributes to be recorded within current context.
|
669
|
+
|
670
|
+
Returns
|
671
|
+
-------
|
672
|
+
None
|
673
|
+
"""
|
674
|
+
|
675
|
+
ObservabilityContext.record_attributes(
|
676
|
+
**attributes,
|
645
677
|
)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from collections.abc import Sequence
|
1
2
|
from contextvars import ContextVar, Token
|
2
3
|
from enum import IntEnum
|
3
4
|
from logging import DEBUG as DEBUG_LOGGING
|
@@ -9,9 +10,8 @@ from types import TracebackType
|
|
9
10
|
from typing import Any, Final, Protocol, Self, final, runtime_checkable
|
10
11
|
|
11
12
|
from haiway.context.identifier import ScopeIdentifier
|
12
|
-
|
13
|
-
# from haiway.context.logging import LoggerContext
|
14
13
|
from haiway.state import State
|
14
|
+
from haiway.types import MISSING, Missing
|
15
15
|
|
16
16
|
__all__ = (
|
17
17
|
"DEBUG",
|
@@ -19,6 +19,8 @@ __all__ = (
|
|
19
19
|
"INFO",
|
20
20
|
"WARNING",
|
21
21
|
"Observability",
|
22
|
+
"ObservabilityAttribute",
|
23
|
+
"ObservabilityAttributesRecording",
|
22
24
|
"ObservabilityContext",
|
23
25
|
"ObservabilityEventRecording",
|
24
26
|
"ObservabilityLevel",
|
@@ -42,6 +44,19 @@ WARNING: Final[int] = ObservabilityLevel.WARNING
|
|
42
44
|
INFO: Final[int] = ObservabilityLevel.INFO
|
43
45
|
DEBUG: Final[int] = ObservabilityLevel.DEBUG
|
44
46
|
|
47
|
+
type ObservabilityAttribute = (
|
48
|
+
Sequence[str]
|
49
|
+
| Sequence[float]
|
50
|
+
| Sequence[int]
|
51
|
+
| Sequence[bool]
|
52
|
+
| str
|
53
|
+
| float
|
54
|
+
| int
|
55
|
+
| bool
|
56
|
+
| None
|
57
|
+
| Missing
|
58
|
+
)
|
59
|
+
|
45
60
|
|
46
61
|
@runtime_checkable
|
47
62
|
class ObservabilityLogRecording(Protocol):
|
@@ -53,6 +68,7 @@ class ObservabilityLogRecording(Protocol):
|
|
53
68
|
message: str,
|
54
69
|
*args: Any,
|
55
70
|
exception: BaseException | None,
|
71
|
+
**extra: Any,
|
56
72
|
) -> None: ...
|
57
73
|
|
58
74
|
|
@@ -65,6 +81,7 @@ class ObservabilityEventRecording(Protocol):
|
|
65
81
|
*,
|
66
82
|
level: ObservabilityLevel,
|
67
83
|
event: State,
|
84
|
+
**extra: Any,
|
68
85
|
) -> None: ...
|
69
86
|
|
70
87
|
|
@@ -78,6 +95,17 @@ class ObservabilityMetricRecording(Protocol):
|
|
78
95
|
metric: str,
|
79
96
|
value: float | int,
|
80
97
|
unit: str | None,
|
98
|
+
**extra: Any,
|
99
|
+
) -> None: ...
|
100
|
+
|
101
|
+
|
102
|
+
@runtime_checkable
|
103
|
+
class ObservabilityAttributesRecording(Protocol):
|
104
|
+
def __call__(
|
105
|
+
self,
|
106
|
+
scope: ScopeIdentifier,
|
107
|
+
/,
|
108
|
+
**attributes: ObservabilityAttribute,
|
81
109
|
) -> None: ...
|
82
110
|
|
83
111
|
|
@@ -103,6 +131,7 @@ class ObservabilityScopeExiting(Protocol):
|
|
103
131
|
|
104
132
|
class Observability: # avoiding State inheritance to prevent propagation as scope state
|
105
133
|
__slots__ = (
|
134
|
+
"attributes_recording",
|
106
135
|
"event_recording",
|
107
136
|
"log_recording",
|
108
137
|
"metric_recording",
|
@@ -115,6 +144,7 @@ class Observability: # avoiding State inheritance to prevent propagation as sco
|
|
115
144
|
log_recording: ObservabilityLogRecording,
|
116
145
|
metric_recording: ObservabilityMetricRecording,
|
117
146
|
event_recording: ObservabilityEventRecording,
|
147
|
+
attributes_recording: ObservabilityAttributesRecording,
|
118
148
|
scope_entering: ObservabilityScopeEntering,
|
119
149
|
scope_exiting: ObservabilityScopeExiting,
|
120
150
|
) -> None:
|
@@ -136,6 +166,13 @@ class Observability: # avoiding State inheritance to prevent propagation as sco
|
|
136
166
|
"event_recording",
|
137
167
|
event_recording,
|
138
168
|
)
|
169
|
+
self.attributes_recording: ObservabilityAttributesRecording
|
170
|
+
object.__setattr__(
|
171
|
+
self,
|
172
|
+
"attributes_recording",
|
173
|
+
attributes_recording,
|
174
|
+
)
|
175
|
+
|
139
176
|
self.scope_entering: ObservabilityScopeEntering
|
140
177
|
object.__setattr__(
|
141
178
|
self,
|
@@ -180,6 +217,7 @@ def _logger_observability(
|
|
180
217
|
message: str,
|
181
218
|
*args: Any,
|
182
219
|
exception: BaseException | None,
|
220
|
+
**extra: Any,
|
183
221
|
) -> None:
|
184
222
|
logger.log(
|
185
223
|
level,
|
@@ -194,6 +232,7 @@ def _logger_observability(
|
|
194
232
|
*,
|
195
233
|
level: ObservabilityLevel,
|
196
234
|
event: State,
|
235
|
+
**extra: Any,
|
197
236
|
) -> None:
|
198
237
|
logger.log(
|
199
238
|
level,
|
@@ -207,10 +246,25 @@ def _logger_observability(
|
|
207
246
|
metric: str,
|
208
247
|
value: float | int,
|
209
248
|
unit: str | None,
|
249
|
+
**extra: Any,
|
210
250
|
) -> None:
|
211
251
|
logger.log(
|
212
252
|
INFO,
|
213
|
-
f"{scope.unique_name} Recorded metric
|
253
|
+
f"{scope.unique_name} Recorded metric: {metric}={value}{unit or ''}",
|
254
|
+
)
|
255
|
+
|
256
|
+
def attributes_recording(
|
257
|
+
scope: ScopeIdentifier,
|
258
|
+
/,
|
259
|
+
**attributes: ObservabilityAttribute,
|
260
|
+
) -> None:
|
261
|
+
if not attributes:
|
262
|
+
return
|
263
|
+
|
264
|
+
logger.log(
|
265
|
+
INFO,
|
266
|
+
f"{scope.unique_name} Recorded attributes:"
|
267
|
+
f"\n{'\n'.join(f'{k}: {v}' for k, v in attributes.items() if v is not None and v is not MISSING)}", # noqa: E501
|
214
268
|
)
|
215
269
|
|
216
270
|
def scope_entering[Metric: State](
|
@@ -238,6 +292,7 @@ def _logger_observability(
|
|
238
292
|
log_recording=log_recording,
|
239
293
|
event_recording=event_recording,
|
240
294
|
metric_recording=metric_recording,
|
295
|
+
attributes_recording=attributes_recording,
|
241
296
|
scope_entering=scope_entering,
|
242
297
|
scope_exiting=scope_exiting,
|
243
298
|
)
|
@@ -302,6 +357,7 @@ class ObservabilityContext:
|
|
302
357
|
/,
|
303
358
|
*args: Any,
|
304
359
|
exception: BaseException | None,
|
360
|
+
**extra: Any,
|
305
361
|
) -> None:
|
306
362
|
try: # catch exceptions - we don't wan't to blow up on observability
|
307
363
|
context: Self = cls._context.get()
|
@@ -313,6 +369,7 @@ class ObservabilityContext:
|
|
313
369
|
message,
|
314
370
|
*args,
|
315
371
|
exception=exception,
|
372
|
+
**extra,
|
316
373
|
)
|
317
374
|
|
318
375
|
except LookupError:
|
@@ -330,6 +387,7 @@ class ObservabilityContext:
|
|
330
387
|
/,
|
331
388
|
*,
|
332
389
|
level: ObservabilityLevel,
|
390
|
+
**extra: Any,
|
333
391
|
) -> None:
|
334
392
|
try: # catch exceptions - we don't wan't to blow up on observability
|
335
393
|
context: Self = cls._context.get()
|
@@ -339,6 +397,7 @@ class ObservabilityContext:
|
|
339
397
|
context._scope,
|
340
398
|
level=level,
|
341
399
|
event=event,
|
400
|
+
**extra,
|
342
401
|
)
|
343
402
|
|
344
403
|
except Exception as exc:
|
@@ -356,6 +415,7 @@ class ObservabilityContext:
|
|
356
415
|
*,
|
357
416
|
value: float | int,
|
358
417
|
unit: str | None,
|
418
|
+
**extra: Any,
|
359
419
|
) -> None:
|
360
420
|
try: # catch exceptions - we don't wan't to blow up on observability
|
361
421
|
context: Self = cls._context.get()
|
@@ -366,6 +426,7 @@ class ObservabilityContext:
|
|
366
426
|
metric=metric,
|
367
427
|
value=value,
|
368
428
|
unit=unit,
|
429
|
+
**extra,
|
369
430
|
)
|
370
431
|
|
371
432
|
except Exception as exc:
|
@@ -375,6 +436,27 @@ class ObservabilityContext:
|
|
375
436
|
exception=exc,
|
376
437
|
)
|
377
438
|
|
439
|
+
@classmethod
|
440
|
+
def record_attributes(
|
441
|
+
cls,
|
442
|
+
**attributes: ObservabilityAttribute,
|
443
|
+
) -> None:
|
444
|
+
try: # catch exceptions - we don't wan't to blow up on observability
|
445
|
+
context: Self = cls._context.get()
|
446
|
+
|
447
|
+
if context.observability is not None:
|
448
|
+
context.observability.attributes_recording(
|
449
|
+
context._scope,
|
450
|
+
**attributes,
|
451
|
+
)
|
452
|
+
|
453
|
+
except Exception as exc:
|
454
|
+
cls.record_log(
|
455
|
+
ERROR,
|
456
|
+
f"Failed to record attributes: {attributes}",
|
457
|
+
exception=exc,
|
458
|
+
)
|
459
|
+
|
378
460
|
__slots__ = (
|
379
461
|
"_scope",
|
380
462
|
"_token",
|
@@ -1,19 +1,16 @@
|
|
1
1
|
from haiway.helpers.asynchrony import asynchronous, wrap_async
|
2
2
|
from haiway.helpers.caching import CacheMakeKey, CacheRead, CacheWrite, cache
|
3
|
+
from haiway.helpers.observability import LoggerObservability
|
3
4
|
from haiway.helpers.retries import retry
|
4
5
|
from haiway.helpers.throttling import throttle
|
5
6
|
from haiway.helpers.timeouted import timeout
|
6
|
-
from haiway.helpers.tracing import
|
7
|
-
ArgumentsTrace,
|
8
|
-
ResultTrace,
|
9
|
-
traced,
|
10
|
-
)
|
7
|
+
from haiway.helpers.tracing import ResultTrace, traced
|
11
8
|
|
12
9
|
__all__ = (
|
13
|
-
"ArgumentsTrace",
|
14
10
|
"CacheMakeKey",
|
15
11
|
"CacheRead",
|
16
12
|
"CacheWrite",
|
13
|
+
"LoggerObservability",
|
17
14
|
"ResultTrace",
|
18
15
|
"asynchronous",
|
19
16
|
"cache",
|
@@ -3,7 +3,9 @@ from time import monotonic
|
|
3
3
|
from typing import Any
|
4
4
|
|
5
5
|
from haiway.context import Observability, ObservabilityLevel, ScopeIdentifier
|
6
|
+
from haiway.context.observability import ObservabilityAttribute
|
6
7
|
from haiway.state import State
|
8
|
+
from haiway.types import MISSING
|
7
9
|
|
8
10
|
__all__ = ("LoggerObservability",)
|
9
11
|
|
@@ -60,7 +62,7 @@ class ScopeStore:
|
|
60
62
|
return True # successfully completed
|
61
63
|
|
62
64
|
|
63
|
-
def LoggerObservability( # noqa: C901
|
65
|
+
def LoggerObservability( # noqa: C901, PLR0915
|
64
66
|
logger: Logger,
|
65
67
|
/,
|
66
68
|
*,
|
@@ -76,6 +78,7 @@ def LoggerObservability( # noqa: C901
|
|
76
78
|
message: str,
|
77
79
|
*args: Any,
|
78
80
|
exception: BaseException | None,
|
81
|
+
**extra: Any,
|
79
82
|
) -> None:
|
80
83
|
assert root_scope is not None # nosec: B101
|
81
84
|
assert scope.scope_id in scopes # nosec: B101
|
@@ -93,6 +96,7 @@ def LoggerObservability( # noqa: C901
|
|
93
96
|
*,
|
94
97
|
level: ObservabilityLevel,
|
95
98
|
event: State,
|
99
|
+
**extra: Any,
|
96
100
|
) -> None:
|
97
101
|
assert root_scope is not None # nosec: B101
|
98
102
|
assert scope.scope_id in scopes # nosec: B101
|
@@ -113,11 +117,12 @@ def LoggerObservability( # noqa: C901
|
|
113
117
|
metric: str,
|
114
118
|
value: float | int,
|
115
119
|
unit: str | None,
|
120
|
+
**extra: Any,
|
116
121
|
) -> None:
|
117
122
|
assert root_scope is not None # nosec: B101
|
118
123
|
assert scope.scope_id in scopes # nosec: B101
|
119
124
|
|
120
|
-
metric_str: str = f"Metric
|
125
|
+
metric_str: str = f"Metric: {metric}={value}{unit or ''}"
|
121
126
|
if summarize_context: # store only for summary
|
122
127
|
scopes[scope.scope_id].store.append(metric_str)
|
123
128
|
|
@@ -126,6 +131,26 @@ def LoggerObservability( # noqa: C901
|
|
126
131
|
f"{scope.unique_name} {metric_str}",
|
127
132
|
)
|
128
133
|
|
134
|
+
def attributes_recording(
|
135
|
+
scope: ScopeIdentifier,
|
136
|
+
/,
|
137
|
+
**attributes: ObservabilityAttribute,
|
138
|
+
) -> None:
|
139
|
+
if not attributes:
|
140
|
+
return
|
141
|
+
|
142
|
+
attributes_str: str = (
|
143
|
+
f"{scope.unique_name} Attributes:"
|
144
|
+
f"\n{'\n'.join(f'{k}: {v}' for k, v in attributes.items() if v is not None and v is not MISSING)}" # noqa: E501
|
145
|
+
)
|
146
|
+
if summarize_context: # store only for summary
|
147
|
+
scopes[scope.scope_id].store.append(attributes_str)
|
148
|
+
|
149
|
+
logger.log(
|
150
|
+
ObservabilityLevel.INFO,
|
151
|
+
attributes_str,
|
152
|
+
)
|
153
|
+
|
129
154
|
def scope_entering[Metric: State](
|
130
155
|
scope: ScopeIdentifier,
|
131
156
|
/,
|
@@ -196,6 +221,7 @@ def LoggerObservability( # noqa: C901
|
|
196
221
|
log_recording=log_recording,
|
197
222
|
event_recording=event_recording,
|
198
223
|
metric_recording=metric_recording,
|
224
|
+
attributes_recording=attributes_recording,
|
199
225
|
scope_entering=scope_entering,
|
200
226
|
scope_exiting=scope_exiting,
|
201
227
|
)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from asyncio import iscoroutinefunction
|
2
|
-
from collections.abc import Callable, Coroutine
|
2
|
+
from collections.abc import Callable, Coroutine
|
3
3
|
from typing import Any, Self, cast, overload
|
4
4
|
|
5
5
|
from haiway.context import ctx
|
@@ -8,43 +8,11 @@ from haiway.types import MISSING, Missing
|
|
8
8
|
from haiway.utils import mimic_function
|
9
9
|
|
10
10
|
__all__ = (
|
11
|
-
"ArgumentsTrace",
|
12
11
|
"ResultTrace",
|
13
12
|
"traced",
|
14
13
|
)
|
15
14
|
|
16
15
|
|
17
|
-
class ArgumentsTrace(State):
|
18
|
-
if __debug__:
|
19
|
-
|
20
|
-
@classmethod
|
21
|
-
def of(
|
22
|
-
cls,
|
23
|
-
*args: Any,
|
24
|
-
**kwargs: Any,
|
25
|
-
) -> Self:
|
26
|
-
return cls(
|
27
|
-
args=[f"{arg}" for arg in args] if args else MISSING,
|
28
|
-
kwargs=[f"{key}:{arg}" for key, arg in kwargs.items()] if kwargs else MISSING,
|
29
|
-
)
|
30
|
-
|
31
|
-
else: # remove tracing for non debug runs to prevent accidental secret leaks
|
32
|
-
|
33
|
-
@classmethod
|
34
|
-
def of(
|
35
|
-
cls,
|
36
|
-
*args: Any,
|
37
|
-
**kwargs: Any,
|
38
|
-
) -> Self:
|
39
|
-
return cls(
|
40
|
-
args=MISSING,
|
41
|
-
kwargs=MISSING,
|
42
|
-
)
|
43
|
-
|
44
|
-
args: Sequence[str] | Missing
|
45
|
-
kwargs: Sequence[str] | Missing
|
46
|
-
|
47
|
-
|
48
16
|
class ResultTrace(State):
|
49
17
|
if __debug__:
|
50
18
|
|
@@ -128,7 +96,11 @@ def _traced_sync[**Args, Result](
|
|
128
96
|
**kwargs: Args.kwargs,
|
129
97
|
) -> Result:
|
130
98
|
with ctx.scope(label):
|
131
|
-
ctx.
|
99
|
+
ctx.attributes(
|
100
|
+
**{f"[{idx}]": f"{arg}" for idx, arg in enumerate(args) if arg is not MISSING}
|
101
|
+
)
|
102
|
+
ctx.attributes(**{key: f"{arg}" for key, arg in kwargs.items() if arg is not MISSING})
|
103
|
+
|
132
104
|
try:
|
133
105
|
result: Result = function(*args, **kwargs)
|
134
106
|
ctx.event(ResultTrace.of(result))
|
@@ -154,7 +126,12 @@ def _traced_async[**Args, Result](
|
|
154
126
|
**kwargs: Args.kwargs,
|
155
127
|
) -> Result:
|
156
128
|
with ctx.scope(label):
|
157
|
-
|
129
|
+
for idx, arg in enumerate(args):
|
130
|
+
ctx.attributes(**{f"[{idx}]": f"{arg}"})
|
131
|
+
|
132
|
+
for key, arg in kwargs.items():
|
133
|
+
ctx.attributes(**{key: f"{arg}"})
|
134
|
+
|
158
135
|
try:
|
159
136
|
result: Result = await function(*args, **kwargs)
|
160
137
|
ctx.event(ResultTrace.of(result))
|