prefect-client 3.1.0__tar.gz → 3.1.1__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.
- {prefect-client-3.1.0/src/prefect_client.egg-info → prefect-client-3.1.1}/PKG-INFO +1 -1
- {prefect-client-3.1.0 → prefect-client-3.1.1}/requirements-dev.txt +9 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/requirements.txt +1 -1
- prefect-client-3.1.1/src/prefect/_internal/compatibility/async_dispatch.py +73 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_version.py +3 -3
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/orchestration.py +11 -9
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/objects.py +21 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/handlers.py +41 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/loggers.py +33 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/logging.yml +8 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/main.py +5 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/api.py +1 -1
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/experiments.py +5 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/logging.py +10 -3
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/root.py +1 -1
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/events.py +1 -1
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/sources.py +21 -0
- prefect-client-3.1.1/src/prefect/telemetry/bootstrap.py +32 -0
- prefect-client-3.1.1/src/prefect/telemetry/instrumentation.py +125 -0
- prefect-client-3.1.1/src/prefect/telemetry/logging.py +26 -0
- prefect-client-3.1.1/src/prefect/telemetry/processors.py +57 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/types/__init__.py +1 -2
- prefect-client-3.1.1/src/prefect/utilities/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/base.py +112 -41
- {prefect-client-3.1.0 → prefect-client-3.1.1/src/prefect_client.egg-info}/PKG-INFO +1 -1
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect_client.egg-info/SOURCES.txt +6 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/LICENSE +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/MANIFEST.in +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/README.md +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/requirements-client.txt +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/setup.cfg +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/setup.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/.prefectignore +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/_logging.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/compatibility/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/compatibility/deprecated.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/compatibility/migration.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/api.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/calls.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/cancellation.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/event_loop.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/inspection.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/primitives.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/services.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/threads.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/concurrency/waiters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/integrations.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/annotations/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/annotations/pendulum.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/schemas.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/v1_schema.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/v2_schema.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pydantic/v2_validated_func.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/pytz.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/retries.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/schemas/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/schemas/bases.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/schemas/fields.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/schemas/serializers.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/_internal/schemas/validators.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/agent.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/artifacts.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/automations.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/abstract.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/core.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/fields.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/notifications.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/redis.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/system.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/blocks/webhook.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/cache_policies.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/base.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/cloud.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/collections.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/constants.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/actions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/filters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/responses.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/schedules.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/schemas/sorting.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/subscriptions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/types/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/types/flexible_schedule_list.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/client/utilities.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/asyncio.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/context.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/events.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/services.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/sync.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/asyncio.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/context.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/events.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/services.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/concurrency/v1/sync.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/context.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/base.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/deployments.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/flow_runs.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/runner.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/schedules.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/steps/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/steps/core.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/steps/pull.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/deployments/steps/utility.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/docker/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/docker/docker_image.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/engine.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/actions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/cli/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/cli/automations.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/clients.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/filters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/related.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/schemas/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/schemas/automations.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/schemas/deployment_triggers.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/schemas/events.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/schemas/labelling.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/utilities.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/events/worker.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/exceptions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/filesystems.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/flow_engine.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/flow_runs.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/flows.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/futures.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/base.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/provisioners/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/provisioners/cloud_run.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/provisioners/container_instance.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/provisioners/ecs.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/infrastructure/provisioners/modal.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/input/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/input/actions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/input/run_input.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/locking/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/locking/filesystem.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/locking/memory.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/locking/protocol.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/configuration.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/filters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/formatters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/logging/highlighters.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/plugins.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/py.typed +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/records/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/records/base.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/records/filesystem.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/records/memory.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/records/result_store.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/results.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/runner.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/server.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/storage.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/submit.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runner/utils.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runtime/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runtime/deployment.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runtime/flow_run.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/runtime/task_run.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/serializers.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/server/api/collections_data/views/aggregate-worker-metadata.json +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/server/api/static/prefect-logo-mark-gradient.png +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/base.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/constants.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/context.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/legacy.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/cli.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/client.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/cloud.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/deployments.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/flows.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/internal.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/results.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/runner.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/api.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/database.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/deployments.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/ephemeral.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/flow_run_graph.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/root.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/services.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/tasks.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/server/ui.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/tasks.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/testing.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/models/worker.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/profiles.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/settings/profiles.toml +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/states.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/task_engine.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/task_runners.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/task_runs.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/task_worker.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/tasks.py +0 -0
- {prefect-client-3.1.0/src/prefect/utilities → prefect-client-3.1.1/src/prefect/telemetry}/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/transactions.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/types/entrypoint.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/annotations.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/asyncutils.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/callables.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/collections.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/compat.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/context.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/dispatch.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/dockerutils.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/engine.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/filesystem.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/hashing.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/importtools.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/math.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/names.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/processutils.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/pydantic.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/render_swagger.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/schema_tools/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/schema_tools/hydration.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/schema_tools/validation.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/services.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/slugify.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/templating.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/text.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/timeout.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/urls.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/utilities/visualization.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/variables.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/__init__.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/block.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/cloud.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/process.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/server.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect/workers/utilities.py +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect_client.egg-info/dependency_links.txt +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect_client.egg-info/requires.txt +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/src/prefect_client.egg-info/top_level.txt +0 -0
- {prefect-client-3.1.0 → prefect-client-3.1.1}/versioneer.py +0 -0
@@ -36,3 +36,12 @@ mkdocs
|
|
36
36
|
mkdocs-material
|
37
37
|
mkdocstrings[python]
|
38
38
|
mkdocs-gen-files
|
39
|
+
|
40
|
+
# OpenTelemetry
|
41
|
+
# Other than the `test-utils` package these versions should match the versions
|
42
|
+
# in `requirements-otel.txt`
|
43
|
+
opentelemetry-distro >= 0.48b0, < 1.0.0
|
44
|
+
opentelemetry-exporter-otlp >= 1.27.0, < 2.0.0
|
45
|
+
opentelemetry-instrumentation >= 0.48b0, < 1.0.0
|
46
|
+
opentelemetry-instrumentation-logging >= 0.48b0, < 1.0.0
|
47
|
+
opentelemetry-test-utils >= 0.48b0, < 1.0.0
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import asyncio
|
2
|
+
import inspect
|
3
|
+
from functools import wraps
|
4
|
+
from typing import Any, Callable, Coroutine, Protocol, TypeVar, Union
|
5
|
+
|
6
|
+
from typing_extensions import ParamSpec
|
7
|
+
|
8
|
+
R = TypeVar("R")
|
9
|
+
P = ParamSpec("P")
|
10
|
+
|
11
|
+
|
12
|
+
class AsyncDispatchable(Protocol[P, R]):
|
13
|
+
"""Protocol for functions decorated with async_dispatch."""
|
14
|
+
|
15
|
+
def __call__(
|
16
|
+
self, *args: P.args, **kwargs: P.kwargs
|
17
|
+
) -> Union[R, Coroutine[Any, Any, R]]:
|
18
|
+
...
|
19
|
+
|
20
|
+
aio: Callable[P, Coroutine[Any, Any, R]]
|
21
|
+
sync: Callable[P, R]
|
22
|
+
|
23
|
+
|
24
|
+
def is_in_async_context() -> bool:
|
25
|
+
"""Check if we're in an async context."""
|
26
|
+
try:
|
27
|
+
# First check if we're in a coroutine
|
28
|
+
if asyncio.current_task() is not None:
|
29
|
+
return True
|
30
|
+
|
31
|
+
# Check if we have a loop and it's running
|
32
|
+
loop = asyncio.get_event_loop()
|
33
|
+
return loop.is_running()
|
34
|
+
except RuntimeError:
|
35
|
+
return False
|
36
|
+
|
37
|
+
|
38
|
+
def async_dispatch(
|
39
|
+
async_impl: Callable[P, Coroutine[Any, Any, R]],
|
40
|
+
) -> Callable[[Callable[P, R]], AsyncDispatchable[P, R]]:
|
41
|
+
"""
|
42
|
+
Decorator that adds async compatibility to a sync function.
|
43
|
+
|
44
|
+
The decorated function will:
|
45
|
+
- Return a coroutine when in an async context (detected via running event loop)
|
46
|
+
- Run synchronously when in a sync context
|
47
|
+
- Provide .aio for explicit async access
|
48
|
+
- Provide .sync for explicit sync access
|
49
|
+
|
50
|
+
Args:
|
51
|
+
async_impl: The async implementation to dispatch to when async execution
|
52
|
+
is needed
|
53
|
+
"""
|
54
|
+
if not inspect.iscoroutinefunction(async_impl):
|
55
|
+
raise TypeError(
|
56
|
+
"async_impl must be an async function to dispatch in async contexts"
|
57
|
+
)
|
58
|
+
|
59
|
+
def decorator(sync_fn: Callable[P, R]) -> AsyncDispatchable[P, R]:
|
60
|
+
@wraps(sync_fn)
|
61
|
+
def wrapper(
|
62
|
+
*args: P.args, **kwargs: P.kwargs
|
63
|
+
) -> Union[R, Coroutine[Any, Any, R]]:
|
64
|
+
if is_in_async_context():
|
65
|
+
return async_impl(*args, **kwargs)
|
66
|
+
return sync_fn(*args, **kwargs)
|
67
|
+
|
68
|
+
# Attach both async and sync implementations directly
|
69
|
+
wrapper.aio = async_impl
|
70
|
+
wrapper.sync = sync_fn
|
71
|
+
return wrapper # type: ignore
|
72
|
+
|
73
|
+
return decorator
|
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2024-
|
11
|
+
"date": "2024-11-08T12:38:16-0800",
|
12
12
|
"dirty": true,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "3.1.
|
14
|
+
"full-revisionid": "6b50a2b9f9d4ebf59703c55e1156c6f79151f1c3",
|
15
|
+
"version": "3.1.1"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
@@ -99,6 +99,7 @@ from prefect.client.schemas.objects import (
|
|
99
99
|
TaskRunResult,
|
100
100
|
Variable,
|
101
101
|
Worker,
|
102
|
+
WorkerMetadata,
|
102
103
|
WorkPool,
|
103
104
|
WorkQueue,
|
104
105
|
WorkQueueStatusDetail,
|
@@ -2596,6 +2597,7 @@ class PrefectClient:
|
|
2596
2597
|
worker_name: str,
|
2597
2598
|
heartbeat_interval_seconds: Optional[float] = None,
|
2598
2599
|
get_worker_id: bool = False,
|
2600
|
+
worker_metadata: Optional[WorkerMetadata] = None,
|
2599
2601
|
) -> Optional[UUID]:
|
2600
2602
|
"""
|
2601
2603
|
Sends a worker heartbeat for a given work pool.
|
@@ -2604,20 +2606,20 @@ class PrefectClient:
|
|
2604
2606
|
work_pool_name: The name of the work pool to heartbeat against.
|
2605
2607
|
worker_name: The name of the worker sending the heartbeat.
|
2606
2608
|
return_id: Whether to return the worker ID. Note: will return `None` if the connected server does not support returning worker IDs, even if `return_id` is `True`.
|
2609
|
+
worker_metadata: Metadata about the worker to send to the server.
|
2607
2610
|
"""
|
2608
|
-
|
2611
|
+
params = {
|
2612
|
+
"name": worker_name,
|
2613
|
+
"heartbeat_interval_seconds": heartbeat_interval_seconds,
|
2614
|
+
}
|
2615
|
+
if worker_metadata:
|
2616
|
+
params["worker_metadata"] = worker_metadata.model_dump(mode="json")
|
2609
2617
|
if get_worker_id:
|
2610
|
-
|
2611
|
-
else:
|
2612
|
-
return_dict = {}
|
2618
|
+
params["return_id"] = get_worker_id
|
2613
2619
|
|
2614
2620
|
resp = await self._client.post(
|
2615
2621
|
f"/work_pools/{work_pool_name}/workers/heartbeat",
|
2616
|
-
json=
|
2617
|
-
"name": worker_name,
|
2618
|
-
"heartbeat_interval_seconds": heartbeat_interval_seconds,
|
2619
|
-
}
|
2620
|
-
| return_dict,
|
2622
|
+
json=params,
|
2621
2623
|
)
|
2622
2624
|
|
2623
2625
|
if (
|
@@ -1689,3 +1689,24 @@ class CsrfToken(ObjectBaseModel):
|
|
1689
1689
|
|
1690
1690
|
|
1691
1691
|
__getattr__ = getattr_migration(__name__)
|
1692
|
+
|
1693
|
+
|
1694
|
+
class Integration(PrefectBaseModel):
|
1695
|
+
"""A representation of an installed Prefect integration."""
|
1696
|
+
|
1697
|
+
name: str = Field(description="The name of the Prefect integration.")
|
1698
|
+
version: str = Field(description="The version of the Prefect integration.")
|
1699
|
+
|
1700
|
+
|
1701
|
+
class WorkerMetadata(PrefectBaseModel):
|
1702
|
+
"""
|
1703
|
+
Worker metadata.
|
1704
|
+
|
1705
|
+
We depend on the structure of `integrations`, but otherwise, worker classes
|
1706
|
+
should support flexible metadata.
|
1707
|
+
"""
|
1708
|
+
|
1709
|
+
integrations: List[Integration] = Field(
|
1710
|
+
default=..., description="Prefect integrations installed in the worker."
|
1711
|
+
)
|
1712
|
+
model_config = ConfigDict(extra="allow")
|
@@ -32,6 +32,7 @@ from prefect.settings import (
|
|
32
32
|
PREFECT_LOGGING_TO_API_BATCH_SIZE,
|
33
33
|
PREFECT_LOGGING_TO_API_MAX_LOG_SIZE,
|
34
34
|
PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW,
|
35
|
+
get_current_settings,
|
35
36
|
)
|
36
37
|
|
37
38
|
|
@@ -180,6 +181,7 @@ class APILogHandler(logging.Handler):
|
|
180
181
|
"""
|
181
182
|
flow_run_id = getattr(record, "flow_run_id", None)
|
182
183
|
task_run_id = getattr(record, "task_run_id", None)
|
184
|
+
worker_id = getattr(record, "worker_id", None)
|
183
185
|
|
184
186
|
if not flow_run_id:
|
185
187
|
try:
|
@@ -215,6 +217,7 @@ class APILogHandler(logging.Handler):
|
|
215
217
|
log = LogCreate(
|
216
218
|
flow_run_id=flow_run_id if is_uuid_like else None,
|
217
219
|
task_run_id=task_run_id,
|
220
|
+
worker_id=worker_id,
|
218
221
|
name=record.name,
|
219
222
|
level=record.levelno,
|
220
223
|
timestamp=pendulum.from_timestamp(
|
@@ -236,6 +239,44 @@ class APILogHandler(logging.Handler):
|
|
236
239
|
return len(json.dumps(log).encode())
|
237
240
|
|
238
241
|
|
242
|
+
class WorkerAPILogHandler(APILogHandler):
|
243
|
+
def emit(self, record: logging.LogRecord):
|
244
|
+
if get_current_settings().experiments.worker_logging_to_api_enabled:
|
245
|
+
super().emit(record)
|
246
|
+
else:
|
247
|
+
return
|
248
|
+
|
249
|
+
def prepare(self, record: logging.LogRecord) -> Dict[str, Any]:
|
250
|
+
"""
|
251
|
+
Convert a `logging.LogRecord` to the API `LogCreate` schema and serialize.
|
252
|
+
|
253
|
+
This will add in the worker id to the log.
|
254
|
+
|
255
|
+
Logs exceeding the maximum size will be dropped.
|
256
|
+
"""
|
257
|
+
|
258
|
+
worker_id = getattr(record, "worker_id", None)
|
259
|
+
|
260
|
+
log = LogCreate(
|
261
|
+
worker_id=worker_id,
|
262
|
+
name=record.name,
|
263
|
+
level=record.levelno,
|
264
|
+
timestamp=pendulum.from_timestamp(
|
265
|
+
getattr(record, "created", None) or time.time()
|
266
|
+
),
|
267
|
+
message=self.format(record),
|
268
|
+
).model_dump(mode="json")
|
269
|
+
|
270
|
+
log_size = log["__payload_size__"] = self._get_payload_size(log)
|
271
|
+
if log_size > PREFECT_LOGGING_TO_API_MAX_LOG_SIZE.value():
|
272
|
+
raise ValueError(
|
273
|
+
f"Log of size {log_size} is greater than the max size of "
|
274
|
+
f"{PREFECT_LOGGING_TO_API_MAX_LOG_SIZE.value()}"
|
275
|
+
)
|
276
|
+
|
277
|
+
return log
|
278
|
+
|
279
|
+
|
239
280
|
class PrefectConsoleHandler(logging.StreamHandler):
|
240
281
|
def __init__(
|
241
282
|
self,
|
@@ -12,6 +12,7 @@ from typing_extensions import Self
|
|
12
12
|
import prefect
|
13
13
|
from prefect.exceptions import MissingContextError
|
14
14
|
from prefect.logging.filters import ObfuscateApiKeyFilter
|
15
|
+
from prefect.telemetry.logging import add_telemetry_log_handler
|
15
16
|
|
16
17
|
if TYPE_CHECKING:
|
17
18
|
from prefect.client.schemas import FlowRun as ClientFlowRun
|
@@ -19,6 +20,7 @@ if TYPE_CHECKING:
|
|
19
20
|
from prefect.context import RunContext
|
20
21
|
from prefect.flows import Flow
|
21
22
|
from prefect.tasks import Task
|
23
|
+
from prefect.workers.base import BaseWorker
|
22
24
|
|
23
25
|
|
24
26
|
class PrefectLogAdapter(logging.LoggerAdapter):
|
@@ -75,6 +77,8 @@ def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|
75
77
|
obfuscate_api_key_filter = ObfuscateApiKeyFilter()
|
76
78
|
logger.addFilter(obfuscate_api_key_filter)
|
77
79
|
|
80
|
+
add_telemetry_log_handler(logger=logger)
|
81
|
+
|
78
82
|
return logger
|
79
83
|
|
80
84
|
|
@@ -136,6 +140,12 @@ def get_run_logger(
|
|
136
140
|
else:
|
137
141
|
raise MissingContextError("There is no active flow or task run context.")
|
138
142
|
|
143
|
+
if isinstance(logger, logging.LoggerAdapter):
|
144
|
+
assert isinstance(logger.logger, logging.Logger)
|
145
|
+
add_telemetry_log_handler(logger.logger)
|
146
|
+
else:
|
147
|
+
add_telemetry_log_handler(logger)
|
148
|
+
|
139
149
|
return logger
|
140
150
|
|
141
151
|
|
@@ -205,6 +215,29 @@ def task_run_logger(
|
|
205
215
|
)
|
206
216
|
|
207
217
|
|
218
|
+
def get_worker_logger(worker: "BaseWorker", name: Optional[str] = None):
|
219
|
+
"""
|
220
|
+
Create a worker logger with the worker's metadata attached.
|
221
|
+
|
222
|
+
If the worker has a backend_id, it will be attached to the log records.
|
223
|
+
If the worker does not have a backend_id a basic logger will be returned.
|
224
|
+
If the worker does not have a backend_id attribute, a basic logger will be returned.
|
225
|
+
"""
|
226
|
+
|
227
|
+
worker_log_name = name or f"workers.{worker.__class__.type}.{worker.name.lower()}"
|
228
|
+
|
229
|
+
worker_id = getattr(worker, "backend_id", None)
|
230
|
+
if worker_id:
|
231
|
+
return PrefectLogAdapter(
|
232
|
+
get_logger(worker_log_name),
|
233
|
+
extra={
|
234
|
+
"worker_id": str(worker.backend_id),
|
235
|
+
},
|
236
|
+
)
|
237
|
+
else:
|
238
|
+
return get_logger(worker_log_name)
|
239
|
+
|
240
|
+
|
208
241
|
@contextmanager
|
209
242
|
def disable_logger(name: str):
|
210
243
|
"""
|
@@ -69,6 +69,10 @@ handlers:
|
|
69
69
|
class: logging.StreamHandler
|
70
70
|
formatter: debug
|
71
71
|
|
72
|
+
worker_api:
|
73
|
+
level: 0
|
74
|
+
class: prefect.logging.handlers.WorkerAPILogHandler
|
75
|
+
|
72
76
|
loggers:
|
73
77
|
prefect:
|
74
78
|
level: "${PREFECT_LOGGING_LEVEL}"
|
@@ -86,6 +90,10 @@ loggers:
|
|
86
90
|
level: NOTSET
|
87
91
|
handlers: [api]
|
88
92
|
|
93
|
+
prefect.workers:
|
94
|
+
level: NOTSET
|
95
|
+
handlers: [worker_api]
|
96
|
+
|
89
97
|
prefect.server:
|
90
98
|
level: "${PREFECT_SERVER_LOGGING_LEVEL}"
|
91
99
|
|
@@ -57,6 +57,11 @@ prefect.logging.get_logger("profiles").debug(
|
|
57
57
|
f"Using profile {prefect.context.get_settings_context().profile.name!r}"
|
58
58
|
)
|
59
59
|
|
60
|
+
# Configure telemetry
|
61
|
+
import prefect.telemetry.bootstrap
|
62
|
+
|
63
|
+
prefect.telemetry.bootstrap.setup_telemetry()
|
64
|
+
|
60
65
|
|
61
66
|
from prefect._internal.compatibility.deprecated import (
|
62
67
|
inject_renamed_module_alias_finder,
|
@@ -25,7 +25,7 @@ class APISettings(PrefectBaseSettings):
|
|
25
25
|
)
|
26
26
|
tls_insecure_skip_verify: bool = Field(
|
27
27
|
default=False,
|
28
|
-
description="If `True`, disables SSL checking to allow insecure requests.
|
28
|
+
description="If `True`, disables SSL checking to allow insecure requests. Setting to False is recommended only during development. For example, when using self-signed certificates.",
|
29
29
|
)
|
30
30
|
ssl_cert_file: Optional[str] = Field(
|
31
31
|
default=os.environ.get("SSL_CERT_FILE"),
|
@@ -22,3 +22,8 @@ class ExperimentsSettings(PrefectBaseSettings):
|
|
22
22
|
default=False,
|
23
23
|
description="Enables the logging of worker logs to Prefect Cloud.",
|
24
24
|
)
|
25
|
+
|
26
|
+
telemetry_enabled: bool = Field(
|
27
|
+
default=False,
|
28
|
+
description="Enables sending telemetry to Prefect Cloud.",
|
29
|
+
)
|
@@ -1,11 +1,18 @@
|
|
1
|
+
from functools import partial
|
1
2
|
from pathlib import Path
|
2
3
|
from typing import Annotated, Literal, Optional, Union
|
3
4
|
|
4
|
-
from pydantic import
|
5
|
+
from pydantic import (
|
6
|
+
AliasChoices,
|
7
|
+
AliasPath,
|
8
|
+
BeforeValidator,
|
9
|
+
Field,
|
10
|
+
model_validator,
|
11
|
+
)
|
5
12
|
from typing_extensions import Self
|
6
13
|
|
7
14
|
from prefect.settings.base import PrefectBaseSettings, _build_settings_config
|
8
|
-
from prefect.types import LogLevel
|
15
|
+
from prefect.types import LogLevel, validate_set_T_from_delim_string
|
9
16
|
|
10
17
|
|
11
18
|
def max_log_size_smaller_than_batch_size(values):
|
@@ -97,7 +104,7 @@ class LoggingSettings(PrefectBaseSettings):
|
|
97
104
|
|
98
105
|
extra_loggers: Annotated[
|
99
106
|
Union[str, list[str], None],
|
100
|
-
|
107
|
+
BeforeValidator(partial(validate_set_T_from_delim_string, type_=str)),
|
101
108
|
] = Field(
|
102
109
|
default=None,
|
103
110
|
description="Additional loggers to attach to Prefect logging at runtime.",
|
@@ -72,7 +72,7 @@ class Settings(PrefectBaseSettings):
|
|
72
72
|
|
73
73
|
client: ClientSettings = Field(
|
74
74
|
default_factory=ClientSettings,
|
75
|
-
description="Settings for
|
75
|
+
description="Settings for controlling API client behavior",
|
76
76
|
)
|
77
77
|
|
78
78
|
cloud: CloudSettings = Field(
|
@@ -128,7 +128,7 @@ class ServerEventsSettings(PrefectBaseSettings):
|
|
128
128
|
|
129
129
|
messaging_cache: str = Field(
|
130
130
|
default="prefect.server.utilities.messaging.memory",
|
131
|
-
description="Which cache implementation to use for the events system.
|
131
|
+
description="Which cache implementation to use for the events system. Should point to a module that exports a Cache class.",
|
132
132
|
validation_alias=AliasChoices(
|
133
133
|
AliasPath("messaging_cache"),
|
134
134
|
"prefect_server_events_messaging_cache",
|
@@ -4,6 +4,7 @@ import warnings
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, Dict, List, Optional, Tuple, Type
|
6
6
|
|
7
|
+
import dotenv
|
7
8
|
import toml
|
8
9
|
from pydantic import AliasChoices
|
9
10
|
from pydantic.fields import FieldInfo
|
@@ -15,6 +16,7 @@ from pydantic_settings import (
|
|
15
16
|
from pydantic_settings.sources import ConfigFileSourceMixin
|
16
17
|
|
17
18
|
from prefect.settings.constants import DEFAULT_PREFECT_HOME, DEFAULT_PROFILES_PATH
|
19
|
+
from prefect.utilities.collections import get_from_dict
|
18
20
|
|
19
21
|
|
20
22
|
class EnvFilterSettingsSource(EnvSettingsSource):
|
@@ -230,6 +232,25 @@ def _get_profiles_path() -> Path:
|
|
230
232
|
return DEFAULT_PROFILES_PATH
|
231
233
|
if env_path := os.getenv("PREFECT_PROFILES_PATH"):
|
232
234
|
return Path(env_path)
|
235
|
+
if dotenv_path := dotenv.dotenv_values(".env").get("PREFECT_PROFILES_PATH"):
|
236
|
+
return Path(dotenv_path)
|
237
|
+
if toml_path := _get_profiles_path_from_toml("prefect.toml", ["profiles_path"]):
|
238
|
+
return Path(toml_path)
|
239
|
+
if pyproject_path := _get_profiles_path_from_toml(
|
240
|
+
"pyproject.toml", ["tool", "prefect", "profiles_path"]
|
241
|
+
):
|
242
|
+
return Path(pyproject_path)
|
233
243
|
if not (DEFAULT_PREFECT_HOME / "profiles.toml").exists():
|
234
244
|
return DEFAULT_PROFILES_PATH
|
235
245
|
return DEFAULT_PREFECT_HOME / "profiles.toml"
|
246
|
+
|
247
|
+
|
248
|
+
def _get_profiles_path_from_toml(path: str, keys: List[str]) -> Optional[str]:
|
249
|
+
"""Helper to get the profiles path from a toml file."""
|
250
|
+
|
251
|
+
try:
|
252
|
+
toml_data = toml.load(path)
|
253
|
+
except FileNotFoundError:
|
254
|
+
return None
|
255
|
+
|
256
|
+
return get_from_dict(toml_data, keys)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Union
|
2
|
+
|
3
|
+
import prefect.settings
|
4
|
+
from prefect.client.base import ServerType, determine_server_type
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from opentelemetry.sdk._logs import LoggerProvider
|
8
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
9
|
+
from opentelemetry.sdk.trace import TracerProvider
|
10
|
+
|
11
|
+
|
12
|
+
def setup_telemetry() -> (
|
13
|
+
Union[
|
14
|
+
tuple["TracerProvider", "MeterProvider", "LoggerProvider"],
|
15
|
+
tuple[None, None, None],
|
16
|
+
]
|
17
|
+
):
|
18
|
+
settings = prefect.settings.get_current_settings()
|
19
|
+
if not settings.experiments.telemetry_enabled:
|
20
|
+
return None, None, None
|
21
|
+
|
22
|
+
server_type = determine_server_type()
|
23
|
+
if server_type != ServerType.CLOUD:
|
24
|
+
return None, None, None
|
25
|
+
|
26
|
+
assert settings.api.key
|
27
|
+
assert settings.api.url
|
28
|
+
|
29
|
+
# This import is here to defer importing of the `opentelemetry` packages.
|
30
|
+
from .instrumentation import setup_exporters
|
31
|
+
|
32
|
+
return setup_exporters(settings.api.url, settings.api.key.get_secret_value())
|
@@ -0,0 +1,125 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
from typing import TYPE_CHECKING
|
5
|
+
from urllib.parse import urljoin
|
6
|
+
from uuid import UUID
|
7
|
+
|
8
|
+
from opentelemetry import metrics, trace
|
9
|
+
from opentelemetry._logs import set_logger_provider
|
10
|
+
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
|
11
|
+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
|
12
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
13
|
+
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
|
14
|
+
from opentelemetry.sdk._logs.export import SimpleLogRecordProcessor
|
15
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
16
|
+
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
17
|
+
from opentelemetry.sdk.resources import Resource
|
18
|
+
from opentelemetry.sdk.trace import TracerProvider
|
19
|
+
|
20
|
+
from .logging import set_log_handler
|
21
|
+
from .processors import InFlightSpanProcessor
|
22
|
+
|
23
|
+
if TYPE_CHECKING:
|
24
|
+
from opentelemetry.sdk._logs import LoggerProvider
|
25
|
+
|
26
|
+
UUID_REGEX = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
27
|
+
|
28
|
+
ACCOUNTS_PREFIX = "accounts/"
|
29
|
+
ACCOUNT_ID_REGEX = f"{ACCOUNTS_PREFIX}{UUID_REGEX}"
|
30
|
+
|
31
|
+
WORKSPACES_PREFIX = "workspaces/"
|
32
|
+
WORKSPACE_ID_REGEX = f"{WORKSPACES_PREFIX}{UUID_REGEX}"
|
33
|
+
|
34
|
+
|
35
|
+
def extract_account_and_workspace_id(url: str) -> tuple[UUID, UUID]:
|
36
|
+
account_id, workspace_id = None, None
|
37
|
+
|
38
|
+
if res := re.search(ACCOUNT_ID_REGEX, url):
|
39
|
+
account_id = UUID(res.group().removeprefix(ACCOUNTS_PREFIX))
|
40
|
+
|
41
|
+
if res := re.search(WORKSPACE_ID_REGEX, url):
|
42
|
+
workspace_id = UUID(res.group().removeprefix(WORKSPACES_PREFIX))
|
43
|
+
|
44
|
+
if account_id and workspace_id:
|
45
|
+
return account_id, workspace_id
|
46
|
+
|
47
|
+
raise ValueError(
|
48
|
+
f"Could not extract account and workspace id from API url: {url!r}"
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
def _url_join(base_url: str, path: str) -> str:
|
53
|
+
return urljoin(base_url.rstrip("/") + "/", path.lstrip("/"))
|
54
|
+
|
55
|
+
|
56
|
+
def setup_exporters(
|
57
|
+
api_url: str, api_key: str
|
58
|
+
) -> tuple[TracerProvider, MeterProvider, "LoggerProvider"]:
|
59
|
+
account_id, workspace_id = extract_account_and_workspace_id(api_url)
|
60
|
+
telemetry_url = _url_join(api_url, "telemetry/")
|
61
|
+
|
62
|
+
headers = {
|
63
|
+
"Authorization": f"Bearer {api_key}",
|
64
|
+
}
|
65
|
+
|
66
|
+
resource = Resource.create(
|
67
|
+
{
|
68
|
+
"service.name": "prefect",
|
69
|
+
"service.instance.id": os.uname().nodename,
|
70
|
+
"prefect.account": str(account_id),
|
71
|
+
"prefect.workspace": str(workspace_id),
|
72
|
+
}
|
73
|
+
)
|
74
|
+
|
75
|
+
trace_provider = _setup_trace_provider(resource, headers, telemetry_url)
|
76
|
+
meter_provider = _setup_meter_provider(resource, headers, telemetry_url)
|
77
|
+
logger_provider = _setup_logger_provider(resource, headers, telemetry_url)
|
78
|
+
|
79
|
+
return trace_provider, meter_provider, logger_provider
|
80
|
+
|
81
|
+
|
82
|
+
def _setup_trace_provider(
|
83
|
+
resource: Resource, headers: dict[str, str], telemetry_url: str
|
84
|
+
) -> TracerProvider:
|
85
|
+
trace_provider = TracerProvider(resource=resource)
|
86
|
+
otlp_span_exporter = OTLPSpanExporter(
|
87
|
+
endpoint=_url_join(telemetry_url, "v1/traces"),
|
88
|
+
headers=headers,
|
89
|
+
)
|
90
|
+
trace_provider.add_span_processor(InFlightSpanProcessor(otlp_span_exporter))
|
91
|
+
trace.set_tracer_provider(trace_provider)
|
92
|
+
|
93
|
+
return trace_provider
|
94
|
+
|
95
|
+
|
96
|
+
def _setup_meter_provider(
|
97
|
+
resource: Resource, headers: dict[str, str], telemetry_url: str
|
98
|
+
) -> MeterProvider:
|
99
|
+
metric_reader = PeriodicExportingMetricReader(
|
100
|
+
OTLPMetricExporter(
|
101
|
+
endpoint=_url_join(telemetry_url, "v1/metrics"),
|
102
|
+
headers=headers,
|
103
|
+
)
|
104
|
+
)
|
105
|
+
meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
|
106
|
+
metrics.set_meter_provider(meter_provider)
|
107
|
+
|
108
|
+
return meter_provider
|
109
|
+
|
110
|
+
|
111
|
+
def _setup_logger_provider(
|
112
|
+
resource: Resource, headers: dict[str, str], telemetry_url: str
|
113
|
+
) -> LoggerProvider:
|
114
|
+
logger_provider = LoggerProvider(resource=resource)
|
115
|
+
otlp_exporter = OTLPLogExporter(
|
116
|
+
endpoint=_url_join(telemetry_url, "v1/logs"),
|
117
|
+
headers=headers,
|
118
|
+
)
|
119
|
+
logger_provider.add_log_record_processor(SimpleLogRecordProcessor(otlp_exporter))
|
120
|
+
set_logger_provider(logger_provider)
|
121
|
+
log_handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)
|
122
|
+
|
123
|
+
set_log_handler(log_handler)
|
124
|
+
|
125
|
+
return logger_provider
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
3
|
+
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from opentelemetry.sdk._logs import LoggingHandler
|
6
|
+
|
7
|
+
_log_handler: Optional["LoggingHandler"] = None
|
8
|
+
|
9
|
+
|
10
|
+
def set_log_handler(log_handler: Optional["LoggingHandler"]) -> None:
|
11
|
+
"""Set the OTLP log handler."""
|
12
|
+
global _log_handler
|
13
|
+
_log_handler = log_handler
|
14
|
+
|
15
|
+
|
16
|
+
def get_log_handler() -> Optional["LoggingHandler"]:
|
17
|
+
"""Get the OTLP log handler."""
|
18
|
+
global _log_handler
|
19
|
+
return _log_handler
|
20
|
+
|
21
|
+
|
22
|
+
def add_telemetry_log_handler(logger: logging.Logger) -> None:
|
23
|
+
"""Add the OTLP log handler to the given logger if the log handler has
|
24
|
+
been configured."""
|
25
|
+
if log_handler := get_log_handler():
|
26
|
+
logger.addHandler(log_handler)
|