port-ocean 0.23.3__tar.gz → 0.23.4__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.
Potentially problematic release.
This version of port-ocean might be problematic. Click here for more details.
- {port_ocean-0.23.3 → port_ocean-0.23.4}/PKG-INFO +1 -1
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/integrations.py +3 -2
- port_ocean-0.23.4/port_ocean/context/metric_resource.py +63 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/resync_state_updater/updater.py +3 -3
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/sync_raw.py +106 -63
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/metric/metric.py +32 -10
- port_ocean-0.23.4/port_ocean/helpers/metric/utils.py +52 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +29 -5
- {port_ocean-0.23.3 → port_ocean-0.23.4}/pyproject.toml +1 -1
- port_ocean-0.23.3/port_ocean/helpers/metric/utils.py +0 -28
- {port_ocean-0.23.3 → port_ocean-0.23.4}/LICENSE.md +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/README.md +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.Deb +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.alpine +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.base.builder +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.base.runner +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.dockerignore +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Dockerfile.local +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/Makefile +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/entry_local.sh +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/grpcio.sh +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/integrations/_infra/init.sh +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.23.3/port_ocean/tests/helpers → port_ocean-0.23.4/port_ocean/cache}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/disk.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/errors.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cache/memory.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.23.3/port_ocean/tests/clients/oauth → port_ocean-0.23.4/port_ocean/cli/cookiecutter}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.23.3/port_ocean/tests/clients → port_ocean-0.23.4/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.23.3/port_ocean/tests → port_ocean-0.23.4/port_ocean/clients}/__init__.py +0 -0
- {port_ocean-0.23.3/port_ocean/log → port_ocean-0.23.4/port_ocean/clients/auth}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/auth/auth_client.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/auth/oauth_client.py +0 -0
- {port_ocean-0.23.3/port_ocean/helpers → port_ocean-0.23.4/port_ocean/clients/port}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/authentication.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/client.py +0 -0
- {port_ocean-0.23.3/port_ocean/exceptions → port_ocean-0.23.4/port_ocean/clients/port/mixins}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/blueprints.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/entities.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/mixins/organization.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/retry_transport.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/clients/port/utils.py +0 -0
- {port_ocean-0.23.3/port_ocean/core/integrations → port_ocean-0.23.4/port_ocean/config}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/config/settings.py +0 -0
- {port_ocean-0.23.3/port_ocean/core/handlers/webhook → port_ocean-0.23.4/port_ocean/consumers}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.23.3/port_ocean/core/handlers/entities_state_applier/port → port_ocean-0.23.4/port_ocean/context}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/event.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/ocean.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/defaults/initialize.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/factory.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/http.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/kafka.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/once.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/polling.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/event_listener/webhooks_only.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.23.3/port_ocean/context → port_ocean-0.23.4/port_ocean/core/handlers/entities_state_applier/port}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/queue/local_queue.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
- {port_ocean-0.23.3/port_ocean/consumers → port_ocean-0.23.4/port_ocean/core/handlers/webhook}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
- {port_ocean-0.23.3/port_ocean/config → port_ocean-0.23.4/port_ocean/core/integrations}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/live_events.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/integrations/mixins/utils.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/models.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/utils/utils.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/debug_cli.py +0 -0
- {port_ocean-0.23.3/port_ocean/clients/port/mixins → port_ocean-0.23.4/port_ocean/exceptions}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/exceptions/webhook_processor.py +0 -0
- {port_ocean-0.23.3/port_ocean/clients/port → port_ocean-0.23.4/port_ocean/helpers}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/async_client.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/helpers/retry.py +0 -0
- {port_ocean-0.23.3/port_ocean/clients/auth → port_ocean-0.23.4/port_ocean/log}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/handlers.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/logger_setup.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/ocean.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/py.typed +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/run.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.23.3/port_ocean/clients → port_ocean-0.23.4/port_ocean/tests}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/test_disk_cache.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/cache/test_memory_cache.py +0 -0
- {port_ocean-0.23.3/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests → port_ocean-0.23.4/port_ocean/tests/clients}/__init__.py +0 -0
- {port_ocean-0.23.3/port_ocean/cli/cookiecutter → port_ocean-0.23.4/port_ocean/tests/clients/oauth}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/conftest.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/conftest.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/defaults/test_common.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/mixins/test_live_events.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/test_utils.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
- {port_ocean-0.23.3/port_ocean/cache → port_ocean-0.23.4/port_ocean/tests/helpers}/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/fake_port_api.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/fixtures.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/integration.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/ocean_app.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/port_client.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/helpers/smoke_test.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/log/test_handlers.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_metric.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_ocean.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/test_smoke.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/utils/test_async_iterators.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/utils/test_cache.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/async_http.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/async_iterators.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/cache.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/ipc.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/misc.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/queue_utils.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/signal.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/utils/time.py +0 -0
- {port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/version.py +0 -0
|
@@ -214,8 +214,9 @@ class IntegrationClientMixin:
|
|
|
214
214
|
logger.debug("starting POST metrics request", metrics=metrics)
|
|
215
215
|
metrics_attributes = await self.get_metrics_attributes()
|
|
216
216
|
headers = await self.auth.headers()
|
|
217
|
+
url = metrics_attributes["ingestUrl"] + "/syncMetrics"
|
|
217
218
|
response = await self.client.post(
|
|
218
|
-
|
|
219
|
+
url,
|
|
219
220
|
headers=headers,
|
|
220
221
|
json={
|
|
221
222
|
"syncKindsMetrics": metrics,
|
|
@@ -229,7 +230,7 @@ class IntegrationClientMixin:
|
|
|
229
230
|
metrics_attributes = await self.get_metrics_attributes()
|
|
230
231
|
url = (
|
|
231
232
|
metrics_attributes["ingestUrl"]
|
|
232
|
-
+ f"/resync/{kind_metrics['eventId']}/kind/{kind_metrics['kindIdentifier']}"
|
|
233
|
+
+ f"/syncMetrics/resync/{kind_metrics['eventId']}/kind/{kind_metrics['kindIdentifier']}"
|
|
233
234
|
)
|
|
234
235
|
headers = await self.auth.headers()
|
|
235
236
|
response = await self.client.put(
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import AsyncIterator, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from loguru import logger
|
|
6
|
+
from werkzeug.local import LocalStack, LocalProxy
|
|
7
|
+
|
|
8
|
+
from port_ocean.exceptions.context import (
|
|
9
|
+
ResourceContextNotFoundError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class MetricResourceContext:
|
|
18
|
+
"""
|
|
19
|
+
The metric resource context is a context manager that allows you to access the current metric resource if there is one.
|
|
20
|
+
This is useful for getting the metric resource kind
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
metric_resource_kind: str
|
|
24
|
+
index: int
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def kind(self) -> str:
|
|
28
|
+
return self.metric_resource_kind
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_resource_context_stack: LocalStack[MetricResourceContext] = LocalStack()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _get_metric_resource_context() -> MetricResourceContext:
|
|
35
|
+
"""
|
|
36
|
+
Get the context from the current thread.
|
|
37
|
+
"""
|
|
38
|
+
top_resource_context = _resource_context_stack.top
|
|
39
|
+
if top_resource_context is None:
|
|
40
|
+
raise ResourceContextNotFoundError(
|
|
41
|
+
"You must be inside an metric resource context in order to use it"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return top_resource_context
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
metric_resource: MetricResourceContext = LocalProxy(lambda: _get_metric_resource_context()) # type: ignore
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@asynccontextmanager
|
|
51
|
+
async def metric_resource_context(
|
|
52
|
+
metric_resource_kind: str, index: int = 0
|
|
53
|
+
) -> AsyncIterator[MetricResourceContext]:
|
|
54
|
+
_resource_context_stack.push(
|
|
55
|
+
MetricResourceContext(metric_resource_kind=metric_resource_kind, index=index)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
with logger.contextualize(
|
|
59
|
+
metric_resource_kind=metric_resource.metric_resource_kind
|
|
60
|
+
):
|
|
61
|
+
yield metric_resource
|
|
62
|
+
|
|
63
|
+
_resource_context_stack.pop()
|
{port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/core/handlers/resync_state_updater/updater.py
RENAMED
|
@@ -94,6 +94,6 @@ class ResyncStateUpdater:
|
|
|
94
94
|
await ocean.metrics.send_metrics_to_webhook(
|
|
95
95
|
kind=ocean.metrics.current_resource_kind()
|
|
96
96
|
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
await ocean.metrics.report_sync_metrics(
|
|
98
|
+
kinds=[ocean.metrics.current_resource_kind()]
|
|
99
|
+
)
|
|
@@ -9,6 +9,7 @@ import httpx
|
|
|
9
9
|
from loguru import logger
|
|
10
10
|
from port_ocean.clients.port.types import UserAgentType
|
|
11
11
|
from port_ocean.context.event import TriggerType, event_context, EventType, event
|
|
12
|
+
from port_ocean.context.metric_resource import metric_resource_context
|
|
12
13
|
from port_ocean.context.ocean import ocean
|
|
13
14
|
from port_ocean.context.resource import resource_context
|
|
14
15
|
from port_ocean.context import resource
|
|
@@ -33,8 +34,8 @@ from port_ocean.core.ocean_types import (
|
|
|
33
34
|
)
|
|
34
35
|
from port_ocean.core.utils.utils import resolve_entities_diff, zip_and_sum, gather_and_split_errors_from_results
|
|
35
36
|
from port_ocean.exceptions.core import OceanAbortException
|
|
36
|
-
from port_ocean.helpers.metric.metric import SyncState, MetricType, MetricPhase
|
|
37
|
-
from port_ocean.helpers.metric.utils import TimeMetric
|
|
37
|
+
from port_ocean.helpers.metric.metric import MetricResourceKind, SyncState, MetricType, MetricPhase
|
|
38
|
+
from port_ocean.helpers.metric.utils import TimeMetric, TimeMetricWithResourceKind
|
|
38
39
|
from port_ocean.utils.ipc import FileIPC
|
|
39
40
|
|
|
40
41
|
SEND_RAW_DATA_EXAMPLES_AMOUNT = 5
|
|
@@ -249,9 +250,16 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
249
250
|
labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
|
|
250
251
|
value=len(objects_diff[0].entity_selector_diff.passed) - len(changed_entities)
|
|
251
252
|
)
|
|
252
|
-
await self.entities_state_applier.upsert(
|
|
253
|
+
upserted_entities = await self.entities_state_applier.upsert(
|
|
253
254
|
changed_entities, user_agent_type
|
|
254
255
|
)
|
|
256
|
+
|
|
257
|
+
ocean.metrics.set_metric(
|
|
258
|
+
name=MetricType.OBJECT_COUNT_NAME,
|
|
259
|
+
labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
|
|
260
|
+
value=len(upserted_entities)
|
|
261
|
+
)
|
|
262
|
+
|
|
255
263
|
else:
|
|
256
264
|
logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
|
|
257
265
|
ocean.metrics.inc_metric(
|
|
@@ -265,6 +273,11 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
265
273
|
modified_objects = await self.entities_state_applier.upsert(
|
|
266
274
|
objects_diff[0].entity_selector_diff.passed, user_agent_type
|
|
267
275
|
)
|
|
276
|
+
ocean.metrics.set_metric(
|
|
277
|
+
name=MetricType.OBJECT_COUNT_NAME,
|
|
278
|
+
labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
|
|
279
|
+
value=len(upserted_entities)
|
|
280
|
+
)
|
|
268
281
|
else:
|
|
269
282
|
modified_objects = await self.entities_state_applier.upsert(
|
|
270
283
|
objects_diff[0].entity_selector_diff.passed, user_agent_type
|
|
@@ -633,16 +646,12 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
633
646
|
async with resource_context(resource,index):
|
|
634
647
|
resource_kind_id = f"{resource.kind}-{index}"
|
|
635
648
|
ocean.metrics.sync_state = SyncState.SYNCING
|
|
649
|
+
|
|
636
650
|
task = asyncio.create_task(
|
|
637
651
|
self._register_in_batches(resource, user_agent_type)
|
|
638
652
|
)
|
|
639
653
|
event.on_abort(lambda: task.cancel())
|
|
640
654
|
kind_results: tuple[list[Entity], list[Exception]] = await task
|
|
641
|
-
ocean.metrics.set_metric(
|
|
642
|
-
name=MetricType.OBJECT_COUNT_NAME,
|
|
643
|
-
labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
|
|
644
|
-
value=len(kind_results[0])
|
|
645
|
-
)
|
|
646
655
|
|
|
647
656
|
if ocean.metrics.sync_state != SyncState.FAILED:
|
|
648
657
|
ocean.metrics.sync_state = SyncState.COMPLETED
|
|
@@ -650,10 +659,88 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
650
659
|
await ocean.metrics.send_metrics_to_webhook(
|
|
651
660
|
kind=resource_kind_id
|
|
652
661
|
)
|
|
653
|
-
|
|
662
|
+
await ocean.metrics.report_kind_sync_metrics(kind=resource_kind_id, blueprint=resource.port.entity.mappings.blueprint)
|
|
654
663
|
|
|
655
664
|
return kind_results
|
|
656
665
|
|
|
666
|
+
@TimeMetricWithResourceKind(MetricPhase.RESYNC)
|
|
667
|
+
async def resync_reconciliation(
|
|
668
|
+
self,
|
|
669
|
+
creation_results: list[tuple[list[Entity], list[Exception]]],
|
|
670
|
+
did_fetched_current_state: bool,
|
|
671
|
+
user_agent_type: UserAgentType,
|
|
672
|
+
app_config: Any,
|
|
673
|
+
silent: bool = True,
|
|
674
|
+
) -> None:
|
|
675
|
+
"""Handle the reconciliation phase of the resync process.
|
|
676
|
+
|
|
677
|
+
This method handles:
|
|
678
|
+
1. Sorting and upserting failed entities
|
|
679
|
+
2. Checking if current state was fetched
|
|
680
|
+
3. Calculating resync diff
|
|
681
|
+
4. Handling errors
|
|
682
|
+
5. Deleting entities that are no longer needed
|
|
683
|
+
6. Executing resync complete hooks
|
|
684
|
+
|
|
685
|
+
Args:
|
|
686
|
+
creation_results (list[tuple[list[Entity], list[Exception]]]): Results from entity creation
|
|
687
|
+
did_fetched_current_state (bool): Whether the current state was successfully fetched
|
|
688
|
+
user_agent_type (UserAgentType): The type of user agent
|
|
689
|
+
app_config (Any): The application configuration
|
|
690
|
+
silent (bool): Whether to raise exceptions or handle them silently
|
|
691
|
+
|
|
692
|
+
"""
|
|
693
|
+
await self.sort_and_upsert_failed_entities(user_agent_type)
|
|
694
|
+
|
|
695
|
+
if not did_fetched_current_state:
|
|
696
|
+
logger.warning(
|
|
697
|
+
"Due to an error before the resync, the previous state of entities at Port is unknown."
|
|
698
|
+
" Skipping delete phase due to unknown initial state."
|
|
699
|
+
)
|
|
700
|
+
return False
|
|
701
|
+
|
|
702
|
+
logger.info("Starting resync diff calculation")
|
|
703
|
+
generated_entities, errors = zip_and_sum(creation_results) or [
|
|
704
|
+
[],
|
|
705
|
+
[],
|
|
706
|
+
]
|
|
707
|
+
|
|
708
|
+
if errors:
|
|
709
|
+
message = f"Resync failed with {len(errors)} errors, skipping delete phase due to incomplete state"
|
|
710
|
+
error_group = ExceptionGroup(
|
|
711
|
+
message,
|
|
712
|
+
errors,
|
|
713
|
+
)
|
|
714
|
+
if not silent:
|
|
715
|
+
raise error_group
|
|
716
|
+
|
|
717
|
+
logger.error(message, exc_info=error_group)
|
|
718
|
+
return False
|
|
719
|
+
|
|
720
|
+
logger.info(
|
|
721
|
+
f"Running resync diff calculation, number of entities created during sync: {len(generated_entities)}"
|
|
722
|
+
)
|
|
723
|
+
entities_at_port = await ocean.port_client.search_entities(
|
|
724
|
+
user_agent_type
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
await self.entities_state_applier.delete_diff(
|
|
728
|
+
{"before": entities_at_port, "after": generated_entities},
|
|
729
|
+
user_agent_type, app_config.get_entity_deletion_threshold()
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
logger.info("Resync finished successfully")
|
|
733
|
+
|
|
734
|
+
# Execute resync_complete hooks
|
|
735
|
+
if "resync_complete" in self.event_strategy:
|
|
736
|
+
logger.info("Executing resync_complete hooks")
|
|
737
|
+
|
|
738
|
+
for resync_complete_fn in self.event_strategy["resync_complete"]:
|
|
739
|
+
await resync_complete_fn()
|
|
740
|
+
|
|
741
|
+
logger.info("Finished executing resync_complete hooks")
|
|
742
|
+
|
|
743
|
+
|
|
657
744
|
@TimeMetric(MetricPhase.RESYNC)
|
|
658
745
|
async def sync_raw_all(
|
|
659
746
|
self,
|
|
@@ -689,8 +776,9 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
689
776
|
logger.info(f"Resync will use the following mappings: {app_config.dict()}")
|
|
690
777
|
|
|
691
778
|
kinds = [f"{resource.kind}-{index}" for index, resource in enumerate(app_config.resources)]
|
|
779
|
+
blueprints = [resource.port.entity.mappings.blueprint for resource in app_config.resources]
|
|
692
780
|
ocean.metrics.initialize_metrics(kinds)
|
|
693
|
-
|
|
781
|
+
await ocean.metrics.report_sync_metrics(kinds=kinds, blueprints=blueprints)
|
|
694
782
|
|
|
695
783
|
# Clear cache
|
|
696
784
|
await ocean.app.cache_provider.clear()
|
|
@@ -716,65 +804,20 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
716
804
|
multiprocessing.set_start_method('fork', True)
|
|
717
805
|
try:
|
|
718
806
|
for index,resource in enumerate(app_config.resources):
|
|
719
|
-
|
|
720
807
|
logger.info(f"Starting processing resource {resource.kind} with index {index}")
|
|
721
|
-
|
|
722
808
|
creation_results.append(await self.process_resource(resource,index,user_agent_type))
|
|
723
|
-
|
|
724
|
-
await self.sort_and_upsert_failed_entities(user_agent_type)
|
|
725
|
-
|
|
726
809
|
except asyncio.CancelledError as e:
|
|
727
810
|
logger.warning("Resync aborted successfully, skipping delete phase. This leads to an incomplete state")
|
|
728
811
|
raise
|
|
729
812
|
else:
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
generated_entities, errors = zip_and_sum(creation_results) or [
|
|
739
|
-
[],
|
|
740
|
-
[],
|
|
741
|
-
]
|
|
742
|
-
|
|
743
|
-
if errors:
|
|
744
|
-
message = f"Resync failed with {len(errors)} errors, skipping delete phase due to incomplete state"
|
|
745
|
-
error_group = ExceptionGroup(
|
|
746
|
-
message,
|
|
747
|
-
errors,
|
|
748
|
-
)
|
|
749
|
-
if not silent:
|
|
750
|
-
raise error_group
|
|
751
|
-
|
|
752
|
-
logger.error(message, exc_info=error_group)
|
|
753
|
-
return False
|
|
754
|
-
else:
|
|
755
|
-
logger.info(
|
|
756
|
-
f"Running resync diff calculation, number of entities created during sync: {len(generated_entities)}"
|
|
757
|
-
)
|
|
758
|
-
entities_at_port = await ocean.port_client.search_entities(
|
|
759
|
-
user_agent_type
|
|
760
|
-
)
|
|
761
|
-
await self.entities_state_applier.delete_diff(
|
|
762
|
-
{"before": entities_at_port, "after": generated_entities},
|
|
763
|
-
user_agent_type, app_config.get_entity_deletion_threshold()
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
logger.info("Resync finished successfully")
|
|
767
|
-
|
|
768
|
-
# Execute resync_complete hooks
|
|
769
|
-
if "resync_complete" in self.event_strategy:
|
|
770
|
-
logger.info("Executing resync_complete hooks")
|
|
771
|
-
|
|
772
|
-
for resync_complete_fn in self.event_strategy["resync_complete"]:
|
|
773
|
-
await resync_complete_fn()
|
|
774
|
-
|
|
775
|
-
logger.info("Finished executing resync_complete hooks")
|
|
776
|
-
|
|
777
|
-
return True
|
|
813
|
+
await self.resync_reconciliation(
|
|
814
|
+
creation_results,
|
|
815
|
+
did_fetched_current_state,
|
|
816
|
+
user_agent_type,
|
|
817
|
+
app_config,
|
|
818
|
+
silent
|
|
819
|
+
)
|
|
820
|
+
await ocean.metrics.report_sync_metrics(kinds=[MetricResourceKind.RECONCILIATION])
|
|
778
821
|
finally:
|
|
779
822
|
await ocean.app.cache_provider.clear()
|
|
780
823
|
if ocean.app.process_execution_mode == ProcessExecutionMode.multi_process:
|
|
@@ -6,7 +6,7 @@ import prometheus_client
|
|
|
6
6
|
from httpx import AsyncClient
|
|
7
7
|
from fastapi.responses import PlainTextResponse
|
|
8
8
|
from loguru import logger
|
|
9
|
-
from port_ocean.context import resource
|
|
9
|
+
from port_ocean.context import metric_resource, resource
|
|
10
10
|
from prometheus_client import Gauge
|
|
11
11
|
import prometheus_client.openmetrics
|
|
12
12
|
import prometheus_client.openmetrics.exposition
|
|
@@ -57,6 +57,11 @@ class SyncState:
|
|
|
57
57
|
FAILED = "failed"
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
class MetricResourceKind:
|
|
61
|
+
RECONCILIATION = "__reconciliation__"
|
|
62
|
+
RESYNC = "__resync__"
|
|
63
|
+
|
|
64
|
+
|
|
60
65
|
# Registry for core and custom metrics
|
|
61
66
|
_metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
|
|
62
67
|
MetricType.DURATION_NAME: (
|
|
@@ -252,8 +257,6 @@ class Metrics:
|
|
|
252
257
|
)
|
|
253
258
|
|
|
254
259
|
def create_mertic_router(self) -> APIRouter:
|
|
255
|
-
if not self.enabled:
|
|
256
|
-
return APIRouter()
|
|
257
260
|
router = APIRouter()
|
|
258
261
|
|
|
259
262
|
@router.get("/", response_class=PlainTextResponse)
|
|
@@ -265,6 +268,12 @@ class Metrics:
|
|
|
265
268
|
def current_resource_kind(self) -> str:
|
|
266
269
|
try:
|
|
267
270
|
return f"{resource.resource.kind}-{resource.resource.index}"
|
|
271
|
+
except ResourceContextNotFoundError:
|
|
272
|
+
return self.current_metric_resource_kind()
|
|
273
|
+
|
|
274
|
+
def current_metric_resource_kind(self) -> str:
|
|
275
|
+
try:
|
|
276
|
+
return metric_resource.metric_resource.metric_resource_kind
|
|
268
277
|
except ResourceContextNotFoundError:
|
|
269
278
|
return "__runtime__"
|
|
270
279
|
|
|
@@ -274,15 +283,21 @@ class Metrics:
|
|
|
274
283
|
).decode()
|
|
275
284
|
|
|
276
285
|
async def report_sync_metrics(
|
|
277
|
-
self,
|
|
286
|
+
self,
|
|
287
|
+
metric_name: Optional[str] = None,
|
|
288
|
+
kinds: Optional[list[str]] = None,
|
|
289
|
+
blueprints: Optional[list[Optional[str]]] = None,
|
|
278
290
|
) -> None:
|
|
279
291
|
if kinds is None:
|
|
280
292
|
return None
|
|
281
293
|
|
|
282
294
|
metrics = []
|
|
283
295
|
|
|
284
|
-
|
|
285
|
-
|
|
296
|
+
if blueprints is None:
|
|
297
|
+
blueprints = [None] * len(kinds)
|
|
298
|
+
|
|
299
|
+
for kind, blueprint in zip(kinds, blueprints):
|
|
300
|
+
metric = self.generate_metrics(metric_name, kind, blueprint)
|
|
286
301
|
metrics.extend(metric)
|
|
287
302
|
|
|
288
303
|
try:
|
|
@@ -291,9 +306,12 @@ class Metrics:
|
|
|
291
306
|
logger.error(f"Error posting metrics: {e}", metrics=metrics)
|
|
292
307
|
|
|
293
308
|
async def report_kind_sync_metrics(
|
|
294
|
-
self,
|
|
309
|
+
self,
|
|
310
|
+
metric_name: Optional[str] = None,
|
|
311
|
+
kind: Optional[str] = None,
|
|
312
|
+
blueprint: Optional[str] = None,
|
|
295
313
|
) -> None:
|
|
296
|
-
metrics = self.generate_metrics(metric_name, kind)
|
|
314
|
+
metrics = self.generate_metrics(metric_name, kind, blueprint)
|
|
297
315
|
if not metrics:
|
|
298
316
|
return None
|
|
299
317
|
|
|
@@ -304,7 +322,10 @@ class Metrics:
|
|
|
304
322
|
logger.error(f"Error putting metrics: {e}", metrics=metrics)
|
|
305
323
|
|
|
306
324
|
def generate_metrics(
|
|
307
|
-
self,
|
|
325
|
+
self,
|
|
326
|
+
metric_name: Optional[str] = None,
|
|
327
|
+
kind: Optional[str] = None,
|
|
328
|
+
blueprint: Optional[str] = None,
|
|
308
329
|
) -> list[dict[str, Any]]:
|
|
309
330
|
try:
|
|
310
331
|
latest_raw = self.generate_latest()
|
|
@@ -363,9 +384,10 @@ class Metrics:
|
|
|
363
384
|
if "-" in kind_key
|
|
364
385
|
else kind_key
|
|
365
386
|
),
|
|
366
|
-
"kindIndex":
|
|
387
|
+
"kindIndex": int(kind_key[-1]) if kind_key[-1].isdigit() else 0,
|
|
367
388
|
"eventId": self.event_id,
|
|
368
389
|
"syncState": self.sync_state,
|
|
390
|
+
"blueprint": blueprint if blueprint else "",
|
|
369
391
|
"metrics": metrics,
|
|
370
392
|
}
|
|
371
393
|
events.append(event)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
import time
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
from port_ocean.context.metric_resource import metric_resource_context
|
|
6
|
+
from port_ocean.context.ocean import ocean
|
|
7
|
+
from port_ocean.helpers.metric.metric import MetricResourceKind, MetricType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def TimeMetric(phase: str) -> Any:
|
|
11
|
+
def decorator(func: Callable[..., Any]) -> Any:
|
|
12
|
+
|
|
13
|
+
@wraps(func)
|
|
14
|
+
async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
|
|
15
|
+
start = time.monotonic()
|
|
16
|
+
res = await func(*args, **kwargs)
|
|
17
|
+
end = time.monotonic()
|
|
18
|
+
duration = end - start
|
|
19
|
+
ocean.metrics.inc_metric(
|
|
20
|
+
name=MetricType.DURATION_NAME,
|
|
21
|
+
labels=[ocean.metrics.current_resource_kind(), phase],
|
|
22
|
+
value=duration,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return res
|
|
26
|
+
|
|
27
|
+
return wrapper
|
|
28
|
+
|
|
29
|
+
return decorator
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def TimeMetricWithResourceKind(phase: str) -> Any:
|
|
33
|
+
def decorator(func: Callable[..., Any]) -> Any:
|
|
34
|
+
|
|
35
|
+
@wraps(func)
|
|
36
|
+
async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
|
|
37
|
+
async with metric_resource_context(MetricResourceKind.RECONCILIATION):
|
|
38
|
+
start = time.monotonic()
|
|
39
|
+
res = await func(*args, **kwargs)
|
|
40
|
+
end = time.monotonic()
|
|
41
|
+
duration = end - start
|
|
42
|
+
ocean.metrics.inc_metric(
|
|
43
|
+
name=MetricType.DURATION_NAME,
|
|
44
|
+
labels=[ocean.metrics.current_resource_kind(), phase],
|
|
45
|
+
value=duration,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return res
|
|
49
|
+
|
|
50
|
+
return wrapper
|
|
51
|
+
|
|
52
|
+
return decorator
|
{port_ocean-0.23.3 → port_ocean-0.23.4}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py
RENAMED
|
@@ -154,7 +154,7 @@ async def test_sync_raw_mixin_self_dependency(
|
|
|
154
154
|
|
|
155
155
|
# Add assertions for actual metrics
|
|
156
156
|
metrics = mock_ocean.metrics.generate_metrics()
|
|
157
|
-
assert len(metrics) ==
|
|
157
|
+
assert len(metrics) == 3
|
|
158
158
|
|
|
159
159
|
# Verify object counts
|
|
160
160
|
for metric in metrics:
|
|
@@ -187,7 +187,7 @@ async def test_sync_raw_mixin_self_dependency(
|
|
|
187
187
|
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
188
188
|
"loaded"
|
|
189
189
|
]["object_count"]
|
|
190
|
-
==
|
|
190
|
+
== 1
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
# Verify success
|
|
@@ -196,6 +196,14 @@ async def test_sync_raw_mixin_self_dependency(
|
|
|
196
196
|
# Verify sync state
|
|
197
197
|
assert metric["syncState"] == "completed"
|
|
198
198
|
|
|
199
|
+
if metric["kind"] == "reconciliation":
|
|
200
|
+
assert (
|
|
201
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
202
|
+
"failed"
|
|
203
|
+
]["object_count"]
|
|
204
|
+
== 1
|
|
205
|
+
)
|
|
206
|
+
|
|
199
207
|
|
|
200
208
|
@pytest.mark.asyncio
|
|
201
209
|
async def test_sync_raw_mixin_circular_dependency(
|
|
@@ -282,7 +290,7 @@ async def test_sync_raw_mixin_circular_dependency(
|
|
|
282
290
|
|
|
283
291
|
# Add assertions for actual metrics
|
|
284
292
|
metrics = mock_ocean.metrics.generate_metrics()
|
|
285
|
-
assert len(metrics) ==
|
|
293
|
+
assert len(metrics) == 3
|
|
286
294
|
|
|
287
295
|
# Verify object counts
|
|
288
296
|
for metric in metrics:
|
|
@@ -315,7 +323,7 @@ async def test_sync_raw_mixin_circular_dependency(
|
|
|
315
323
|
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
316
324
|
"loaded"
|
|
317
325
|
]["object_count"]
|
|
318
|
-
==
|
|
326
|
+
== 0
|
|
319
327
|
)
|
|
320
328
|
|
|
321
329
|
# Verify success
|
|
@@ -324,6 +332,14 @@ async def test_sync_raw_mixin_circular_dependency(
|
|
|
324
332
|
# Verify sync state
|
|
325
333
|
assert metric["syncState"] == "completed"
|
|
326
334
|
|
|
335
|
+
if metric["kind"] == "reconciliation":
|
|
336
|
+
assert (
|
|
337
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
338
|
+
"loaded"
|
|
339
|
+
]["object_count"]
|
|
340
|
+
== 2
|
|
341
|
+
)
|
|
342
|
+
|
|
327
343
|
|
|
328
344
|
@pytest.mark.asyncio
|
|
329
345
|
async def test_sync_raw_mixin_dependency(
|
|
@@ -422,7 +438,7 @@ async def test_sync_raw_mixin_dependency(
|
|
|
422
438
|
|
|
423
439
|
# Add assertions for actual metrics
|
|
424
440
|
metrics = mock_ocean.metrics.generate_metrics()
|
|
425
|
-
assert len(metrics) ==
|
|
441
|
+
assert len(metrics) == 3
|
|
426
442
|
|
|
427
443
|
# Verify object counts
|
|
428
444
|
for metric in metrics:
|
|
@@ -458,6 +474,14 @@ async def test_sync_raw_mixin_dependency(
|
|
|
458
474
|
# Verify sync state
|
|
459
475
|
assert metric["syncState"] == "completed"
|
|
460
476
|
|
|
477
|
+
if metric["kind"] == "reconciliation":
|
|
478
|
+
assert (
|
|
479
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
480
|
+
"loaded"
|
|
481
|
+
]["object_count"]
|
|
482
|
+
== 5
|
|
483
|
+
)
|
|
484
|
+
|
|
461
485
|
|
|
462
486
|
@pytest.mark.asyncio
|
|
463
487
|
async def test_register_raw(
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
from functools import wraps
|
|
2
|
-
import time
|
|
3
|
-
from typing import Any, Callable
|
|
4
|
-
|
|
5
|
-
from port_ocean.context.ocean import ocean
|
|
6
|
-
from port_ocean.helpers.metric.metric import MetricType
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def TimeMetric(phase: str) -> Any:
|
|
10
|
-
def decorator(func: Callable[..., Any]) -> Any:
|
|
11
|
-
|
|
12
|
-
@wraps(func)
|
|
13
|
-
async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
|
|
14
|
-
start = time.monotonic()
|
|
15
|
-
res = await func(*args, **kwargs)
|
|
16
|
-
end = time.monotonic()
|
|
17
|
-
duration = end - start
|
|
18
|
-
ocean.metrics.inc_metric(
|
|
19
|
-
name=MetricType.DURATION_NAME,
|
|
20
|
-
labels=[ocean.metrics.current_resource_kind(), phase],
|
|
21
|
-
value=duration,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
return res
|
|
25
|
-
|
|
26
|
-
return wrapper
|
|
27
|
-
|
|
28
|
-
return decorator
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.23.3/port_ocean/tests/helpers → port_ocean-0.23.4/port_ocean/cache}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|